1

我对使用休眠多线程Java应用程序的工作。我们得到一个org.hibernate.StaleObjectStateException因为我们有到位乐观锁定和某些实体(我们称之为Pojo)从许多应用模块,它可以和已经在竞争条件(我没有设计的应用程序)相撞更新。有问题的代码块看起来是这样的:Hibernate会话没有刷新数据后,初始提交失败

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如果初始提交失败,由于竞争条件下,我们进入另外的尝试,希望能在一个干净,unconflicted交易成功。我不喜欢这种模式,但必须暂时与它合作。

我已经能够仪打破在行pojo.setSomeVar("xyz");,从另一个线程/法和程序,从而未能提交并进入捕,由于乐观锁定更新数据库中的竞争条件,回滚和进入重试循环的下一次迭代。

问题是,在第二次迭代中,行pojo = hibnSessn.get(Pojo.class, pojoID);不刷新pojo与来自数据库的新数据,但从会话中拉出陈旧的对象,击败重试的目的。

另一个有趣的事情是,hibnSessn.get(...)不会真正去到DB(正常情况下),因为当我提交失败之前hibnSessn.get前更改数据从另一个线程/法在第一次迭代,对象也得到刷新。在提交失败并且事务回滚之后,它只会失败。

我寻找各种方法来强制Hibernate进入数据库,并刷新该对象在经过最初提交失败。

更新:我试着evict/refresh在赶上刷新对象,但也导致StaleObjectStateException

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

+0

有关使用查询,而不是刷新什么?类似于“来自Pojo的id =?”这只是一个尝试,基本上它们不应该有所不同。 –

回答

-1

hibnSessn.flush()将删除该会话的staleobject(每单位为此事)。因此从db 中检索例如

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

当我尝试刷新时,出现'StaleObjectStateException' – amphibient

+0

您可以将stacktrace添加为附加信息plz。我会添加int pojoID = pojo.getID();你的for循环之外 –

+0

'flush()'没有帮助,它的目的是将数据写入数据库 - 但是你处于一个无法写入的锁冲突状态。 –

1

您可以尝试从catch中的会话中逐出对象。

hibnSessn.evict(pojo); 

在重试的获得则应该从DB获得一个新的副本。

刷新它也可能工作。

hibnSessn.refresh(pojo); 
+0

'refresh()'是正确的方法。您将失去对刷新实体的任何现有更改,但锁定冲突将得到解决 - 因此您可能需要将更改后的逻辑更改重新应用于刷新的实体。 –

+0

我完全试过这个解决方案(有和没有evict),并且两次我得到一个'StaleObjectStateException' – amphibient