TakéDB transakce, SQL transakce, transactionPokročilý

Definice

Databázová transakce je řízená skupina databázových operací, která se má provést jako jeden logický celek. Pokud se všechny kroky podaří, změny se potvrdí commitem; při chybě se vrátí rollbackem. Transakce chrání konzistenci dat hlavně při souběžných zápisech, výpadcích a více navazujících změnách.

Kategorie: DatabázeAktualizováno

Proč transakce drží změny pohromadě

Databázová transakce dává databázi hranici, za kterou se změny buď stanou trvalou součástí dat, nebo zmizí, jako by neproběhly. Typický případ je objednávka: aplikace odečte sklad, založí objednávku, zapíše platbu a přidá událost pro expedici. Bez transakce může chyba uprostřed postupu zanechat databázi v napůl změněném stavu.

V relačních databázích se transakce často popisují vlastnostmi ACID. Atomarita řeší celek, konzistence hlídá pravidla databáze, izolace omezuje rušení mezi souběžnými operacemi a trvalost znamená, že potvrzená změna přežije běžný pád procesu nebo restart.

BEGIN, COMMIT a ROLLBACK v praxi

Příkaz BEGIN obvykle otevře transakční blok. Příkaz COMMIT změny potvrdí. Příkaz ROLLBACK vrátí databázi do stavu před začátkem transakce. Přesná syntaxe a výchozí režim se liší podle systému, ale princip je podobný v PostgreSQL, SQLite i mnoha dalších databázích pracujících se SQL.

BEGIN;
UPDATE accounts SET balance = balance - 1000 WHERE id = 1;
UPDATE accounts SET balance = balance + 1000 WHERE id = 2;
COMMIT;

Chyba mezi oběma příkazy UPDATE by bez transakce mohla odečíst peníze z jednoho účtu, ale nepřičíst je na druhý. Transakční zápis umožní aplikaci při problému zavolat ROLLBACK a nechat oba účty beze změny.

Izolace při souběžných zápisech

Izolace rozhoduje, co uvidí dvě transakce běžící ve stejný čas. Slabší izolace dovolí vyšší propustnost, ale aplikace musí počítat s jevy jako opakované čtení jiného výsledku nebo konflikt dvou zápisů. Silnější izolace omezuje překvapení, zároveň může víc blokovat a častěji vyvolat opakování transakce.

Databázové systémy používají různé mechanismy: zámky řádků, verzování záznamů nebo kontrolu konfliktů při potvrzení. Transakce proto není jen obal kolem několika dotazů. Transakce je dohoda mezi aplikací a databází, jak zacházet s časem, souběhem a chybou.

Dva praktické scénáře

Převod peněz mezi účty

Bankovní aplikace odečte částku z účtu plátce a připíše stejnou částku příjemci. Databázová transakce zajistí, že se neuloží pouze první polovina převodu. Při výpadku aplikace se celá operace vrátí, nebo se po potvrzení považuje za dokončenou.

Rezervace posledního kusu zboží

E-shop má poslední kus telefonu a dva zákazníci kliknou na nákup téměř současně. Transakce může při čtení nebo aktualizaci skladového řádku použít zámek, aby se stejný kus neprodal dvakrát. Druhý požadavek potom čeká, selže, nebo dostane informaci, že položka už není dostupná.

BEGIN;
SELECT quantity FROM stock WHERE product_id = 42 FOR UPDATE;
UPDATE stock SET quantity = quantity - 1 WHERE product_id = 42 AND quantity > 0;
COMMIT;

Hranice, které transakce nepřekročí

Databázová transakce chrání hlavně data uvnitř jedné databáze nebo v rámci mechanismu, který daný systém výslovně podporuje. E-mail odeslaný během transakce nejde automaticky „ododeslat“ při rollbacku. Platba u externí brány, zpráva ve frontě nebo zápis do jiné služby vyžadují navazující návrh, například idempotenci, outbox pattern nebo kompenzační operaci.

Příliš dlouhá transakce drží zámky, brzdí úklid starých verzí a zvyšuje riziko konfliktů. Dobrý návrh nechává uvnitř transakce jen nutné databázové změny a pomalé síťové volání provádí mimo kritický úsek. Takový postup pomáhá předcházet i části problémů typu race condition.

