我以一个例子提出问题。
断言我们有一个存储库,如下所示:
public interface ExampleObjectRepository extends CrudRepository<ExampleObject, Long> {
}
通过扩展JpaRepository
接口,ExampleObject
存储库继承了以下方法:
T findOne(ID id);
现在,我观察到,如果在调用此方法后收到对ExampleObject的引用,我对此方法所做的任何操作都会自动保存到数据库中,例如:
ExampleObject pointInCase = exampleObjectRepository.findOne(1L);
pointInCase.setName("Something else");
阅读主题,我理解这标志着ExampleObject
实例是not detached
。
这违背了我的期望。我原以为我需要使用从CrudRepository
继承的save方法来保存更改:
T save(T entity);
是否有人能够确认从Spring Data JPA Repository返回的对象仍然作为标准附加,并解释如何使用API在存储库中标记方法,使其仅返回分离的引用?
我认为更改实体的状态也可能会在使用所述save(T entity)
方法时更改其定义,因此我还要理解如何处理更新的标识。
答案 0 :(得分:18)
这是JPA的基本原则。您使用附加(托管)实体,并且对这些托管实体所做的每个修改都会自动保持持久性。
如果您不希望您的更改是持久的,则不要进行更改或回滚事务。
处理分离的实体将是一场噩梦,因为它会阻止延迟加载所有关联。您可以随时在您的实体上调用EntityManager.detach()
,但我真的不会这样做。试着了解它是如何工作的并处理它。有许多好处而不是缺点。其中之一就是你甚至不必考虑保存复杂业务逻辑可能会做的所有更改,因为这一切都是由JPA透明地完成的。
答案 1 :(得分:5)
如果您的Transaction限定为存储库,则可以使Repository返回已分离的实体。即您的事务从进入存储库开始,并在代码退出存储库时关闭。
如果你这样工作,你必须要注意一次性加载所有必要的数据,否则你将得到延迟初始化异常。但在许多情况下,我认为这是可取的,因为它可以让您在何时以及加载了什么数据时对其进行控制,否则在使用JPA时会轻易滑过手指。
对于修改,我使用不同的事务范围,它包装了加载,更改(以及隐式持久)的完整过程。
答案 2 :(得分:1)
我也遇到了同样的问题。
但是对我来说,问题出在自定义存储库实现上,然后我添加了@Transactional(readOnly = true)。