le mie informazioni di contatto
Posta[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
In un ambiente con operazioni simultanee di database, più transazioni che tentano di aggiornare gli stessi dati contemporaneamente possono causare conflitti. PostgreSQL fornisce una serie di meccanismi per gestire questi conflitti di aggiornamenti simultanei per garantire la coerenza e l'integrità dei dati.
Possono verificarsi conflitti di aggiornamenti simultanei quando due o più transazioni tentano di modificare la stessa riga di dati contemporaneamente. Gli scenari comuni includono:
PostgreSQL utilizza principalmente MVCC (Multiversion Concurrency Control) per gestire transazioni simultanee. MVCC consente a una transazione di leggere una versione di dati che soddisfa i requisiti del livello di isolamento senza bloccarsi per bloccare le operazioni di lettura di altre transazioni. Tuttavia, potrebbero verificarsi ancora conflitti durante le operazioni di scrittura.
PostgreSQL utilizza diversi tipi di blocchi per controllare l'accesso simultaneo ai dati. I tipi di blocco comuni includono:
La granularità del blocco può essere a livello di riga (Livello di riga), a livello di pagina (Livello di pagina) e a livello di tabella (Livello di tabella).
PostgreSQL supporta quattro livelli di isolamento delle transazioni:
Un approccio semplice consiste nel ripetere la transazione quando si verifica un conflitto. Gli esempi sono i seguenti:
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;
$$;
Nell'esempio precedente, se l'operazione di aggiornamento non influisce su alcuna riga (indicando che potrebbe esserci un conflitto), viene impostato un flag, attende un periodo di tempo e quindi riprova.
Il controllo ottimistico della concorrenza presuppone che i conflitti di concorrenza si verifichino raramente. In questo metodo la transazione non si blocca durante l'aggiornamento dei dati, ma controlla se i dati sono stati modificati da altre transazioni durante il commit. Se non sono presenti conflitti, il commit della transazione ha esito positivo; se sono presenti conflitti, la transazione viene ripristinata e ritentata secondo necessità.
-- 获取数据的初始版本
SELECT price AS original_price FROM products WHERE id = 1;
-- 进行业务处理和修改
UPDATE products SET price = 100 WHERE id = 1 AND price = original_price;
Nell'esempio precedente, l'operazione di aggiornamento ha esito positivo solo se i dati non sono stati modificati da altre transazioni.
Il controllo pessimistico della concorrenza presuppone la probabilità che si verifichino conflitti di concorrenza e acquisisce i blocchi necessari durante l'esecuzione delle transazioni per bloccare altre transazioni potenzialmente in conflitto.
BEGIN;
-- 获取排他锁
LOCK TABLE products IN SHARE ROW EXCLUSIVE MODE;
-- 进行数据更新
UPDATE products SET price = 100 WHERE id = 1;
COMMIT;
Aggiungi un campo versione alla tabella per tenere traccia delle modifiche ai dati.
CREATE TABLE products (
id SERIAL PRIMARY KEY,
price DECIMAL(10, 2),
version INT DEFAULT 0
);
Quando si aggiornano i dati, incrementare anche il campo della versione:
UPDATE products SET price = 100, version = version + 1 WHERE id = 1 AND version = <expected_version>;
Se il numero di righe interessate dall'aggiornamento è 0, esiste un conflitto perché la versione prevista non è coerente con la versione effettiva.
Aggiungi un campo timestamp a ogni riga di dati per registrare l'ora dell'ultima modifica dei dati.
CREATE TABLE products (
id SERIAL PRIMARY KEY,
price DECIMAL(10, 2),
last_modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Durante l'aggiornamento, aggiorna solo i dati con un timestamp precedente a quello letto dalla transazione corrente:
UPDATE products SET price = 100 WHERE id = 1 AND last_modified <= <read_timestamp>;
Supponiamo di avere un sistema di gestione dell'inventario per un negozio online con a inventory
tabella per memorizzare le quantità di articoli in inventario.
CREATE TABLE inventory (
product_id INT PRIMARY KEY,
quantity INT,
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Ora ci sono due transazioni simultanee:
Transazione 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;
Transazione 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;
Se queste due transazioni vengono eseguite quasi contemporaneamente, potrebbe verificarsi un conflitto.
Se utilizziamo la risoluzione dei conflitti basata sul timestamp:
T1
)。T2
)。Quando la transazione 1 tenta di aggiornarsi, se nessun'altra transazione ha modificato i dati da quando li ha letti (ad es. last_updated <= T1
), l'aggiornamento è riuscito.
Quando la transazione 2 tenta di aggiornarsi, se rileva che data last_updated
più delT2
(Indicando che è stato modificato dopo che la transazione 2 lo ha letto), l'aggiornamento non riesce e la transazione 2 può scegliere di eseguire il rollback e riprovare oppure eseguire altre elaborazioni in base alla logica aziendale.
🎉相关推荐