Как заблокировать базу данных PostgreSQL через JDBC?

В моем веб-приложении Java каждый экземпляр при запуске проверяет актуальность базы данных через соединение JDBC. Если БД не актуальна, она выполняет процедуру обновления, выполняя сценарии SQL.

Я не могу контролировать, когда экземпляры запускаются. Поэтому мне нужно убедиться, что только один экземпляр выполняет обновление базы данных одновременно. В идеале мне нужно было бы заблокировать всю базу данных, но согласно

http://www.postgresql.org/docs/8.4/static/explicit-locking.html

и

http://wiki.postgresql.org/wiki/Lock_database

PostgreSQL не поддерживает его (я все еще использую версию 8.4).

Какие еще варианты у меня есть?


person Sebi    schedule 06.09.2012    source источник
comment
вы собираетесь выполнять эти операции через чистый JDBC или у вас есть фреймворк, помогающий с этим (Hibernate, myBatis и т. д.)?   -  person vector    schedule 06.09.2012
comment
Должно быть очевидно, что любой идентификатор пользователя, который может делать то, что вы предлагаете, может очень легко запустить атаку типа «отказ в обслуживании», поэтому я предполагаю, что это делается с помощью специального идентификатора пользователя, который не используется для нормального выполнения приложения? Вам нужно отключить всех пользователей, которые уже подключены, когда вы делаете это? Есть ли у вас достаточный контроль над другими соединениями, чтобы использовать решение, в котором им потребуется сотрудничать для захвата рекомендательной блокировки?: postgresql.org/docs/8.4/interactive/   -  person kgrittn    schedule 06.09.2012
comment
Мой код обновления БД запускает сценарии SQL через JDBC. Позже запросы выполняются через Hibernate. Я мог бы позаботиться о том, чтобы код обновления учитывал рекомендательную блокировку, но я не уверен, что что-то подобное можно сделать в Hibernate.   -  person Sebi    schedule 06.09.2012


Ответы (2)


Если вы контролируете код для всех экземпляров, то вы можете создать таблицу в базе данных, где каждый запускаемый экземпляр ищет в этой таблице запись с отметкой времени. Давайте назовем это вашей "замковой" записью.

Если процесс обнаруживает, что запись о блокировке не существует, он вставляет запись и обрабатывает требуемые данные.

Если процесс обнаруживает, что запись о блокировке существует, вы можете предположить, что ее создал другой процесс, и ничего не делать, ждать или делать что-то еще.

При таком дизайне вы фактически создаете «замок» в базе данных для синхронизации ваших процессов. Вы кодируете это, поэтому все процессы знают, что они должны придерживаться логики записи блокировки.

Как только первый процесс, имеющий блокировку, завершит обработку, он должен очистить запись блокировки, чтобы следующий перезапуск вел себя правильно. Вам также нужно подумать о ситуации, когда блокировка не была снята из-за ошибки сервера или ошибки выполнения. Как правило, если блокировка старше n минут, вы можете считать ее «устаревшей», поэтому удалите ее и создайте заново (или просто обновите).

При работе с записью «lock» обязательно используйте изоляцию Serializable. level на вашем соединении с БД, чтобы гарантировать атомарность.

Уровень Сервис вашего кода Java может принудительно применить вашу стратегию блокировки до вызова уровня Доступ к данным. Неважно, используете вы Hibernate или нет, так как это просто логика приложения.

person Brad    schedule 06.09.2012
comment
Так что это в основном то же решение, что и рекомендательный замок в комментарии к моему вопросу. С этим легко справиться в самом коде обновления, и кажется, что это один из способов решить эту проблему. - person Sebi; 06.09.2012
comment
Концептуально похожи, но отличаются реализацией. Мое решение можно использовать с любым сервером базы данных, так как оно использует стандартную таблицу. Механизм рекомендательной блокировки специфичен для PostGres. В обоих случаях весь код вашего приложения должен знать о блокировке и вести себя должным образом, чтобы стратегия блокировки была эффективной. - person Brad; 07.09.2012
comment
Поскольку в настоящее время переносимость не является проблемой, я использовал рекомендательную блокировку, и она отлично работает. Но, как вы сказали ранее, это, вероятно, не слишком отличается от наличия пользовательской таблицы журнала. - person Sebi; 07.09.2012

В идеале мне нужно было бы заблокировать всю базу данных.

Действительно ли имеет значение, к чему применяется ваша блокировка, если вы эффективно сериализуете доступ? Просто приобретите эксклюзивную блокировку для любой таблицы или строки, если на то пошло.

person eevar    schedule 06.09.2012
comment
Что ж, если бы я мог заблокировать все, всем другим соединениям пришлось бы ждать. Обновление занимает около 1-2 секунд. - person Sebi; 06.09.2012