我有一个保存bean的代码,并通过Hibernate更新数据库中的另一个bean。它必须在同一个事务中执行,因为如果出现错误(f.ex启动异常),则必须对这两个操作执行回滚。
public class BeanDao extends ManagedSession {
public Integer save(Bean bean) {
Session session = null;
try {
session = createNewSessionAndTransaction();
Integer idValoracio = (Integer) session.save(bean); // SAVE
doOtherAction(bean); // UPDATE
commitTransaction(session);
return idBean;
} catch (RuntimeException re) {
log.error("get failed", re);
if (session != null) {
rollbackTransaction(session);
}
throw re;
}
}
private void doOtherAction(Bean bean) {
Integer idOtherBean = bean.getIdOtherBean();
OtherBeanDao otherBeanDao = new OtherBeanDao();
OtherBean otherBean = otherBeanDao.findById(idOtherBean);
.
. (doing operations)
.
otherBeanDao.attachDirty(otherBean)
}
}
问题是:
如果是
session.save(bean)
启动错误,然后我得到AssertionFailure,因为函数doOtherAction(在项目的其他部分中使用)在抛出异常后使用会话。
我想到的第一件事是提取函数doOtherAction的代码,但后来我有相同的代码重复,似乎不是最好的做法。
重构这个的最佳方法是什么?
答案 0 :(得分:0)
在DAO,服务或其他业务逻辑类之上管理一个级别的事务是一种常见做法。这样,基于业务/服务逻辑,您可以在一个案例中在一个事务中执行两个DAO操作,在另一个案例中,在单独的事务中执行它们。
答案 1 :(得分:0)
我是声明式交易管理的忠实粉丝。如果你可以腾出时间让它工作(带有Application Server的小蛋糕,如GlassFish或JBoss,轻松使用Spring)。如果您使用@TransactionAttribute(REQUIRED)
注释您的业务方法(它甚至可以设置为默认设置)并且它调用两个DAO方法,您将得到您想要的:一切都立即提交或回滚到异常。
这个解决方案与它得到的松散耦合一样。
答案 2 :(得分:0)
其他人是正确的,因为他们考虑到目前的常见做法。
但这并不能真正帮助您完成目前的练习。
您应该做的是创建两个新的DAO方法。例如CreateGlobalSession和CommitGlobalSession。
这些与您当前的创建和提交例程的作用相同。
不同之处在于它们设置了一个“全局”会话变量(最有可能最好用ThreadLocal完成)。然后,您更改当前例程,以便检查此全局会话是否已存在。如果您的create检测到全局会话,则只需返回它。如果您的提交检测到全局会话,那么它什么都不做。
现在,当您想要使用它时,您可以这样做:
try {
dao.createGlobalSession();
beanA.save();
beanb.save();
Dao.commitGlobalSession();
} finally {
dao.rollbackGlobalSession();
}
确保将进程包装在try块中,以便在出现错误时重置全局会话。
虽然其他技术被认为是最佳实践,但理想情况下,有一天你可能会发展成类似的东西,这将使你获得超过3种新方法并改变现有方法的优势。之后,其余代码保持不变。