java - Hibernate session 在初始提交失败后未刷新数据库中的数据

标签 java multithreading hibernate optimistic-locking stalestateexception

我正在开发一个使用Hibernate的多线程Java应用程序。我们收到org.hibernate.StaleObjectStateException,因为我们有乐观锁定,并且某个实体(我们称之为Pojo)从许多应用程序模块,它们可能并且已经在竞争条件下发生冲突(我没有设计该应用程序)。有问题的代码块看起来像这样:

Transaction txn = null;
HibernateException ex = null

for(int retryAttempt = 0; retryAttempt < 5; retryAttempt++) {
    try {
        txn = hibnSessn.beginTransaction();

        int pojoID = pojo.getID();
        pojo = hibnSessn.get(Pojo.class, pojoID);

        pojo.setSomeVar("xyz");

        txn.commit();

        ex = null;
    } catch(HibernateException e) {
        if (txn != null)
        {
            txn.rollback();
        }

        ex = e;
        // Gonna keep retrying
        continue;
    }

    break;
}

并且Pojo.hbm.xml开始这样的事情:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
    <class name="com.myproject.Pojo" table="pojo">
        <id name="id" column="id" type="int">
            <generator class="identity"/>
        </id>
        <!-- this is used to enforce optimistic locking -->
        <version name="dbVersion" column="db_version"/>
        ...

这段代码的原作者之所以加入上述重试循环,正是因为还有其他模块也会更新 Pojo,并且如果初始提交由于竞争条件而失败,我们将进行额外的尝试,希望在干净、无冲突的交易中取得成功。我不喜欢这种模式,但暂时必须使用它。

我已经能够通过在 pojo.setSomeVar("xyz"); 行处中断来检测竞争条件,从另一个线程/方法更新数据库,然后继续,这会导致提交失败并由于乐观锁定,进入 catch,回滚并进入重试循环的下一次迭代。

问题是,在第二次迭代中,行 pojo = hibnSessn.get(Pojo.class, pojoID); 不会使用新数据刷新 pojo从数据库中获取,但从 session 中提取过时的对象,从而违背了重试的目的。

另一件有趣的事情是 hibnSessn.get(...) 实际上会进入数据库(在正常情况下),因为当我在 hibnSessn 之前从另一个线程/方法更改数据时.get 在提交失败之前的第一次迭代中,对象确实被刷新。只有在提交失败且事务回滚后,它才会执行此操作。

我正在寻找方法来强制 Hibernate 在初始提交失败后进入数据库并刷新对象。

更新:我在 catch 中尝试了 evict/refresh 来刷新对象,但这也导致了 StaleObjectStateException

相关: https://stackoverflow.com/questions/19364343/staleobjectstateexception-when-evicting-refreshing-stale-object-from-hibernate-s

最佳答案

您可以尝试在 catch 中从 session 中逐出该对象。

hibnSessn.evict(pojo);

重试时的获取应该从数据库获取新的副本。

刷新它也可能有效。

hibnSessn.refresh(pojo);

关于java - Hibernate session 在初始提交失败后未刷新数据库中的数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19329338/

相关文章:

java - 将二维数组转换为组织表格外观

java - 将 JSONObject 转换为 Java 对象

java - ReentrantLock 线程随机终止

java - 使用图像作为按钮,获得空白屏幕

c# - 线程安全的异步方法

multithreading - OpenGL中的多线程渲染

spring - 未能延迟初始化集合

java - 运行一个简单的 Hibernate 项目没有效果

java - JUnit-Test 类测试和项目测试之间存在差异

java - 从外部 bean 注入(inject) bean 属性