@Transactional方法调用 - 我们应该将对象作为参数传递吗?

时间:2017-05-02 18:09:49

标签: java spring jpa spring-data-jpa

@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
}

我认为这是一个基本问题,但已经看到了其他问题,但无法澄清。感谢。

1 个答案:

答案 0 :(得分:2)

简短回答:两者都有效

答案很长:

关于@Transactional和事务传播,有很多细节。以下是大多数开发人员使用的最简单方案的一些信息。

当一个组件/服务/控制器有@Transactional Spring将它包装在代理(思考装饰器模式)中,这将创建线程本地状态,以容纳交易信息并将其链接到@PersistenceContext EntityManagers。当代理完成对@Transactional方法的调用时,它将提交事务。由于这使用了在@PersistenceContext方法中使用的任何EntityManager带注释的@Transactional的线程本地状态,或者它调用的任何方法,因此即使其他bean中的方法也将共享相同的事务和持久性上下文。

为了更好地理解更新,让我们看一下在JPA中加载实体时会发生什么。当你加载一个实体时,持久化上下文会保存一个副本,当事务提交时,它会遍历所有被管实体并将它们与加载时的副本进行比较,根据它来确定要发送给哪些更新语句。数据库。因此,当您加载实体并对其进行修改时,您不必执行任何操作(除了让事务提交)以更新数据库。当您持久保存新实体时,将其添加到托管实体的内部集合中,如果将实体发送到修改它的方法,只要在事务提交之前进行修改,这也将最终在数据库中,并且实体变得分离。

这只是冰山的顶端,一旦你开始谈论不同的传播类型,手动调用flush或触发预查询刷新的查询,它就会变得相当复杂。根据我的经验,JPA是最被低估的Java技术之一,从表面上看它看起来很简单,但如果你不了解基础知识,你可以花上几天时间来理解/调试你得到的错误。