MySQL
ИЗБЕРЕТЕ... ЗА АКТУАЛИЗИРАНЕ с АКТУАЛИЗИРАНЕ
Използване на транзакции с InnoDB (автоматичното извършване е изключено), SELECT ... FOR UPDATE
позволява на една сесия временно да заключи конкретен запис (или записи), така че никоя друга сесия да не може да го актуализира. След това, в рамките на същата транзакция, сесията може действително да извърши UPDATE
на същия запис и завършете или отменете транзакцията. Това ще ви позволи да заключите записа, така че никоя друга сесия да не може да го актуализира, докато може би правите някаква друга бизнес логика.
Това се постига със заключване. InnoDB използва индекси за заключване на записи, така че заключването на съществуващ запис изглежда лесно - просто заключете индекса за този запис.
ИЗБЕРЕТЕ... ЗА АКТУАЛИЗИРАНЕ с INSERT
Въпреки това, за да използвате SELECT ... FOR UPDATE
с INSERT
, как да заключите индекс за запис, който все още не съществува? Ако използвате нивото на изолация по подразбиране REPEATABLE READ
, InnoDB също ще използва gap ключалки. Стига да знаете id
(или дори диапазон от идентификатори), за да заключите, тогава InnoDB може да заключи празнината, така че да не може да се вмъкне друг запис в тази празнина, докато не приключим с нея.
Ако вашият id
колона бяха колона с автоматично увеличение, след което SELECT ... FOR UPDATE
с INSERT INTO
би било проблематично, защото няма да знаете какво е новият id
беше докато не го поставите. Въпреки това, тъй като знаете id
които искате да вмъкнете, SELECT ... FOR UPDATE
с INSERT
ще работи.
ПРЕДУПРЕЖДЕНИЕ
На ниво на изолация по подразбиране, SELECT ... FOR UPDATE
на несъществуващ запис нене блокира други транзакции. Така че, ако и двете транзакции извършват SELECT ... FOR UPDATE
на един и същ несъществуващ индексен запис и двамата ще получат заключването и нито една транзакция няма да може да актуализира записа. Всъщност, ако се опитат, ще бъде открита задънена улица.
Следователно, ако не искате да се справяте със задънена улица, можете просто да направите следното:
ВМЕСЕТЕ В...
Стартирайте транзакция и изпълнете INSERT
. Направете своята бизнес логика и или ангажирайте, или отменете транзакцията. Веднага след като направите INSERT
на несъществуващия индекс на запис при първата транзакция, всички други транзакции ще блокират, ако се опитат да INSERT
запис със същия уникален индекс. Ако втората транзакция се опита да вмъкне запис със същия индекс, след като първата транзакция извърши вмъкването, тогава тя ще получи грешка "дублиран ключ". Работете съответно.
ИЗБЕРЕТЕ... ЗАКЛЮЧЕТЕ В РЕЖИМ НА СПЕДЕНЕ
Ако изберете с LOCK IN SHARE MODE
преди INSERT
, ако предишна транзакция е вмъкнала този запис, но все още не е ангажирана, SELECT ... LOCK IN SHARE MODE
ще блокира, докато предишната транзакция приключи.
Така че, за да намалите вероятността от дублиращи се грешки с ключове, особено ако държите ключалките за известно време, докато изпълнявате бизнес логиката, преди да ги извършите или да ги върнете обратно:
SELECT bar FROM FooBar WHERE foo = ? LOCK FOR UPDATE
- Ако няма върнати записи, тогава
INSERT INTO FooBar (foo, bar) VALUES (?, ?)