使用Spring(MVC,Batch和persistence)我定义了以下接口:
public interface JobStatusService {
@Transactional(readOnly = false)
@Modifying
JobStatus save(JobStatus status);
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
Optional<JobStatus> get(ResultsIdentifier identifier);
}
请注意REQUIRES_NEW
,因为它是破碎的方法。
此接口在以下位置实现:
@Override
public JobStatus save(JobStatus status) {
if (status.getUserId() == null) {
status.setUserId(userService.getCurrentUser());
}
status.setLastUpdateTime(new Date());
return repository.save(status);
}
@Override
public Optional<JobStatus> get(ResultsIdentifier identifier) {
return repository.findByJobIdentifier(identifier);
}
其中repository是JPA存储库,其中包含以下内容:
public interface JobStatusRepository extends Repository<JobStatus, ResultsIdentifier> {
JobStatus save(JobStatus status);
Optional<JobStatus> findByJobIdentifier(ResultsIdentifier id);
}
ResultsIdentifier
是字符串代码和ID号的简单复合ID类。
在其他地方,我有一个批处理Writer通过将JobStatus写入存储库来完成,以及一个Web Controller类,它运行一个包含对作业状态服务的查询的循环。 save()
操作似乎正确执行,get()
操作第一次正确 。
但是,如果循环的第一次运行调用get()
并且JobStatus不是“完成”,则在所有后续运行中仍不是“完成”。事实上,同样的确切对象是从Hibernate(这是我的持久性工具)回来的。发生的事情是SessionImpl
/ StatefulPersistenceContext
中的会话缓存保留了它的副本并始终返回而不是进行真正的数据库查询。所以,我想,propagation = Propagation.REQUIRES_NEW
应该始终开始一个新的事务/会话,对吧?但是,无论我是否在注释中包含它,都会再次出现同样的问题。
会话和交易的生命周期在这里不是一致的吗?如果没有,我怎么能告诉Spring我想要开始一个新的会话?我试图避免更改我的XML配置以将Hibernate会话工厂推入JobStatusService实现并手动clear()
它,因为系统的其他任何部分都没有直接看到Hibernate。
我也很高兴听到有关调试会话相关内容的任何建议,因为在我的代码中它只是一个神奇的注释。
我最终通过在特定实体定义上设置fetch到EAGER来“解决”这个问题。这似乎不应该起作用,所以我放入this question来询问可能发生的事情。