Oracle
 sql >> база данни >  >> RDS >> Oracle

SELECT FOR UPDATE предотвратява ли вмъкването на други връзки, когато редът не присъства?

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 ще блокира, докато предишната транзакция приключи.

Така че, за да намалите вероятността от дублиращи се грешки с ключове, особено ако държите ключалките за известно време, докато изпълнявате бизнес логиката, преди да ги извършите или да ги върнете обратно:

  1. SELECT bar FROM FooBar WHERE foo = ? LOCK FOR UPDATE
  2. Ако няма върнати записи, тогава
  3. INSERT INTO FooBar (foo, bar) VALUES (?, ?)


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. десетична(s,p) или число(s,p)?

  2. Entity Framework и множество схеми

  3. Бизнес логика:база данни или приложен слой

  4. SQL трасиране, 10046 събитие в Oracle:trcsess, помощна програма tkprof

  5. Как да приложим връзки едно към едно, едно към много и много към много, докато проектирате таблици?