2013-07-08 2 views
3

Я использую PostgreSQL 9.2 в среде Windows. Я нахожусь в среде 2PC (2 phase commit), используя MSDTC.Как ждать во время SELECT, что в ожидании INSERT совершить?

У меня есть клиентское приложение, которое запускает транзакцию на уровне изоляции SERIALIZABLE, вставляет новую строку данных в таблицу для определенного значения внешнего ключа (есть индекс в столбце) и голосует за завершение транзакция (сделка ПОДГОТОВЛЕНА). Сделка будет ОБРАТИТЬСЯ координатором транзакций.

Immediatly после этого, за пределами транзакции, тот же клиент запрашивает все строки для этого же определенного значения внешнего ключа.

Поскольку может произойти задержка до того, как предыдущая транзакция действительно будет совершена, предложение SELECT может вернуть предыдущий снимок данных. На самом деле это случается иногда, и это проблематично. Конечно, приложение может быть переработано, но до тех пор я ищу решение для блокировки. Консультативный замок?

Я уже решил проблему при выполнении UPDATE на определенных строках, затем используя SELECT ... FOR SHARE, и он работает хорошо. SELECT ждет, пока транзакция не зафиксирует и не вернет старые и новые строки.

Теперь я пытаюсь решить его для INSERT. SELECT ... FOR SHARE не блокирует и не возвращает сразу.

Здесь нет проблемы параллелизма, так как только один клиент имеет дело с определенным набором строк. Я уже знаю о MVCC.

Любая помощь приветствуется.

+0

Вы пробовали 'SELECT ... FOR UPDATE'? –

+0

@Denis Yep, такой же результат. –

ответ

1

Чтобы дождаться еще не совершенного INSERT, вам необходимо взять предикатную блокировку . В PostgreSQL ограниченная блокировка предикатов для сериализуемой поддержки, но она не отображается непосредственно пользователю.

Простой SERIALIZABLE изоляция не поможет здесь, потому что SERIALIZABLE только требует, чтобы быть порядок, в котором операции могли бы произошло, чтобы произвести последовательный результат. В вашем случае это заказ SELECT, а затем INSERT.

Единственный вариант, о котором я могу думать, это сделать блокировку ACCESS EXCLUSIVE на столе до INSERT ing. Это будет выпущено только на COMMIT PREPARED или ROLLBACK PREPARED времени, и в то же время любые другие запросы будут ждать блокировки. Вы можете применить это с помощью триггера BEFORE, чтобы избежать необходимости изменять приложение. Вы, вероятно, получите нечетный тупик и откат, если вы сделаете это именно так, потому что INSERT займет более низкую блокировку, тогда вы попытаетесь заблокировать продвижение в триггере. Если возможно, лучше выполнить команду LOCK TABLE ... IN ACCESS EXCLUSIVE MODEдоINSERT.

Как вы уже упоминали, это в основном проблема неправильного проектирования приложения. Ожидание увидеть строки, еще не выполненные, на самом деле не имеет никакого смысла.

+0

Если все остальные запросы будут ждать и не выйдут из строя с проблемой сериализации (ошибка 40001), это может сработать. –

+0

@omatrot Это должно быть так, но они могут потерпеть неудачу с '40P01 Deadlock Detected', если вы попытаетесь сделать это с помощью триггеров, так как у вас будет два tx, каждый из которых имеет блокировку младшего порядка для' INSERT ', и каждый из них нуждается в блокировке« ACCESS EXCLUSIVE », для которой другой блокирует блокировку. Это только проблема, если вы «INSERT» из нескольких транзакций за раз. –

+0

Я возьму LOCK TABLE ... до маршрута INSERT, у меня может быть несколько транзакций одновременно. Я буду держать вас в курсе прогресса. –

Смежные вопросы