如何将JPA持久性上下文与单个数据库事务

时间:2016-01-06 11:03:43

标签: spring hibernate jpa transactions spring-data-jpa

使用JPA和Hibernate的最新Spring Boot:我很难理解事务,持久化上下文和休眠会话之间的关系,我无法轻易避免可怕的无会话延迟初始化问题。

我在一个事务中更新了一组对象,然后我想循环遍历那些在一个单独的事务中处理它们的对象 - 看起来很简单。

public void control() {
    List<> entities = getEntitiesToProcess();
    for (Entity entity : entities) {
        processEntity(entity.getId());
    }
}

@Transactional(value=TxType.REQUIRES_NEW)
public List<Entity> getEntitiesToProcess() {
    List<Entity> entities = entityRepository.findAll();
    for (Entity entity : entities) {
        // Update a few properties
    }
    return entities;
}

@Transactional(value=TxType.REQUIRES_NEW)
public void processEntity(String id) {
    Entity entity = entityRepository.getOne(id);
    entity.getLazyInitialisedListOfObjects(); // throws LazyInitializationException: could not initialize proxy - no Session
}

然而,我遇到了一个问题,因为(我认为)两个事务都使用了相同的hibernate会话。当我在第二个事务中调用entityRepository.getOne(id)时,我可以在调试器中看到我返回的是与没有数据库访问的第一个事务中的findAll()返回的完全相同的对象。如果我理解正确,那么hibernate缓存是这样做的吗?如果我然后在我的对象上调用一个需要进行惰性求值的方法,我会得到一个&#34; no session&#34;错误。我认为缓存和会话是相互关联的,这是我的第一次困惑。

如果我删除了所有的@Transactional注释,或者如果我在控制方法上放置@Transactional,那么一切运行正常,但是数据库提交都没有完成,直到控制方法完成,这显然不是我想要的。

所以,我有几个问题:

  1. 如何让hibernate会话与我的事务范围保持一致?
  2. 使用JPA和声明式事务管理在循环中执行分离事务的好模式是什么?
  3. 我想保留声明式样式(即没有xml),并且不想做任何特定的Hibernate。

    任何帮助表示赞赏!

    由于

    马库斯

1 个答案:

答案 0 :(得分:1)

Spring在您的服务类周围创建一个代理,这意味着只有在通过代理调用带注释的方法时(注入此服务的地方)才会应用@Transactional注释。

您正在getEntitiesToProcess()内拨打processEntity()control(),这意味着这些调用不是通过代理,而是具有control()方法的事务范围(如果你也没有从同一个类的另一个方法调用control()。)

要申请@Transactional,您需要执行类似的操作

@Autowired
private ApplicationContext applicationContext;

public void control() {
    MyService myService = applicationContext.getBean(MyService.class);
    List<> entities = myService.getEntitiesToProcess();
    for (Entity entity : entities) {
        myService.processEntity(entity.getId());
    }
}