В моем приложении (JEE) есть процесс (задание cron). И у меня есть два его экземпляра, запущенных на двух разных машинах. Я хочу, чтобы это задание cron выполнялось только один раз. Я знаю, что есть много способов сделать это. Но я хочу сделать это с помощью таблицы базы данных Lock.
Итак, первое, что делается в этом процессе, - это получить БЛОКИРОВКУ некоторой таблицы в базе данных. Если один процесс получает блокировку, другой процесс должен немедленно прерваться.
Я использую Postgresql (10.4). Это то, что у меня есть в моем коде
Statement statement = connection.createStatement();
statement.execute("LOCK TABLE crontable NOWAIT");
Я ожидаю, что когда один процесс получит блокировку, другой процесс будет прерван (согласно документации https://www.postgresql.org/docs/10/sql-lock.html)
Но то, что происходит в настоящее время, - это то, что другой процесс ждет, пока блокировка не будет снята первым процессом.
Я что-то упустил?
@a_horse_with_no_name благодарит за совет. Я пробовал это. SELECT pg_try_advisory_lock(1) from sometable. Это работает, когда я выполняю это непосредственно в базе данных. Но когда я попробовал из java-кода (развернутого на сервере приложений). Оба процесса получают блокировку. Не уверен, что случилось. Я использую один и тот же идентификатор в обоих процессах
Вы, вероятно, включили автоматическую фиксацию в соединении JDBC, что означает, что блокировка получается через select, затем транзакция фиксируется и, таким образом, блокировка снова снимается.
Нет. Я отключил его явно. connection.setAutoCommit(false);
Тогда у вас, вероятно, есть другой код, который выполняет фиксацию после выбора. Может быть, слой обфускации, такой как Hibernate. Вы используете пул соединений?
Нет. Я использую PGSimpleDataSource datasource = new PGSimpleDataSource(); datasource.getConnection()codehare.io/50J8xD
Изучите pg_locks, если вы действительно заблокировали базу данных. Блокировка вполне может быть в коде Java.
@LaurenzAlbe. Да, у меня есть блокировка базы данных. Я заметил, что с pg_try_advisory_lock я вижу две записи в базе данных. Следовательно, взаимное исключение не работает. Но если я использую pg_advisory_lock и устанавливаю lock_timeout на 1 секунду. Я могу добиться того, чего хочу.
@a_horse_with_no_name. С pg_try_advisory_lock я наблюдал, когда один процесс запускается и получает блокировку. Я вижу три записи, созданные в pg_locks с отношением lock_type, virtualxid и advice) Когда другой процесс работает параллельно и пытается получить блокировку. он создал еще две записи в pg_locks с lock_type в качестве отношения и virtualxid. И, следовательно, второй процесс не прерывается (как я ожидал). Но если я буду использовать pg_advisory_lock и lock_timeout, то смогу добиться того, чего хочу. Есть мысли, почему pg_try_advisory_lock не работает?




Не связано с вашей проблемой: я думаю, что консультативный замок больше подходит для такого рода задач