使用JDBC模板(Postgres)时,select for update不起作用

3

我希望我的Java代码有多个实例可以读取相同的数据集,并且我想要锁定第一个实例读取记录(行级别)。这样第二个实例就不会读取相同的数据。以下是我的示例代码,但它无法工作。如果我同时读取两次,我会得到相同的记录。为了测试目的,我创建了列表1和列表2,并依次读取两次以模拟多个实例读取同一数据。

    query = "SELECT  * from xyz LIMIT 10  FOR UPDATE of xyz"

            List<XYZ> list1= new ArrayList<XYZ>();
    List<XYZ> list2= new ArrayList<XYZ>();

    DefaultTransactionDefinition def = new DefaultTransactionDefinition();
    def.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);

    TransactionStatus s=datasourceconfig.platformTransactionManager.getTransaction(def);

    try {
        list1= datasourceconfig.queryForObjectList(query , paramMap ,XYZ.class);

    } catch (Exception ex) {
        log.error("", ex);
    }

    try {
        list2= datasourceconfig.queryForObjectList(query,paramMap,XYZ.class);
    } catch (Exception ex) {
        log.error("", ex);
    }

    empDsCfg.platformTransactionManager.commit(s);

当我收到结果时,两个列表都有相同的记录。请帮助。

我不确定您是否理解 FOR UPDATE 锁的作用。它们(通常)只阻止其他事务修改所选行(但从不隐藏它们)。如果在同一事务中读取行,则永远不会发生此阻塞。而且,在SERIALIZABLE隔离级别中其运行方式略有不同。请仔细阅读有关事务隔离的文档。我们只能重复那里写的内容。 - pozs
1个回答

0

如果您使用的是 PostgreSQL 9.5 或更高版本,则可以使用

SELECT ...
LIMIT 10
FOR UPDATE SKIP LOCKED;

这将选择并锁定最多十行,这些行尚未被并发事务锁定。

可以在所有PostgreSQL版本中使用的替代方法是使用如下的咨询锁:

SELECT ...
WHERE pg_try_advisory_xact_lock(id)
LIMIT 10
FOR UPDATE;

这里的id是主键,假设它是一个整数值(可以隐式转换为bigint类型)。

此函数返回TRUE,如果还没有具有该编号的独占advisory lock,则会获取锁作为副作用。

注意:锁仅在事务期间保持,因此请确保在单个事务中执行锁定和随后的数据修改。


跳过锁定在9.5上运行,但必须添加begin和end/commit才能使其工作。 - Ammar
我以为那是被理解的,但我已经添加了一条注释来澄清。 - Laurenz Albe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接