【发布时间】:2015-10-10 01:31:39
【问题描述】:
我正在使用无状态 EJB 类来更新位于数据库中的持久性实体。 EJB 中的方法调用完成工作的实现类。我相信导致问题的原因是一个名为Foo 的实体与一个实体Bar 具有oneToMany 关系。事情已经完成,会话更新为Foo,它“级联”到Bar。当StaleObjectStateException 发生时,事务没有完全回滚,这会导致错误,原因很明显。
EJB:
private Session getSession() throws BusinessException {
if( this.sess == null ) {
ServiceLocator locator = new ServiceLocator();
SessionFactory sf = locator.getHibernateSessionFactory();
this.sess = sf.openSession();
}
return this.sess;
}
private ProductionOrderImpl getImpl() throws BusinessException {
if( this.impl == null ) {
this.impl = new ProductionOrderImpl( getSession() );
}
return this.impl;
}
public void cutoffOrders( ) throws Exception {
Transaction tx = null;
try {
tx = getSession().beginTransaction();
getImpl().cutOffFoos(fooTime);
tx.commit();
} catch (StaleObjectStateException e1){
if (tx != null) tx.rollback();
logger.error( "Failed to cutoff order : " + e1 );
throw new Exception( LocaleMgr.getMessage());
}
finally {
// reset implementation object, close session,
// and reset session object
impl = null;
sess.close();
sess = null;
}
}
实施:
public ProductionOrderImpl(Session sess) {
this.sess = sess;
}
public void cutoffFoos( Timestamp fooTime) throws Exception {
... Code that gets fooList ...
if( fooList != null ) {
for( Foo foo: fooList ) {
for( Bar bar : foo.getBarList() ) {
... Code that does things with existing Barlist ...
if( ... ) {
... Code that makes new Bar object ...
foo.getBarList().add(bar2);
}
}
sess.update( foo );
}
}
}
相关 Foo 代码:
@OneToMany(cascade=CascadeType.ALL, mappedBy="foo")
@OrderBy("startTime DESC")
Set<Bar> barList;
所以基本上,当事务尝试回滚时,已更改的 Bar 部分会回滚,但新的 Bar(代码中的 bar2)记录仍然存在..
任何指导将不胜感激。就像我说的,我相信这里的错误与 sess.update(foo); 有关。可能与autocommit 有关,但默认情况下它应该是关闭的。
我相信正在发生的事情是 Session.Update(foo) 反过来创建了两个单独的事务。具体来说,Foo 已更新 (SQL UPDATE),但 Bar 已保存 (SQL INSERT)。由于事务上下文只会真正看到 SQL UPDATE,这就是它的全部反转。将不得不对此进行更多研究..
我已尝试将Session.FlushMode 更改为COMMIT,但似乎仍无法解决问题。但是,它确实部分解决了问题。它会正确回滚条目,但导致 StaleObjectStateException 的特定条目除外。该特定条目实际上已从数据库中删除...
【问题讨论】:
-
您使用的是什么版本的 EJB?您的持久性提供者是什么?你为什么要 EJB 调用另一个实现类(什么类型?),那个 ,,other'' 类如何访问
sess(我假设某种持久性会话)?如果您使用的是 EJB,那么您真的应该使用 Container managed transactions 和 EntityManager 而不是自定义 tx 和会话。关于您的问题,我猜想 EJB 中的sess对象与您的 impl 类中的sess不同。 -
sess通过构造函数传递给 impl。你可能是对的。我已经解决了我的问题,但我会调查你所说的,因为我认为这将是一个更干净的解决方案。 -
从您的描述来看,这听起来不是这个特殊问题,但请注意,为了使条正确关联到 foo,需要设置条上的 'foo' 成员正确(mappedBy="foo")。 CASCADE 将 session.update() 调用转发到 barList 上的 bar,但关联仍由“mappedBy”管理。
-
您的 getSession() 方法看起来如何?分别,Hibernate是如何配置的?但是你真的应该尝试使用容器管理的事务并注入 @PersistenceContext 而不是 getSession() 和 getSessin.beginTransaction() & try/catch/finally。
-
Michal 的问题是我无法更改代码的体系结构,因为它是生产中的代码。从字面上看,它用于生产制成品。资源根本无法改变这些事情。不过谢谢你的建议。
标签: java hibernate jpa transactions