Hibernate / JPA:如果@Transactional失败,是否会回滚嵌套刷新?

时间:2013-11-05 10:47:07

标签: java hibernate jpa transactions rollback

假设我的某个地方有注释@Transactional(因此启动了一个事务)并在里面做了几个saveAndFlush()。也许我甚至调用一些依赖项,该依赖项具有一个方法,通过注释@Transactional来启动它自己的(sub?nested?)事务。如果事务在两者之间的某个地方失败,那么会回滚什么?

一些例子:

public class ComplexProcess {
    @Inject
    private DAO<SomeEntity> someEntityDao;

    @Inject
    private SomeManagerClass manager;

    @Transactional
    public void doStuff(SomeEntity entity) {
        manager.createAnObjectDependingOnEntity(entity);
        entity = someEntityDao.saveAndFlush(entity); // what if this fails?
        manager.doMoreStuffDependingOnEntity(entity);
    }
}

public class SomeManagerClass {

    @Inject
    private DAO<SomeObject> someObjectDao;

    @Inject
    private DAO<SomeOtherEntity> someOtherEntityDao;

    // what if this fails?
    @Transactional // what if this isn't there?
    public void createAnObjectDependingOnEntity(SomeEntity entity) {
        SomeObject someObject = createSomeObjectDependingOnEntity(entity);
        someObjectDao.saveAndFlush(someObject);
    }

    // what if this fails?
    @Transactional // what if this isn't there?
    public void doMoreStuffDependingOnEntity(SomeEntity entity) {
        SomeOtherEntity someOtherEntity = whatever(entity);
        someOtherEntityDao.safeAndFlush(someOtherEntity);
    }
}

再说一遍:如果说最后一步失败了,那么hibernate还会回滚doStuff()之前发生的所有事情吗?因为我有一种感觉它没有。如果由于saveAndFlush()而无法完成此完全回滚,那么只使用save()并在事务结束时等待自动刷新帮助吗?我刚刚读到,即使在离开@Transactional块之前,hibernate也会在它们之间进行一些无法控制的刷新?!

2 个答案:

答案 0 :(得分:7)

  • 刷新不应影响所有的交易管理。当回滚事务时,将回滚对该事务中对数据库状态所做的所有更改(即,由Hibernate刷新的更改)。

  • @Transactional的默认传播政策为PROPAGATION_REQUIRED。这意味着您可以安全地从其他@Transactional方法调用@Transactional方法,并且它们将使用由顶级事务方法创建的相同事务。如果您明确提供不同的传播设置,情况并非如此。

因此,这意味着在执行顶级@Transactional方法期间发生的任何失败(即从该方法抛出的任何异常)都应该导致回滚,并且在这种情况下应该回滚所有更改。

如果您观察到不同的行为,可能是某些内容配置错误(例如,顶级@Transactional因某种原因无法生效)。尝试在测试中重现此行为。

答案 1 :(得分:1)

使用您的代码,Hibernate所做的所有更改都应该回滚,如果某个地方决定回滚当前事务。当然,只有一切都正确配置。

一些常见的配置问题是: 您的persistence.xml应该定义JTA持久性单元(而不是RESOURCE_LOCAL),并且您的数据库/表应该支持事务(例如,MySQL表应该与InnoDb搜索引擎一起使用)。