@Transactional
public void schoolProcessing{
//some logic here
save(student); //student is now managed
//Calling update student
updateStudent(student) or updateStudent();
//which of the above is the correct way
}
public void updateStudent(Student student) {
//some student update logic
}
在JPA中从@Transactional方法调用方法时,我们是否应该将托管实体作为参数传递?或者是因为它被标记为@Transactional,JPA无缝处理所有持久性,就好像从@Transactional调用的所有方法都在同一个方法中一样?
澄清一下,上述代码在各方面都与以下相同。
@Transactional
public void schoolProcessing{
//some logic here
save(student); //student is now managed
//some student update logic
}
我认为这是一个基本问题,但已经看到了其他问题,但无法澄清。感谢。
答案 0 :(得分:2)
简短回答:两者都有效
答案很长:
关于@Transactional
和事务传播,有很多细节。以下是大多数开发人员使用的最简单方案的一些信息。
当一个组件/服务/控制器有@Transactional
Spring将它包装在代理(思考装饰器模式)中,这将创建线程本地状态,以容纳交易信息并将其链接到@PersistenceContext
EntityManagers
。当代理完成对@Transactional
方法的调用时,它将提交事务。由于这使用了在@PersistenceContext
方法中使用的任何EntityManager
带注释的@Transactional
的线程本地状态,或者它调用的任何方法,因此即使其他bean中的方法也将共享相同的事务和持久性上下文。
为了更好地理解更新,让我们看一下在JPA中加载实体时会发生什么。当你加载一个实体时,持久化上下文会保存一个副本,当事务提交时,它会遍历所有被管实体并将它们与加载时的副本进行比较,根据它来确定要发送给哪些更新语句。数据库。因此,当您加载实体并对其进行修改时,您不必执行任何操作(除了让事务提交)以更新数据库。当您持久保存新实体时,将其添加到托管实体的内部集合中,如果将实体发送到修改它的方法,只要在事务提交之前进行修改,这也将最终在数据库中,并且实体变得分离。
这只是冰山的顶端,一旦你开始谈论不同的传播类型,手动调用flush或触发预查询刷新的查询,它就会变得相当复杂。根据我的经验,JPA是最被低估的Java技术之一,从表面上看它看起来很简单,但如果你不了解基础知识,你可以花上几天时间来理解/调试你得到的错误。