* Заключване на данните при транзакция
Публикувано на 18 април 2009 в раздел Бази от Данни.
Синхронизацията на данните е изключително важна. За да демонстрираме това нека покажем първо един пример. Нека проверим първо колко пари има в акаунт с id = 1:
mysql> USE banks; Database changed mysql> SELECT amount FROM accounts WHERE id = 1; +--------+ | amount | +--------+ | 306.38 | +--------+ 1 row in set (0.00 sec)
Сега нека напишем заявка UPDATE, с която искаме да изтеглим 500 лева, но така, че ако искаме да няма такава наличност, то заявката да не се изпълни:
mysql> UPDATE accounts SET amount = amount - 500 WHERE id = 1 AND amount >= 500; Query OK, 0 rows affected (0.00 sec) Rows matched: 0 Changed: 0 Warnings: 0 mysql> SELECT amount FROM accounts WHERE id = 1; +--------+ | amount | +--------+ | 306.38 | +--------+ 1 row in set (0.00 sec)
Нека сега стартираме две връзки към базата от данни и да започнем транзакции. С тези транзакции ние ще се опитаме да изтеглим два пъти по 250 лева от акаунт с id = 1:
Виждаме, че втората връзка не върна резултат – тя стои в „спящ“ (idle) режим. Това е така, защото сървъра знае, че в този момент друга транзакция все още не е приключила, тоест резултатът от нея все още не е записан. Така втората връзка все още не „вижда“, че вече сумата в акаунта е намалена и ако вземе 250 лева, то банката ще изгуби пари. Затова при стартиране на транзакция се прави т.нар. „заключване“ (lock).
Нека сега приключим първата транзакция:
Виждаме, че това се отрази моментално във втората връзка. Както очаквахме там UPDATE не се направи, защото в акаунта вече няма достатъчно пари (те бяха взети от първата връзка).
Същото заключване на транзакции важи и за INSERT заявки. Нека създадем една примерна елементарна база от данни:
mysql> CREATE DATABASE locks;
Query OK, 1 row affected (0.00 sec)
mysql> USE locks;
Database changed
mysql> CREATE TABLE test(
val INT
) ENGINE=InnoDB;
Query OK, 0 rows affected (0.14 sec)
mysql> INSERT INTO test
VALUES (1), (2);
Query OK, 2 rows affected (0.06 sec)
Records: 2 Duplicates: 0 Warnings: 0
Нека сега стартираме две транзакции, с които искаме да прочетем най-голямата стойност в колоната val и съответно добавят нова стойност с едно по-голяма от втората:
Виждаме, че отново втората транзакция изчаква завършването на първата. В момента, в който извършим COMMIT в първата транзакция втората също ще изпълни заявката си:
Сега ще видим, че се е получило точно това, което искахме – първата транзакция е добавила val = 3, а втората val = 4:
Ако заключването на връзката не съществуваше, то и двете транзакции щяха да вмъкнат стойност „3″ и щяхме да имаме повтарящи се редове.
От тези примери трябва да си извадим важна бележка – важно е да приключваме транзакциите си възможно най-бързо. Ако ние се „бавим“, то други транзакции ще трябва да ни изчакват. В MySQL има стандартен timeout от няколко секунди (естествено може да бъде настройван чрез my.cnf/my.ini) за изчакване – ако дадена заявка е в режим „изчакване“ и този timeout бъде достигнат, то заявката ще пропадне.
Заключването на връзките важи за заявки UPDATE, INSERT и DELETE. По подразбиране то не е валидно за заявки от тип SELECT. MySQL обаче ни предоставя възможност да го правим ръчно:
SELECT <rows> FROM <table> FOR UPDATE;
В последния пример указваме, че данните, които са върнати от SELECT заявката, ще бъдат заключени. По този начин ако някоя друга транзакция се опита да чете или променя данните, то тя ще трябва да изчака изпълнението на първата започната.
По-слабо заключване е „LOCK IN SHARE MODE“, с което позволяваме на други транзакции да четат, но не и да променят данните. Чрез такова заключване сме сигурни, че прочетените данни ще бъдат най-новите налични в системата и никоя друга транзакция няма да ги промени междувременно:
SELECT <rows> FROM <table> LOCK IN SHARE MODE;
С последния пример при отваряне на втора връзка всички видове заявки ще бъдат блокирани в idle режим докато първата транзакция не завърши.
Trackback URI | RSS за коментарите
Пусни коментар
Категории
- Бази от Данни (39)
- Вероятности (30)
- История (14)
- Кучета (67)
- Лада Нива (91)
- Математика (159)
- Методика (52)
- Общи работи (107)
- ПИК-3 Java (38)
- Политика (40)
- Програмни Среди (1)
- ПТСК (37)
- С/C++ (45)
- Семейни (15)
- Физика (35)
- ХHTML/JS (25)
- Храна (11)
Нови
- Как да разрежем хляба?
- Здравей бебе!
- Какво означават метеорологичните кодове?
- Берра проправя пътеки
- Задача от YES




