Докато предложението на Ървин е може би най-простото начин да получите правилно поведение (стига да опитате отново транзакцията си, ако получите изключение с SQLSTATE
от 40001), приложенията с опашка по своето естество са склонни да работят по-добре с блокиране на заявки за шанс да заемат своя ред на опашката, отколкото с реализацията на PostgreSQL на SERIALIZABLE
транзакции, което позволява по-висока едновременност и е малко по-„оптимистично“ по отношение на шансовете за сблъсък.
Примерната заявка във въпроса, както е сега, в READ COMMITTED
по подразбиране Нивото на изолация на транзакциите би позволило на две (или повече) едновременни връзки и двете да "заявят" един и същ ред от опашката. Какво ще се случи е следното:
- T1 започва и стига до заключването на реда в
UPDATE
фаза. - T2 припокрива T1 във времето на изпълнение и се опитва да актуализира този ред. Той блокира в очакване на
COMMIT
илиROLLBACK
на Т1. - T1 извършва ангажименти, след като успешно „заявява“ реда.
- T2 се опитва да актуализира реда, открива, че T1 вече има, търси новата версия на реда, открива, че все още отговаря на критериите за избор (който е точно този
id
съвпада), а също и "заявява" реда.
Може да бъде модифициран, за да работи правилно (ако използвате версия на PostgreSQL, която позволява FOR UPDATE
клауза в подзаявка). Просто добавете FOR UPDATE
до края на подзаявката, която избира идентификатора и това ще се случи:
- T1 стартира и сега заключва реда преди избиране идентификационният номер.
- T2 припокрива T1 във времето за изпълнение и блокира, докато се опитва да избере идентификатор, в очакване на
COMMIT
илиROLLBACK
на Т1. - T1 извършва ангажименти, след като успешно „заявява“ реда.
- До момента, в който T2 е в състояние да чете реда, за да види идентификатора, той вижда, че е заявен, така че намира следващия наличен идентификатор.
В REPEATABLE READ
или SERIALIZABLE
ниво на изолация на транзакциите, конфликтът при запис ще доведе до грешка, която бихте могли да хванете и да определите, че е неуспешна сериализация въз основа на SQLSTATE, и да опитате отново.
Ако обикновено искате СЕРИАЛИЗИРУЕМИ транзакции, но искате да избегнете повторни опити в зоната на опашката, може да успеете да постигнете това, като използвате заключване за съвет.