【问题标题】:Spring Data JPA - Why are changes to a returned Entity automatically persisted?Spring Data JPA - 为什么对返回的实体的更改会自动持久化?
【发布时间】:2012-11-15 07:54:49
【问题描述】:

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

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

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) 方法一起使用时,所以我也希望了解如何处理更新的身份。

【问题讨论】:

  • 也许这是旧版本 Spring Data JPA 中的一种行为,在最近的版本中,CrudRepository 的默认实现中的所有读取操作都用 @Transactional(readOnly = true) 注释,这使得它们分离,你需要做 repository.save 以保持更改

标签: spring jpa spring-data-jpa


【解决方案1】:

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

如果您不希望更改持久化,请不要进行更改或回滚事务。

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

【讨论】:

  • 感谢您的 cmets - 他们肯定与办公室的其他意见一致!然而,如果几个 POJO 操作是作为事务的一部分进行的,这种行为会破坏方法的事务性质吗?
  • 为什么会这样?您启动一个事务,对任意数量和种类的实体进行任意数量的修改,然后提交该事务。要么提交所有更改,要么回滚所有更改。方法的事务方面也适用于它调用的每个内部方法:事务上下文被传播。
  • 所以...调用save 方法是不必要的,除非你分离?或者我应该调用其他方法来确保 JPA 关闭事务而不是回滚?
  • @kiedysktos 是的,保存托管实体是没有用的。如何提交事务取决于您的环境(Java EE?Java SE?Spring 管理的事务?)。但是无论您是否调用 save(),都必须提交事务才能使更改真正应用于数据库。
【解决方案2】:

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

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

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

【讨论】:

  • 您如何实现仅针对存储库确定事务范围?
  • @JanZyka 在任何显式事务之外使用存储库。 Spring 将为方法调用打开一个事务。
【解决方案3】:

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

【讨论】:

  • 当您想使用@Transactional 延迟加载实体但不希望任何持久性时,这很有用
猜你喜欢
  • 2014-10-20
  • 1970-01-01
  • 2018-05-01
  • 2020-06-20
  • 2021-05-06
  • 1970-01-01
  • 2020-03-26
  • 1970-01-01
  • 2012-11-08
相关资源
最近更新 更多