【问题标题】:Hibernate session and transaction across methods跨方法休眠会话和事务
【发布时间】:2015-07-13 08:05:16
【问题描述】:

我有一个从sessionFactory.openSession() 检索的休眠会话,以及一些对Entities 的复杂计算,并且我想在计算期间持久化(UPDATE, INSERT, DELETE)一些Entities

这是一个案例:

假设我有一个代表产品的ProductEntity,代表产品订单记录的OrderEntity,以及代表预订产品订单的用户的UserEntity

我知道我可以通过这种方式处理预订操作:

  public void addOrder(UserEntity userEntity, ProductEntity productEntity, int quantity){
       session = sf.openSession();
       Transaction tx = session.beginTransaction();
       //do some compution and generate the orderEntity and persistent it to the db.
       try{
          tx.commit();
       }catch(Exception e){
          tx.rollback();
       }finnaly{
          session.close();
       }
 }

现在我必须向该过程添加更多操作,例如 (Maybe) 创建一个 NotifyEntity 并存储在 db 中,它代表拥有该产品的商家的通知记录。这个notify 记录可以由orderEntity 生成,与productEntityUserEntity 无关,实际上,我希望这个notifyMerchantByOrderEntity 方法从addOrder 过程中分离出来,以便我可以复用这个方法,把代码搞清楚(我真的不想在同一个方法里搞一大堆代码,其实如果校验逻辑够复杂的话,addOrder方法的代码可以很- 很长)。

无论如何,我想:

  • 将一个很长的事务分成几个方法
  • 但是这些方法应该作为一个整体的事务一起考虑(即当异常发生时它们应该一起回滚)

类似这样的:

 public void addOrder(UserEntity userEntity, ProductEntity productEntity, int quantity){
    Session session = sf.openSession();
    session.beginTransaction();
    invokeOtherMethod();  //invoking other method which also contains some db operation.
    try{
       tx.commit()
    }catch(Exception e){
       tx.rollback(); //this should rollback the operation in invokeOtherMethod() too.
    }finally{
       session.close();
    }
 }

【问题讨论】:

    标签: java hibernate session orm transactions


    【解决方案1】:

    我找到了一种替代方法,它将session 传递给将被调用的方法。并且测试演示显示我还可以在发生异常时回滚 invoked 方法中的数据库操作,尽管@Vlad 给出的答案可能值得一试。我在这里发布我这样做的方式,希望它可以激发遇到类似问题的人。

    public OrderEntity addOrder(UserEntity userEntity, ProductEntity, int quantity){
          Session session = sf.openSession();
          try{
              Transaction tx = session.beginTransaction();
              OrderEntity orderEntity = new OrderEntity(userEntity, productEntity, quantity);
              session.save(orderEntity);
              notifyMerchant(orderEntity, session); //here we will invoke another method with session together.
              tx.commit();
              return orderEntity;
         }catch(Exception e){
              e.printStack();
              tx.rollback(); // if Exception occurs all the operations making to the db will be rollback, as well as those operations in method notifyMerchant();
              return null; 
         }finally{
            session.close();
         } 
    }
    
    private void notifyMerchant(OrderEntity orderEntity, Session session){
         NotifyEntity notifyEntity = new NotifyEntity(orderEntity);
         notifyEntity.notifyMerchant();
         session.save(notifyEntity); // this will save the notifyEntity to db as a sort of log stuff;
    }
    

    @Vlad 可能会提供更好的方法,目前上述实现是我的项目更改较少的方式。

    【讨论】:

      【解决方案2】:

      您应该切换到使用Spring TransactionManager,因为它允许您将多个 DAO 调用分组到同一个数据库事务中。

      如果您不想使用 Spring,您仍然可以使用服务层方法拦截器(可能是动态代理或 Javassist)来实现事务管理逻辑,该方法使用 ThreadLocal 存储将当前线程绑定到同一个 Hibernate Session

      当你进入事务边界时你打开事务,当你离开事务边界时,如果没有抛出异常则提交事务,如果捕获到任何异常则回滚:

      private SessionFactory sf;
      
      private final ThreadLocal<Session> sessionStorage =
              new ThreadLocal<Session>();
      
      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
          Session session = sessionStorage.get();
          if(session == null) {
              session = sf.openSession();
          }
          Transaction tx = session.beginTransaction();
          try{
              return method.invoke(target, args);
              tx.commit();
          }catch(Exception e){
              tx.rollback();
              throw new ServiceException(e);
          }finally{
              session.close();
              sessionStorage.remove();
          }
      }
      

      现在您必须将此拦截器编织到所有 Service 方法调用。

      【讨论】:

        猜你喜欢
        • 2014-07-26
        • 2011-06-08
        • 2011-06-13
        • 1970-01-01
        • 2017-06-19
        • 2017-09-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多