初始提交失败后,Hibernate会话不会刷新数据库中的数据

时间:2013-10-12 01:01:14

标签: 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);不会使用来自DB的新数据刷新pojo,而是从会话中提取陈旧对象,从而无法重试。

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

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

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

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

2 个答案:

答案 0 :(得分:1)

你可以尝试从catch中的会话中驱逐对象。

hibnSessn.evict(pojo);

然后,重试的获取应该从数据库中获得一份新的副本。

刷新它也可能有用。

hibnSessn.refresh(pojo);

答案 1 :(得分:-1)

hibnSessn.flush()将从Session中删除staleobject(每个实体)。从而从db中检索 例如。

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