* Транзакции
Публикувано на 18 април 2009 от Филип Петров. Записано в DB.
Транзакция наричаме последователност от SQL заявки, която трябва да изпълняват условието или всичките да бъдат изпълнени или нито една от тях да не бъде изпълнена. Може да дадем класически пример с банковите транзакции. Например ако искаме да прехвърлим 50 лева от акаунт 1 в акаунт 2, то трябва да изпълним следните две заявки:
UPDATE accounts SET amount = amount - 50 WHERE id = 1; UPDATE accounts SET amount = amount + 50 WHERE id = 2;
Какво обаче ще се случи ако например втората заявка не се изпълни (например възникне грешка)? Отговорът е, че парите ще бъдат изгубени. Тук се явява силата на транзакциите – те гарантират че ако някоя заявка не се изпълни, то данните ще бъдат възстановени в първоначален вид.
Групирането на заявки в транзакция се изпълнява изключително лесно. Единствено трябва да оградим данните с BEGIN (започване на транзакция) и COMMIT (край на транзакция):
BEGIN; UPDATE accounts SET amount = amount - 50 WHERE id = 1; UPDATE accounts SET amount = amount + 50 WHERE id = 2; COMMIT;
Ако някоя от транзакциите пропадне, то се прави т.нар. ROLLBACK. За целта се използва innodb log файл, в който се записват старите данни преди изпълнението на всяка заявка. Естествено ние можем да правим ROLLBACK и сами. Например:
mysql> SELECT amount FROM accounts WHERE id = 1; +--------+ | amount | +--------+ | 106.38 | +--------+ 1 row in set (0.00 sec) mysql> BEGIN; Query OK, 0 rows affected (0.00 sec) mysql> UPDATE accounts SET amount = amount - 50 WHERE id = 1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> ROLLBACK; Query OK, 0 rows affected (0.36 sec) mysql> SELECT amount FROM accounts WHERE id = 1; +--------+ | amount | +--------+ | 106.38 | +--------+ 1 row in set (0.00 sec)
Виждате, че резултатите от заявката SELECT са едни и същи, тоест ROLLBACK е „върнал“ данните в първоначалния им вид преди заявката UPDATE.
Транзакциите трябва да отговарят на условие за консистентно четене. Това означава, че всеки SELECT чете данните записани точно след последния COMMIT. Ето един пример – отворили сме две връзки към базата данни. С едната започваме транзакция и правим UPDATE като даваме 200 лева на акаунт 1. След това във втората връзка искаме да проверим наличността на този акаунт:
След това с първата връзка завършваме транзакцията и отново проверяваме каква е стойността във втората връзка:
Важно е да споменем, че при InnoDB всяка заявка, която НЕ участва в блокове „BEGIN – COMMIT“ е автоматично записана, т.е. можем да приемем, че единичните заявки са завършени транзакции сами по себе си.
В следващата статия ще разгледаме „заключвания“ с цел синхронизация на транзакции.
Забележка: За стартиране на транзакция можете да използвате и по-популярната сред останалите бази данни „START TRANSACTION“ команда.
5 коментара за “Транзакции”
Trackback URI | RSS за коментарите
Пусни коментар
Страници
Категории
- C/C++ (45)
- DB (36)
- Dogs (49)
- Food (7)
- History (8)
- Java (33)
- Lada (41)
- Math (104)
- Metodos (23)
- NetSec (36)
- Other (76)
- Politics (32)
- Probability (13)
- VC++.Net (1)
- XHTML/JS (25)
Нови
- Един виц за капитализма
- Как да получиш целувка?
- Лека разходка на Витоша
- Роко и Берра на училище
- Газова бутилка под багажника на Лада Нива


14 май 2009 на 1:03
Искам само да попитам първия и най-лесен пример за транзакции как ще стане на Access, прочетох, че се слага BEGIN TRANSACTION и COMMIT TRANSACTION, но пак не ми тръгва.
14 май 2009 на 6:34
SQL стандартът попринцип казва „START TRANSACTION“ и „COMMIT“. Честно си признавам, че не знам как е в ACCESS.
14 май 2009 на 21:01
Нещо не схващам обаче…
Пиша това във MySQL конзолния прозорец:
BEGIN;
UPDATE Customer
SET t_id = 4
WHERE cus_id = 4;
UPDATE Customer
SET t_id = 5
WHERE cus_id = 4213;
COMMIT;
Както се сещате на 2-рия UPDATE такова id няма и изплюва грешка там. Но в момента в който дам COMMIT промяната на първия UPDATE се изпълнява въпреки всичко. Нали идеята на транзакциите беше да се опаковат няколко заявки във едно (между Begin и Commit-а) за да се изпълнят всички заедно и така или се изпълняват всички или никоя не се изпълнява. Как така въпреки грешката се изпълнява първия UPDATE? Или ако не при какви условия би треело транзакцията да пропадне.
ПП: Докато не дам commit, в базата ми няма промяна, проверих…
ПП2: Ползвам ENGINE = InnoDB;
ПП3: Нещо като напиша коментар не ми излизат след тва… Писах и за View преди неколко дена и все още не е излезъл..
14 май 2009 на 21:18
Филип Славов – Здравей,
Бъркаш цялата концепция. За MySQL това, че даден UPDATE връща „грешка“ (от твоя пример – няма такова id) не означава, че заявката не е изпълнена успешно. Не е сървъра за базата данни този, който взима решението кога транзакция е успешна и кога не – ние сме.
В твоя пример си представи следното – тези заявки се подават от програма написана на С. След първата заявка резултатът се подава към програмата и той е „OK, 1 rows affected“, което за програмата означава „първата заявка е успешна“. След втората заявка обаче се връща грешка – тогава програмата вместо COMMIT ще подаде заявка ROLLBACK. Това е логиката. Надявам се, че се изразих ясно.
14 май 2009 на 21:23
Аха… значи все пак ние ръчно решаваме дали да commit-нем, или Rollback-нем в зависимост от общия резултат на заявките (дали ни харесва или не :D )
10x…