Вы можете получить явную блокировку для участника:
BEGIN;
SELECT FROM Participant WHERE Id = $PARTICIPANT_ID FOR NO KEY UPDATE;
DELETE FROM Answer WHERE Participant_Id = $PARTICIPANT_ID;
INSERT INTO Answer (Question_id, Option_Id, Participant_Id)
VALUES ($QUESTION_ID, $OPTION_ID, $PARTICIPANT_ID);
COMMIT;
Таким образом, любое другое соединение, пытающееся сделать то же самое, должно будет ждать завершения этой транзакции.
КомуУбедитесь сами, попробуйте это с двумя сессиями PSQL.В первом вы набираете:
BEGIN;
SELECT FROM Participant WHERE Id = $PARTICIPANT_ID FOR NO KEY UPDATE;
Во втором сеансе вы заметите, что обычный SELECT
все еще работает:
SELECT * FROM Participant WHERE Id = $PARTICIPANT_ID;
Но получая такую же блокировку вВторой сеанс будет зависать:
SELECT FROM Participant WHERE Id = $PARTICIPANT_ID FOR NO KEY UPDATE;
Он будет ждать, пока вы COMMIT
или ROLLBACK
не совершите транзакцию в первом сеансе, гарантируя, что только один поток одновременно удерживает эту блокировку.
Если вы предпочитаете потерпеть неудачу рано, если блокировка недоступна, а не ожидает ее получения, вы можете использовать NOWAIT
.Попробуйте сделать это сейчас во втором сеансе, пока транзакция еще продолжается в первом сеансе:
SELECT FROM Participant WHERE Id = $PARTICIPANT_ID FOR NO KEY UPDATE NOWAIT;
Вы получите немедленную ошибку:
ОШИБКА: не удалось получить блокировкув строке в отношении «Участник»
См. документы PostgreSQL о явном блокировании для получения дополнительной информации.