pg_advisory_lock работает, но не pg_try_advisory_lock - PullRequest
0 голосов
/ 04 января 2019

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

Я использую консультативные блокировки для достижения этой цели.

Когда я пытался использовать консультативные блокировки. Это то, что я заметил.

Я создал специальную таблицу для этого. Например, таблица с именем «cron». Когда я пытаюсь

SELECT pg_advisory_lock (123) ОТ cron ,

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

Во-вторых, когда я просмотрел документацию, я обнаружил, что вместо pg_advisory_lock я также могу использовать pg_try_advisory_lock, который будет возвращать true или false (в отличие от pg_advisory_lock, который выдает исключение).

Но когда я попробовал pg_try_advisory_lock, я заметил, что один процесс извиняется и получает блокировку. Я вижу три записи, созданные в pg_locks с отношением lock_type , virtualxid и advisory ) Когда другой процесс работает параллельно и пытается получить блокировку, он создает еще два записи в pg_locks с lock_type как отношение и virtualxid . И, следовательно, второй процесс также возвращает true.

С помощью pg_try_advisory_lock оба процесса возвращают true.

Но если я использую pg_advisory_lock и использую lock_timeout (с очень низким значением), то второй процесс завершается с исключением. Таким образом, я мог добиться взаимного исключения.
Так почему же он не работает с pg_try_advisory_lock, а работает с pg_advisory_lock (в сочетании с таймаутом блокировки)?

Любой намек очень ценится

Я использую Postgresql. И подключение через приложение Java.

1 Ответ

0 голосов
/ 04 января 2019

Вам не нужна таблица для выполнения функции.Используйте только

SELECT pg_advisory_lock(123);

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

Функция pg_try_advisory_lock() просто возвращает логическое значение.Он не может автоматически прервать текущую транзакцию.Вы должны проверить, что возвращает функция, и предпринять некоторые действия в зависимости от результата.


Обновление.Метод lockTable() в вашем коде всегда возвращает true.

private static boolean lockTable(Connection connection, LocalDateTime now) throws SQLException {
    String sqlQuery = String.format(GET_LOCK, now.getDayOfYear());
    try (PreparedStatement ps = connection.prepareStatement(sqlQuery)) {
        try (ResultSet rs = ps.executeQuery()) {
            return rs.next();
            // obviously, this always returns true
            // instead you should do something like
            // return rs.getBool("pg_try_advisory_lock")
            }
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...