如何 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,它都运行良好,但数据库提交直到控制方法完成才完成,这显然不是我想要的。
所以,我有几个问题:
- 如何使休眠会话与我的事务范围保持一致?
- 使用 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());
}
}
最新 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,它都运行良好,但数据库提交直到控制方法完成才完成,这显然不是我想要的。
所以,我有几个问题:
- 如何使休眠会话与我的事务范围保持一致?
- 使用 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());
}
}