简体   繁体   English

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

[英]Hibernate session not refreshing data from DB after initial commit failure

I am working on a multithreaded Java application that uses Hibernate . 我正在使用Hibernate的多线程Java应用程序上工作。 We are getting a org.hibernate.StaleObjectStateException because we have optimistic locking in place and a certain entity (let's call it Pojo ) is updated from many application modules, which can and have collided in race conditions (I have not designed the application). 我们之所以得到org.hibernate.StaleObjectStateException是因为我们拥有乐观的锁定 ,并且从许多应用程序模块更新了某个实体(我们称其为Pojo ),这些模块可能会在竞争条件下发生冲突(我没有设计应用程序)。 The problematic code block looks something like this: 有问题的代码块如下所示:

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;
}

And Pojo.hbm.xml starts something like this: 然后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"/>
        ...

The original author of this code put in the above retry loop precisely because there are other modules that also update Pojo and if the initial commit fails due to a race condition, we go into additional attempts, hoping to succeed in a clean, unconflicted transaction. 该代码的原始编写者放入上面的重试循环中,恰恰是因为还有其他模块也更新了Pojo并且如果初始提交由于竞争条件而失败,我们将进行其他尝试,希望能够在干净无冲突的事务中取得成功。 I dislike this pattern but have to work with it for the time being. 我不喜欢这种模式,但暂时必须使用它。

I have been able to instrument the race condition by breaking at line pojo.setSomeVar("xyz"); 我已经能够通过在pojo.setSomeVar("xyz");处断开来检测比赛条件pojo.setSomeVar("xyz"); , updating the database from another thread/method, and proceeding, which fails the commit and goes into the catch, due to the optimistic locking, rolling back and going into the next iteration of the retry loop. ,从另一个线程/方法更新数据库,然后继续进行,由于乐观锁定,回滚并进入重试循环的下一个迭代,导致提交失败并进入陷阱。

The problem is that, in the second iteration, the line pojo = hibnSessn.get(Pojo.class, pojoID); 问题在于,在第二次迭代中,行pojo = hibnSessn.get(Pojo.class, pojoID); does not refresh pojo with the fresh data from DB but pulls the stale object from the session, defeating the purpose of the retry. 不会使用数据库中的新鲜数据刷新pojo ,而是从会话中提取陈旧的对象,从而破坏了重试的目的。

Another interesting thing is that hibnSessn.get(...) does actually go into the DB (under normal conditions) because when I change the data from another thread/method before hibnSessn.get in the first iteration before a commit failure, the object does get refreshed. 另一个有趣的事情是hibnSessn.get(...)实际上确实进入了数据库(在正常情况下),因为当我在提交失败之前的第一次迭代中更改了hibnSessn.get之前的另一个线程/方法中的数据时,该对象确实刷新了。 It only fails to do so after a commit has failed and the transaction rolled back. 只有在提交失败并且事务回滚之后,它才能这样做。

I am looking for ways to force Hibernate to go into the DB and refresh the object after an initial commit failure. 我正在寻找强制Hibernate在最初的提交失败后进入数据库并刷新对象的方法。

UPDATE: I tried evict/refresh in the catch to refresh the object but that also resulted in a StaleObjectStateException . 更新:我尝试在捕获中evict/refresh来刷新对象,但这也导致了StaleObjectStateException

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

You could try evicting the object from the session in the catch. 您可以尝试从捕获中的会话中逐出对象。

hibnSessn.evict(pojo);

The get on the retry should then get a fresh copy from the DB. 然后,重试的get应该从数据库中获得一个新副本。

Refreshing it might also work. 刷新它也可能有效。

hibnSessn.refresh(pojo);

hibnSessn.flush() will remove the staleobject (every entity for that matter) from the Session. hibnSessn.flush()将从会话中删除旧对象(与此有关的每个实体)。 Thus retrieve from the db for eg 因此从数据库中获取例如

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM