我想从我的应用程序内部运行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应用程序进行连接。
答案 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")
}
}
}
}