pg_advisory_lock有效,但不能使用pg_try_advisory_lock

时间:2019-01-04 11:34:41

标签: java postgresql locking

我想从我的应用程序内部运行cron作业。但是,当我运行此应用程序的多个实例时,希望相互排斥。即cron作业仅通过单个过程运行。

我正在使用 咨询锁 来实现这一目标。

当我尝试使用咨询锁时。这就是我注意到的。

我为此创建了专用表。例如,名为“ cron”的表。当我尝试

从cron中选择pg_advisory_lock(123)

它没有任何锁。但是,当我在该表中插入一行并再次尝试相同的命令时,则成功获取锁定。
所以我的问题是:是否必须至少有一行才能获得咨询锁定?还是我在这里想念东西?

第二,当我阅读文档时,我发现除了pg_advisory_lock之外,我还可以使用pg_try_advisory_lock,它会返回true或false(与pg_advisory_lock会引发异常)不同。

但是当我尝试pg_try_advisory_lock时,我观察到的是,当一个进程执行并获得锁时。我看到在pg_locks中创建了带有lock_type relation virtualxid advisory 的三个条目。)当另一个进程并行运行并尝试获取锁时,它在pg_locks中创建了另外两个条目,其lock_type为 relation virtualxid 。因此,第二个过程也返回true。

使用pg_try_advisory_lock,两个过程均返回true。

但是,如果我使用pg_advisory_lock并使用lock_timeout(值非常低),那么第二个进程将异常退出。这样我就可以实现互斥。
那么为什么它不能与pg_try_advisory_lock一起使用,却可以与pg_advisory_lock一起使用(结合锁定超时)?

任何提示都非常感谢

我正在使用Postgresql。并通过Java应用程序进行连接。

1 个答案:

答案 0 :(得分:1)

您不需要表即可执行功能。只需使用

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")
            }
        }
    }
}