初始提交失败后,Hibernate会话不会从数据库刷新数据 [英] Hibernate session not refreshing data from DB after initial commit failure

查看:177
本文介绍了初始提交失败后,Hibernate会话不会从数据库刷新数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究使用 Hibernate 的多线程Java应用程序。我们得到一个 org.hibernate.StaleObjectStateException ,因为我们有乐观锁定和一个特定的实体(我们称之为 Pojo )从许多应用程序模块更新,这些应用程序模块可能会在竞争条件下发生冲突(我还没有设计应用程序)。有问题的代码块看起来像这样:

  Transaction txn = null; 
HibernateException ex = null
$ b 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;
//要继续重试
继续;
}

break;
}

Pojo.hbm.xml 开始如下所示:

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

< hibernate-mapping>
< class name =com.myproject.Pojotable =pojo>
< id name =idcolumn =idtype =int>
< generator class =identity/>
< / id>
<! - - 用于执行乐观锁定 - >
< version name =dbVersioncolumn =db_version/>
...

此代码的原始作者恰恰放入了上述重试循环,因为还有其他模块也会更新 Pojo ,并且如果由于竞争条件而导致初始提交失败,我们会进行额外的尝试,希望能够成功进行干净的非冲突事务。我不喜欢这种模式,但必须暂时与它合作。



我已经能够通过在 pojo处进行检查来检查比赛情况.setSomeVar(xyz); ,从另一个线程/方法更新数据库,然后继续执行,由于乐观锁定,回滚并进入重试循环的下一次迭代。

问题在于,在第二次迭代中, pojo = hibnSessn.get(Pojo.class,pojoID); 不会刷新 pojo 与来自数据库的新数据,但会从会话中提取旧的对象,从而破坏重试的目的。



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



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



更新:我在catch中捕获了 evict / refresh 刷新对象,但也导致 StaleObjectStateException



相关: < a href =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

解决方案

您可以尝试将对象从这个会议在catch。

  hibnSessn.evict(pojo); 

获得重试应该从数据库中获得新的副本。



刷新它也可以。

  hibnSessn.refresh(pojo); 


I am working on a multithreaded Java application that uses Hibernate. 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). 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:

<?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. 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");, 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); does not refresh pojo with the fresh data from DB but pulls the stale object from the session, defeating the purpose of the retry.

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. 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.

UPDATE: I tried evict/refresh in the catch to refresh the object but that also resulted in a StaleObjectStateException.

RELATED: 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.

Refreshing it might also work.

hibnSessn.refresh(pojo);

这篇关于初始提交失败后,Hibernate会话不会从数据库刷新数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