barbitoff programmer`s blog

Здесь я публикую заметки из программерской жизни: грабли, на которые мне случилось наступить, проблемы, для которых было найдено элегантное (или не очень) решение, а также все, с чем мне пришлось столкнуться и чем хотелось бы поделиться =)
PS Если хотите меня поблагодарить - на странице есть 3 места, чтобы это сделать =)

пятница, 30 декабря 2011 г.

Транзакции и ограничения

Столкнулся тут с интересным поведением PostgreSQL, связанным с UNIQUE-ограничениями и параллельными транзакциями: пусть имеется табличка "h" с колонкой "u" типа int, на которую установлено ограничения "UNIQUE", и параллельно выполняются две транзакции (назовем их t1 и t2), делающие следующую последовательность операций:
1) t1: BEGIN
2) t2: BEGIN
3) t1: INSERT INTO h("u") VALUES (1)
4) t2: INSERT INTO h("u") VALUES (1)
5) t1: COMMIT
6) t2: COMMIT
Уровень изоляции транзакций - "read committed", т.е. транзакции видят только откомиченные изменения друг друга.
Мне казалось что реакция СУБД должна быть следующая: оба INSERT`а проходят нормально, т.к. на момент их выполнения UNIQUE-ограничение не нарушается, COMMIT у транзакции t1 завершается успешно, а у t2 вызывает ошибку и откат транзакции, т.к. на момент этого коммита ограничение уже нарушено.
На самом же деле СУБД ведет себя по-другому: при попытке выполнить INSERT транзакции t2, который может нарушить ограничение в случае, если t1 будет откомиченна, СУБД приостанавливает выполнение команды и заканчивает его только после COMMIT`а или ROLLBACK`а t1 (соответственно, ругаясь на нарушение ограничения или успешно вставляя строку). Такое поведение наблюдается только если нарушение ограничения действительно возможно. Т.е. если вторая транзакция вставляла бы в таблицу значение "2", INSERT выполнялся бы по-обычному, не ожидая первой транзакции.
Теоретически, предполагаемое мной поведение могло бы реально наблюдаться, если бы ограничение было бы задано как DEFERRABLE INITIALLY DEFERRED (тогда ограничение проверялось бы только при COMMIT`е, а не сразу при выполнении операции), но у меня сейчас под рукой только Postgres 8.3, тогда как до 9ой версии можно было объявлять откладываемыми только FOREIGN KEY ограничения.
Насчет поведения других СУБД ничего сказать не могу, надо будет попробовать.

Комментариев нет:

Отправить комментарий