Příklady z praxe

  1. Převod peněz mezi účty

    Bankovní aplikace odečte částku z účtu plátce a připíše stejnou částku příjemci. Databázová transakce zajistí, že se neuloží pouze první polovina převodu. Při výpadku aplikace se celá operace vrátí, nebo se po potvrzení považuje za dokončenou.

    BEGIN;
    UPDATE accounts SET balance = balance - 1000 WHERE id = 1;
    UPDATE accounts SET balance = balance + 1000 WHERE id = 2;
    COMMIT;
  2. Rezervace posledního kusu

    E-shop má poslední kus telefonu a dva zákazníci kliknou na nákup téměř současně. Transakce při čtení nebo aktualizaci skladového řádku použije zámek, aby se stejný kus neprodal dvakrát. Druhý požadavek potom čeká, selže, nebo dostane informaci, že položka už není dostupná.

    BEGIN;
    SELECT quantity FROM stock WHERE product_id = 42 FOR UPDATE;
    UPDATE stock SET quantity = quantity - 1 WHERE product_id = 42 AND quantity > 0;
    COMMIT;

Časté omyly

MýtusTransakce vyřeší všechny race conditiony v aplikaci.
Ve skutečnostiDatabázová transakce omezuje závody nad daty, která databáze skutečně řídí. Race condition může zůstat v aplikační logice, cache, externí službě nebo ve špatně zvolené úrovni izolace.
MýtusKdyž je dotaz v transakci, ostatní uživatelé nemůžou s databází pracovat.
Ve skutečnostiDatabázová transakce obvykle nezamkne celou databázi. Moderní systémy zamykají konkrétní řádky nebo používají verzování, takže mnoho čtení a zápisů může běžet souběžně.
MýtusRollback vrátí úplně všechno, co aplikace během transakce udělala.
Ve skutečnostiRollback vrací databázové změny zahrnuté v dané transakci. Odeslaný e-mail, volání platební brány nebo zápis do externího systému se automaticky nevrátí.

Časté dotazy

Proč databázová transakce někdy blokuje jiné dotazy?
Databázová transakce může blokovat jiné dotazy, protože databáze chrání právě měněná data před souběžnou změnou. Zámek může být na řádku, stránce, tabulce nebo jiné interní struktuře podle konkrétní databáze a dotazu. Dlouhé transakce proto zvyšují čekání ostatních požadavků. Praktické řešení bývá zkrátit transakční úsek, používat vhodné indexy a opakovat transakci při detekovaném konfliktu.
Co znamená autocommit u databázové transakce?
Autocommit u databázové transakce znamená, že databáze každý samostatný příkaz automaticky spustí a hned potvrdí jako vlastní transakci. Režim je pohodlný pro jednoduché dotazy, ale nestačí pro postup složený z více navazujících změn. Aplikace musí autocommit vypnout nebo otevřít explicitní transakci, pokud potřebuje potvrdit několik příkazů společně.
Stačí databázová transakce pro platbu kartou a vytvoření objednávky?
Databázová transakce sama o sobě nestačí pro platbu kartou a vytvoření objednávky, pokud platební brána běží mimo databázi obchodu. Rollback databáze nevrátí automaticky externí platbu a potvrzená databázová změna nemusí znamenat úspěšnou autorizaci platby. Běžný návrh oddělí stav objednávky, volání brány a následné potvrzení pomocí idempotentních operací nebo kompenzačních kroků.
Jak dlouhá má databázová transakce být?
Databázová transakce má být obvykle co nejkratší, ale stále musí obsahovat všechny změny, které musí platit společně. Pomalé HTTP volání, čekání na uživatele nebo generování rozsáhlého reportu do transakce většinou nepatří. Krátká transakce snižuje dobu držení zámků, riziko deadlocku a množství práce, kterou musí databáze při konfliktu zahodit.

Zdroje

  1. 3.4. Transactions(otevře se v novém okně)PostgreSQL Global Development Group
  2. 13.2. Transaction Isolation(otevře se v novém okně)PostgreSQL Global Development Group
  3. Transaction(otevře se v novém okně)SQLite
  4. Transactions(otevře se v novém okně)MongoDB
  5. Transactions (Transact-SQL)(otevře se v novém okně)Microsoft

Související pojmy

Potřebujete to vyřešit v praxi?

Poradíme, jak na to ve vašem projektu

Vysvětlit pojem je jedna věc, navrhnout kolem něj funkční řešení druhá. Ozvěte se a probereme, co dává smysl u vás.