JPA:嵌套事务方法未回滚

时间:2016-06-16 14:02:35

标签: spring hibernate jpa jta

UPD 1:经过进一步研究,我认为以下信息可能有用:

  • 我通过WildFly 9.0.2上的JNDI查找获取数据源,然后' wrap'例如HikariDataSource(例如return new HikariDataSource(jndiDSLookup(dsName)))。
  • 最终使用的事务管理器是JTATransactionManager
  • 我没有以任何方式配置事务管理器。

原始问题:

我遇到了JPA / Hibernate和(可能)Spring-Boot的问题,即使调用了调用方法中的更改,也会提交从另一个类的事务方法调用的一个类的事务方法中引入的数据库更改回来(因为他们应该)。

以下是我的交易服务

StuffService

@Service
@Transactional(rollbackFor = IOException.class)
public class StuffService {

    @Inject private BarService barService;
    @Inject private StuffRepository stuffRepository;

    public Stuff updateStuff(Stuff stuff) {

        try {
            if (null != barService.doBar(stuff)) {
                stuff.setSomething(SOMETHING);
                stuff.setSomethingElse(SOMETHING_ELSE);
                return stuffRepository.save(stuff);
            }
        } catch (FirstCustomException e) {
            logger.error("Blah", e);
            throw new SecondCustomException(e.getMessage());
        }

        throw new SecondCustomException("Blah 2");
    }

    // other methods
}

BarService

@Service
@Transactional
public class BarService {

    @Inject private EntityARepository entityARepository;
    @Inject private EntityBRepository entityBRepository;

    /* 
     * updates existing entity A and persists new entity B. 
     */
    public EntityA doBar(Stuff stuff) throws FirstCustomException {

        EntityA a = entityARepository.findOne(/* some criteria */);
        a.setSomething(SOMETHING);

        EntityB b = new EntityB();
        b.setSomething(SOMETHING);
        b.setSomethingElse(SOMETHING_ELSE);

        entityBRepository.save(b);
        return entityARepository.save(a);
    }

// other methods
}

EntityARepositoryEntityBRepository是非常相似的Spring-Boot存储库,定义如下:

public interface EntityARepository extends JpaRepository<EntityA, Long>{

    EntityA findOne(/* some criteria */);
}

FirstCustomException延伸Throwable

SecondCustomException延伸RuntimeException

Stuff实体已版本化,并且每隔一段时间由StuffService.updateStuff()同时更新。在这种情况下,对stuff个实例之一的更改将按预期回滚,但barService.doBar()中发生的所有内容最终都会被提交。

由于两种方法上的事务传播应该是REQUIRED(默认值),并且两种方法属于不同的类,因此@Transactional应适用于两者。

我确实看到了Transaction is not completely rolled back after server throws OptimisticLockException 1

但它并没有真正回答我的问题。

有谁能请让我知道发生了什么?

谢谢。

1 个答案:

答案 0 :(得分:0)

这不是'嵌套'事务 - 这些服务在完全独立的事务中运行。如果您希望回滚一个影响另一个,则需要让它们参与同一个事务而不是自己创建。

或者,如果您的问题是传入doBar方法的'stuff'版本存在问题并且您希望验证它,那么您将需要对可能导致乐观锁定检查的stuff实例执行某些操作,并且如果它是陈旧的,那么会导致异常。见EntityManager.lock