Condivisione della tecnologia

Come gestire la risoluzione dei conflitti per aggiornamenti simultanei di dati in PostgreSQL?

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

bella linea di demarcazione

PostgreSQL


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.

bella linea di demarcazione

1. Scenari di conflitto di aggiornamenti simultanei

Possono verificarsi conflitti di aggiornamenti simultanei quando due o più transazioni tentano di modificare la stessa riga di dati contemporaneamente. Gli scenari comuni includono:

  1. Modifica diverse colonne della stessa riga contemporaneamente
  2. Aggiorna diversi valori della stessa colonna contemporaneamente

bella linea di demarcazione

2. Meccanismo di controllo della concorrenza in PostgreSQL

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.

(1) Meccanismo di blocco

PostgreSQL utilizza diversi tipi di blocchi per controllare l'accesso simultaneo ai dati. I tipi di blocco comuni includono:

  1. Blocco condiviso: consente ad altre transazioni di acquisire blocchi condivisi, ma impedisce l'acquisizione di blocchi esclusivi. Comunemente utilizzato per le operazioni di lettura.
  2. Blocco esclusivo: impedisce ad altre transazioni di acquisire qualsiasi tipo di blocco, spesso utilizzato per le operazioni di scrittura.

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).

(2) Livello di isolamento della transazione

PostgreSQL supporta quattro livelli di isolamento delle transazioni:

  1. Leggi senza impegno: questo è il livello di isolamento più basso. Una transazione può leggere le modifiche dei dati non confermate di altre transazioni, il che può portare a problemi come letture sporche, letture non ripetibili e letture fantasma.
  2. Leggi Impegnato: le transazioni possono solo leggere i dati inviati, evitando letture sporche, ma potrebbero comunque verificarsi letture non ripetibili e letture fantasma.
  3. Lettura ripetibile: Leggendo gli stessi dati più volte all'interno di una transazione si otterrà lo stesso risultato, evitando letture non ripetibili, ma potrebbero verificarsi letture fantasma.
  4. Serializzabile: Il livello di isolamento più elevato, che garantisce l'esecuzione seriale delle transazioni attraverso un rigoroso controllo della concorrenza, evitando letture sporche, letture non ripetibili e letture fantasma.

bella linea di demarcazione

3. Soluzione ai conflitti di aggiornamenti simultanei

(1) Meccanismo di riprova

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;
$$;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

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.

(2) Utilizzare il controllo ottimistico della concorrenza

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;
  • 1
  • 2
  • 3
  • 4
  • 5

Nell'esempio precedente, l'operazione di aggiornamento ha esito positivo solo se i dati non sono stati modificati da altre transazioni.

(3) Utilizzare il controllo pessimistico della concorrenza

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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

(4) Campo della versione dell'applicazione

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
);
  • 1
  • 2
  • 3
  • 4
  • 5

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>;
  • 1

Se il numero di righe interessate dall'aggiornamento è 0, esiste un conflitto perché la versione prevista non è coerente con la versione effettiva.

(5) Risoluzione dei conflitti basata sulla marcatura temporale

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
);
  • 1
  • 2
  • 3
  • 4
  • 5

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>;
  • 1

bella linea di demarcazione

4. Considerazioni sulle applicazioni pratiche

(1) Impatto sulle prestazioni

  1. Diversi metodi di risoluzione dei conflitti hanno impatti diversi sulle prestazioni del database. Ad esempio, l'utilizzo del blocco può causare l'attesa di altre transazioni, aumentare il tempo di blocco del sistema e quindi influire sulla concorrenza. Il controllo ottimistico della concorrenza funziona meglio quando i conflitti si verificano raramente, ma quando i conflitti si verificano frequentemente, può portare a un numero elevato di tentativi di transazione, aumentando il tempo di esecuzione complessivo.
  2. L'applicazione di campi di versione o metodi basati su timestamp potrebbe richiedere ulteriore spazio di archiviazione per conservare le informazioni sulla versione o sul timestamp, nonché valutazioni ed elaborazioni aggiuntive durante l'aggiornamento.

(2) Adattabilità della logica aziendale

  1. Alcuni scenari aziendali potrebbero essere più adatti per uno specifico metodo di risoluzione dei conflitti. Ad esempio, se l'azienda ha requisiti molto elevati di coerenza dei dati e non può tollerare alcuna incoerenza, il controllo pessimistico della concorrenza o il livello di isolamento della serializzazione potrebbero essere una scelta migliore.
  2. Il controllo ottimistico della concorrenza può essere più appropriato per scenari in cui i conflitti sono meno frequenti e i requisiti di tempo di risposta sono più elevati.

(3) Distribuzione dei dati e modelli di accesso

  1. Se l’accesso ai dati è altamente simultaneo e più transazioni spesso accedono alle stesse righe di dati contemporaneamente, i metodi di risoluzione dei conflitti devono essere scelti con maggiore attenzione per evitare blocchi e conflitti eccessivi.
  2. Per le situazioni in cui la distribuzione dei dati è relativamente uniforme e la probabilità di conflitto è bassa, è possibile utilizzare metodi relativamente semplici ed efficienti, come il controllo ottimistico della concorrenza.

bella linea di demarcazione

5. Analisi di esempio

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
);
  • 1
  • 2
  • 3
  • 4
  • 5

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;
  • 1
  • 2
  • 3
  • 4
  • 5

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;
  • 1
  • 2
  • 3
  • 4
  • 5

Se queste due transazioni vengono eseguite quasi contemporaneamente, potrebbe verificarsi un conflitto.

Se utilizziamo la risoluzione dei conflitti basata sul timestamp:

  1. La transazione 1 ha ottenuto il timestamp corrente durante la lettura dei dati (T1)。
  2. La transazione 2 ha ottenuto un timestamp leggermente successivo durante la lettura dei dati (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.


bella linea di demarcazione

🎉相关推荐

PostgreSQL