2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Dans un environnement d'opérations simultanées de base de données, plusieurs transactions tentant de mettre à jour les mêmes données en même temps peuvent provoquer des conflits. PostgreSQL fournit une série de mécanismes pour gérer ces conflits de mises à jour simultanées afin de garantir la cohérence et l'intégrité des données.
Des conflits de mise à jour simultanées peuvent survenir lorsque deux transactions ou plus tentent de modifier la même ligne de données en même temps. Les scénarios courants incluent :
PostgreSQL utilise principalement MVCC (Multiversion Concurrency Control) pour gérer les transactions simultanées. MVCC permet à une transaction de lire une version de données qui répond à ses exigences de niveau d'isolement sans verrouillage pour bloquer les opérations de lecture d'autres transactions. Toutefois, des conflits peuvent toujours survenir lors des opérations d'écriture.
PostgreSQL utilise plusieurs types de verrous pour contrôler l'accès simultané aux données. Les types de verrous courants incluent :
La granularité du verrouillage peut être au niveau de la ligne (Row-Level), au niveau de la page (Page-Level) et au niveau de la table (Table-Level).
PostgreSQL prend en charge quatre niveaux d'isolation des transactions :
Une approche simple consiste à réessayer la transaction lorsqu'un conflit survient. Les exemples sont les suivants :
DO
$$
DECLARE
conflict_detected BOOLEAN := FALSE;
BEGIN
LOOP
-- 尝试执行更新操作
UPDATE products SET price = 100 WHERE id = 1;
-- 检查是否有冲突(例如,通过检查受影响的行数)
IF NOT FOUND THEN
conflict_detected := TRUE;
ELSE
EXIT;
END IF;
-- 若有冲突,等待一段时间并重试
IF conflict_detected THEN
PERFORM pg_sleep(1);
END IF;
END LOOP;
END;
$$;
Dans l'exemple ci-dessus, si l'opération de mise à jour n'affecte aucune ligne (ce qui indique qu'il peut y avoir un conflit), un indicateur est défini, attend un certain temps, puis réessaye.
Le contrôle de concurrence optimiste suppose que les conflits de concurrence se produisent rarement. Dans cette méthode, la transaction ne se verrouille pas lors de la mise à jour des données, mais vérifie si les données ont été modifiées par d'autres transactions lors de la validation. S'il n'y a pas de conflits, la transaction est validée avec succès ; s'il y a des conflits, la transaction est annulée et réessayée si nécessaire.
-- 获取数据的初始版本
SELECT price AS original_price FROM products WHERE id = 1;
-- 进行业务处理和修改
UPDATE products SET price = 100 WHERE id = 1 AND price = original_price;
Dans l'exemple ci-dessus, l'opération de mise à jour réussit uniquement si les données n'ont pas été modifiées par d'autres transactions.
Le contrôle de concurrence pessimiste suppose que des conflits de concurrence sont susceptibles de se produire et acquiert les verrous requis pendant l'exécution de la transaction pour bloquer d'autres transactions potentiellement conflictuelles.
BEGIN;
-- 获取排他锁
LOCK TABLE products IN SHARE ROW EXCLUSIVE MODE;
-- 进行数据更新
UPDATE products SET price = 100 WHERE id = 1;
COMMIT;
Ajoutez un champ de version au tableau pour suivre les modifications apportées aux données.
CREATE TABLE products (
id SERIAL PRIMARY KEY,
price DECIMAL(10, 2),
version INT DEFAULT 0
);
Lors de la mise à jour des données, incrémentez également le champ version :
UPDATE products SET price = 100, version = version + 1 WHERE id = 1 AND version = <expected_version>;
Si le nombre de lignes affectées par la mise à jour est 0, il y a un conflit car la version attendue est incohérente avec la version réelle.
Ajoutez un champ d'horodatage à chaque ligne de données pour enregistrer l'heure de la dernière modification des données.
CREATE TABLE products (
id SERIAL PRIMARY KEY,
price DECIMAL(10, 2),
last_modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Lors de la mise à jour, mettez à jour uniquement les données dont l'horodatage est antérieur à l'horodatage lu par la transaction en cours :
UPDATE products SET price = 100 WHERE id = 1 AND last_modified <= <read_timestamp>;
Supposons que nous ayons un système de gestion des stocks pour une boutique en ligne avec un inventory
table pour stocker les quantités d’articles en stock.
CREATE TABLE inventory (
product_id INT PRIMARY KEY,
quantity INT,
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Il y a désormais deux transactions simultanées :
Opération 1 :
BEGIN;
SELECT * FROM inventory WHERE product_id = 1;
-- 假设读取到的数量为 10
UPDATE inventory SET quantity = 5 WHERE product_id = 1 AND last_updated <= <read_timestamp>;
COMMIT;
Opération 2 :
BEGIN;
SELECT * FROM inventory WHERE product_id = 1;
-- 假设也读取到的数量为 10
UPDATE inventory SET quantity = 8 WHERE product_id = 1 AND last_updated <= <read_timestamp>;
COMMIT;
Si ces deux transactions sont exécutées presque en même temps, un conflit peut survenir.
Si nous utilisons la résolution de conflits basée sur l'horodatage :
T1
)。T2
)。Lorsque la transaction 1 tente de se mettre à jour, si aucune autre transaction n'a modifié les données depuis qu'elle les a lues (c'est-à-dire last_updated <= T1
), la mise à jour a réussi.
Lorsque la transaction 2 tente de se mettre à jour, si elle constate que les données last_updated
plus que leT2
(Indiquant qu'elle a été modifiée après la lecture de la transaction 2), la mise à jour échoue et la transaction 2 peut choisir d'annuler et de réessayer, ou d'effectuer un autre traitement selon la logique métier.
🎉相关推荐