我有一个从sessionFactory.openSession()
检索到的hibernate会话,以及一些复杂的计算到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
生成,与productEntity
或UserEntity
无关,事实上,我希望此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();
}
}
答案 0 :(得分:1)
您应该切换到使用Spring TransactionManager,因为它允许您将多个DAO调用分组到同一个数据库事务中。
如果您不想使用Spring,您仍然可以使用服务层方法拦截器(可能是动态代理或Javassist)来实现事务管理逻辑,该拦截器使用ThreadLocal存储将当前Thread绑定到同一个Hibernate会话
当您输入事务边界时,您打开事务,当您离开事务边界时,如果没有抛出异常则提交事务,或者如果您发现任何异常,则将其回滚:
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方法调用中。
答案 1 :(得分:1)
我找到了另一种方法来将session
传递给将要调用的方法。测试演示显示,当发生异常时,我也可以在调用的方法中回滚数据库操作,虽然给出的答案@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可能会提供更好的方法,目前上面的工具是我的项目变化较少的方式。