38

我用一个例子来提出这个问题。

断言我们有一个存储库,如下所示:

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来保存更改:

T save(T entity);

是否有人愿意确认从 Spring Data JPA 存储库返回的对象仍然作为标准附加,并解释如何使用 API 标记存储库中的方法,使其仅返回分离的引用?

我想更改实体的状态也可能会在与所述方法一起使用时更改其定义save(T entity),因此我也希望了解如何处理更新的身份。

4

3 回答 3

28

这是 JPA 的基本原则。您使用附加(托管)实体,并且对这些托管实体所做的每次修改都会自动持久化。

如果您不希望您的更改是持久的,那么不要进行更改或回滚事务。

处理分离的实体将是一场噩梦,因为它会阻止延迟加载所有关联。你可以随时调用EntityManager.detach()你的实体,但我真的不会那样做。试着了解它是如何工作的并处理它。好处多于坏处。其中之一是您甚至不必考虑保存复杂业务逻辑可能执行的所有更改,因为这一切都是由 JPA 透明地为您完成的。

于 2012-11-27T17:08:01.480 回答
7

如果您的 Transaction 的范围限定为存储库,则可以使您的存储库返回分离的实体。即,您的事务从进入存储库开始,并在您的代码退出存储库时关闭。

如果你像这样工作,你必须注意一次性加载所有必要的数据,否则你会得到延迟初始化异常。但是在许多情况下,我认为这是可取的,因为它可以让您控制何时以及加载哪些数据,否则在使用 JPA 时很容易从您的手指中溜走。

对于修改,我使用不同的 Transaction 范围,它包含了加载、更改(和隐式持久化)的完整过程。

于 2015-05-22T07:45:40.017 回答
2

我也面临同样的问题。
但对我来说,问题出在自定义存储库实现上,然后我添加了@Transactional(readOnly = true)。

于 2019-02-12T06:01:22.963 回答