如何 link 具有单个数据库事务的 JPA 持久性上下文

How to link JPA persistence context with single database transaction

最新 Spring 使用 JPA 和 Hibernate 启动:我正在努力理解事务、持久性上下文和 Hibernate 会话之间的关系,而且我无法轻易避免可怕的无会话延迟初始化问题。

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

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
}

但是,我遇到了一个问题,因为(我认为)两个事务正在使用同一个休眠会话。当我在第二个事务中调用 entityRepository.getOne(id) 时,我可以在调试器中看到我返回的对象与第一个事务中 findAll() 返回的对象完全相同,没有数据库访问权限。如果我理解正确的话,是休眠缓存在做这个吗?如果我随后在我的对象上调用一个需要惰性评估的方法,我会收到 "no session" 错误。我以为缓存和会话是链接的,所以这是我的第一个困惑。

如果我删除所有@Transactional 注释或者如果我在控制方法上放置一个@Transactional,它都运行良好,但数据库提交直到控制方法完成才完成,这显然不是我想要的。

所以,我有几个问题:

  1. 如何使休眠会话与我的事务范围保持一致?
  2. 使用 JPA 和声明式事务管理在循环中执行分离事务的良好模式是什么?

我想保留声明式风格(即没有 xml),并且不想做任何特定于 Hibernate 的事情。

感谢任何帮助!

谢谢

马库斯

Spring 围绕您的服务 class 创建一个代理,这意味着 @Transactional 注释仅在通过代理调用带注释的方法时应用(您已注入此服务)。

您正在从 control() 中调用 getEntitiesToProcess()processEntity(),这意味着这些调用不通过代理,而是具有 control() 方法的事务范围(如果您还没有从同一 class 中的另一个方法调用 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());
    }
}