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

Java JPA/Hibernate-不需要的部分回滚和会话处理,java,hibernate,jpa,transactions,Java,Hibernate,Jpa,Transactions,我使用无状态EJB类来更新数据库中的持久性实体。EJB中的方法调用完成工作的实现类。我认为导致问题的原因是,一个名为Foo的实体与一个实体Bar有一个单一的关系。事情完成后,会话将使用Foo进行更新,它“级联”到Bar。当发生StaleObjectStateException时,事务没有完全回滚,这会由于明显的原因导致错误 EJB: private Session getSession() throws BusinessException { if( this.sess == null

我使用无状态EJB类来更新数据库中的持久性实体。EJB中的方法调用完成工作的实现类。我认为导致问题的原因是,一个名为
Foo
的实体与一个实体
Bar
有一个单一的关系。事情完成后,会话将使用
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 );
        }
    }
}
@OneToMany(cascade=CascadeType.ALL, mappedBy="foo")
@OrderBy("startTime DESC")
Set<Bar> barList;
实施

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 );
        }
    }
}
@OneToMany(cascade=CascadeType.ALL, mappedBy="foo")
@OrderBy("startTime DESC")
Set<Bar> barList;
相关食品代码

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 );
        }
    }
}
@OneToMany(cascade=CascadeType.ALL, mappedBy="foo")
@OrderBy("startTime DESC")
Set<Bar> barList;
@OneToMany(cascade=CascadeType.ALL,mappedBy=“foo”)
@订购人(“开始时间描述”)
设置条码列表;
因此,基本上,当事务尝试回滚时,已更改的条形图部分将回滚,但新的条形图(代码中的bar2)记录将保留

任何指导都将不胜感激。就像我说的,我相信这里的错误与sess.update(foo)有关;可能与
自动提交有关,但默认情况下它应处于关闭状态

我相信正在发生的事情是Session.Update(foo)反过来创建了两个独立的事务。具体来说,更新
Foo
(SQL更新),但保存
(SQL插入)。因为事务上下文只会真正看到SQL更新,所以它只会反转这些。我们必须进一步调查这件事


我已尝试将
会话.FlushMode
更改为
提交
,但似乎仍然无法解决问题。但是,它确实部分解决了问题。。它将正确回滚条目,但导致StaleObjectStateException的特定条目除外。该特定条目实际上已从数据库中删除…

我成功地解决了我的问题。。我会等着接受它的情况下,其他人张贴更好的东西,更多。。。值得赏金。

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

我将EJB更改为具有以下内容:

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;
  }   
}
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 );
      }
  }
}
然后,实现代码将具有以下内容:

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

好吧,这是我的两分钱,因为这也是关于JPA的:

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

1.@进行存储库调用之前的事务性注释(处理回滚)

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

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

    }

}
save和flush在内部的作用是:

/*
     * (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);
    }
}
/*
*(非Javadoc)
*@see org.springframework.data.repository.crudepository#save(java.lang.Object)
*/
@交易的
公共存储(S实体){
if(entityInformation.isNew(实体)){
em.persist(实体);
返回实体;
}否则{
返回em.merge(实体);
}
}
然后em.flush()

在这种情况下,在此之后,如果您遇到@Audited versioning问题,删除的记录不会显示,那么将org.hibernate.envers.store\u data\u设置为\u delete=true


希望这能为解决方案增加透视图。

您使用的是什么版本的EJB?您的持久性提供者是什么?为什么EJB调用另一个实现类(什么类型?),以及其他“”类如何访问
sess
(我假设是某种持久性会话)?如果您使用的是EJB,那么实际上应该使用and,而不是自定义tx和会话。关于您的问题,我猜EJB中的
sess
对象与impl类中的
sess
不同。sess
通过构造函数传递到impl中。你可能是对的。我已经解决了我的问题,但我会研究你说的话,因为我认为这将是一个更干净的解决方案。从你的描述来看,这听起来不像是这个特定的问题,但请注意,为了使条正确地关联到foo,需要正确地设置条上的“foo”成员(mappedBy=“foo”)。级联将session.update()调用转发到barList上的bars,但关联仍由“mappedBy”管理。getSession()方法看起来如何?分别是如何配置Hibernate的?但是您确实应该尝试使用容器管理的事务和注入的@PersistenceContext,而不是getSession()和getSession.beginTransaction()&try/catch/finally.Michal,问题是我无法更改代码的体系结构,因为它是正在生产的代码。从字面上说,它是用来生产制成品的。这些资源根本无法改变这些事情。但是谢谢你的建议。我不使用Spring,所以它并不完全适用。。只是有点。但是因为你增加了一点洞察力,没有其他人回答。。有一些代表。谢谢你的努力。