首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >JPA/Hibernate -不需要的部分回滚和会话处理

JPA/Hibernate -不需要的部分回滚和会话处理
EN

Stack Overflow用户
提问于 2015-07-21 03:27:07
回答 2查看 2.7K关注 0票数 19

我正在使用无状态EJB类来更新位于数据库中的持久性实体。EJB中的方法调用完成工作的实现类。我认为导致该问题的原因是一个名为Foo的实体与一个实体Bar之间存在oneToMany关系。一切都完成了,会话用“级联”到BarFoo进行了更新。当发生StaleObjectStateException时,事务没有完全回滚,这会导致错误,原因很明显。

EJB

代码语言:javascript
复制
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;
    }   
}

Implementation

代码语言:javascript
复制
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代码

代码语言:javascript
复制
@OneToMany(cascade=CascadeType.ALL, mappedBy="foo")
@OrderBy("startTime DESC")
Set<Bar> barList;

因此,基本上,当事务尝试回滚时,已更改的条形图部分将被回滚,但新的条形图(代码中的bar2)记录仍将保留。

任何指导都将不胜感激。就像我说的,我认为这里的错误与sess.update(foo)有关;可能与autocommit有关,但默认情况下它应该是关闭的。

我认为,正在发生的情况是,Session.Update(foo)反过来创建了两个独立的事务。具体地说,更新了Foo (SQL UPDATE),但保存了Bar (SQL INSERT)。因为事务上下文只会真正看到SQL更新,所以这就是它要反转的全部内容。将不得不对此进行更多的调查..

我已经尝试将Session.FlushMode更改为COMMIT,但似乎仍然不能解决问题。然而,它确实部分地解决了这个问题。它将正确地回滚条目,但导致StaleObjectStateException的特定条目除外。该特定条目实际上已从数据库中删除...

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-11-17 23:00:43

我设法解决了我的问题..我会等着接受它,以防别人发布更好的东西,更多的东西…… bounty better。

基本上,通过将FlushMode更改为manual,并在整个过程中手动刷新,我可以更早地捕获StaleObjectException,从而更快地回退代码。我仍然保留着部分回滚记录的工件..但是,此方法按计划每2分钟运行一次,因此在第二次遍历期间,它修复了所有问题。

我更改了我的EJB,使其具有以下内容:

代码语言:javascript
复制
public void cutoffOrders(  ) throws Exception {
  Transaction tx = null;
  try {
      tx = getSession().beginTransaction();
      getSession().setFlushMode(FlushMode.MANUAL);
      getImpl().cutOffFoos(fooTime);
      getSession().flush();
      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;
  }   
}

然后实现代码要有以下几点:

代码语言:javascript
复制
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 ...
               sess.flush();
               if( ... ) {
                   ... Code that makes new Bar object ...
                   foo.getBarList().add(bar2);
               }
          }
          sess.flush();
          sess.update( foo );
      }
  }
}
票数 4
EN

Stack Overflow用户

发布于 2015-11-19 04:12:13

好吧,这是我对此的两点看法,因为这也适用于JPA:

在Spring Data JPA中,您可以只使用以下内容:

1.在进行存储库调用之前使用@Transactional注释(处理回滚)

2.使用JPA仓库saveAndFlush方法,即:

代码语言:javascript
复制
@Service
public class ProductionOrderServiceImpl extends ProductionOrderService{

    @Autowired
    ProductionOrderRepository jpaRepository;

    @Transactional
    public void cutoffOrders( Timestamp fooTime ){

    ... Code that gets fooList ...
      if( fooList != null ) {
          for( Foo foo: fooList ) {
              for( Bar bar : foo.getBarList() ) {
                   ... Code that does things with existing Barlist ...
                   {Call another similar method with @transactional..}//saveAndFlush(BarList);
                   if( ... ) {
                       ... Code that makes new Bar object ...
                       foo.getBarList().add(bar2);
                   }
              }
              jpaRepository.saveAndFlush(foo);
          }
      }

    }

}

在内部保存和刷新的操作是这样的:

代码语言:javascript
复制
/*
     * (non-Javadoc)
     * @see org.springframework.data.repository.CrudRepository#save(java.lang.Object)
     */
@Transactional
public <S extends T> S save(S entity) {

    if (entityInformation.isNew(entity)) {
        em.persist(entity);
        return entity;
    } else {
        return em.merge(entity);
    }
}

然后是em.flush();

在此之后,如果您遇到@Audited版本控制问题,其中删除的记录没有显示,则设置org.hibernate.envers.store_data_at_delete=true.

希望这增加了解决方案的视角。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31524763

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档