Java 如何在不丢失封装的情况下进行事务处理?
我有一个代码保存一个bean,并通过Hibernate更新数据库中的另一个bean。它必须在同一事务中执行,因为如果发生错误(f.ex启动异常),则必须对这两个操作执行回滚Java 如何在不丢失封装的情况下进行事务处理?,java,hibernate,transactions,Java,Hibernate,Transactions,我有一个代码保存一个bean,并通过Hibernate更新数据库中的另一个bean。它必须在同一事务中执行,因为如果发生错误(f.ex启动异常),则必须对这两个操作执行回滚 public class BeanDao extends ManagedSession { public Integer save(Bean bean) { Session session = null; try { session = createNewSessionAndTransact
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函数的代码,但是我有相同的代码副本,而且似乎不是这样做的最佳实践
重构的最佳方法是什么?通常在DAO之上的一个级别、服务或其他业务逻辑类中管理事务。这样,基于业务/服务逻辑,在一种情况下,您可以在一个事务中执行两个DAO操作,在另一种情况下,您可以在单独的事务中执行它们。我非常喜欢声明式事务管理。如果你能抽出时间让它工作(用GlassFish或JBoss之类的工具就很容易了,而且使用起来也很简单)。如果您使用
@TransactionAttribute(必需)
注释您的业务方法(甚至可以将其设置为默认值),并且它调用两个DAO方法,您将得到您想要的结果:所有内容都立即提交或回滚到异常。
这个解决方案是松散耦合的。其他解决方案是正确的,因为它们考虑了当前的常见做法 但这并不能真正帮助你目前的做法 您应该做的是创建两个新的DAO方法。例如CreateGlobalSession和CommitGlobalSession 它们所做的与您当前的创建和提交例程相同 区别在于它们设置了一个“全局”会话变量(很可能最好使用ThreadLocal)。然后更改当前例程,以便它们检查此全局会话是否已存在。如果create检测到全局会话,则只需返回它。如果提交检测到全局会话,那么它什么也不做 现在,如果要使用它,请执行以下操作:
try {
dao.createGlobalSession();
beanA.save();
beanb.save();
Dao.commitGlobalSession();
} finally {
dao.rollbackGlobalSession();
}
确保将进程包装在try块中,以便在出现错误时可以重置全局会话
虽然其他技术被认为是最佳实践,理想情况下,有一天你可以发展成类似的技术,但这将使你通过3种新方法和改变两种现有方法度过难关。之后,您的其余代码保持不变。作为一个不得不维护大量使用共享会话/事务(反)模式的代码的人,我可以说,在开发阶段仅仅为了避免一些配置工作和重构而使用它是不明智的。这种解决方案往往会增加维护成本。在某个时刻,有人会忘记提交事务,会话会泄漏,您会在调度作业或集群应用程序等方面遇到问题。从一个完全实用的角度来看,我不是在谈论“理想”的方法,而是“从长远来看,经证明是便宜的”.我只是想修正一下我所说的:共享会话/事务是一种可以快速复制和粘贴到任何地方的变通方法,迟早会成为项目中事务管理的某种标准。请不要制造怪物。@Anthony,当然,但事情是这样的。这种情况只需要实际的交易,这种情况(显然)到目前为止是罕见的。因此,DAO的正常机制仍然存在(当然,它仍然可能泄漏)。然后,如果有人想稍后添加另一个multi-bean事务,他们可能会剪切并粘贴此原始代码,从而保留模式。当然,作为副作用。但是,他也没有提到他的代码是在服务器上,还是在客户机上。要执行您建议的操作,他需要EJB、Spring或其他框架。这对他来说可能不太实际。我明白了,在纯Java SE环境中,我仍然希望重构代码,在DAO构造函数中接收会话,并在业务层使用事务划分代码(见鬼,如果需要,甚至创建一些动态代理)。至少更容易看到事务必须从何处开始和结束)。所以我想说的是,即使你的代码可以在一小时内解决OP的问题,而不是几个小时/天,我仍然推荐Olaf方法。非主题:1+用于hibernate“尝试使用资源”支持:D。