【问题标题】:Spring Data JPA: save list of parents where children have been moved between parents in one transactionSpring Data JPA:保存在一次事务中在父母之间移动孩子的父母列表
【发布时间】:2019-09-30 05:02:39
【问题描述】:

我有一个父母列表,其中每个一对多父母都有一个多对一孩子的列表。孤儿删除已开启,并且关系是惰性的。

我在 Hibernate 中使用 JpaRepository

我需要在父母之间移动孩子并在单个事务中保存所有更改。

如果我加载父母列表,在他们之间移动孩子(通过更新关系的双方)并在循环中一个一个地保存列表中的人,这样每个人都可以保存在自己的列表中,它工作正常交易。

但是当我将循环放入一个带有@Transactional 注释的方法中,以便将整个保存过程保持在一个回滚的总体事务中时,如果其中一个保存调用失败,孩子们将 有时没有正确存储。

当我在单独的事务中逐一保存时,如果子行已从另一个父级移动到当前正在保存的父级,Hibernate 会简单地更新子行,但删除并重新插入 如果它已从当前正在保存的父级中删除,则为子级。我可以在 SQL 日志中看到这一点。

当我保存在单个事务中时,这似乎失败了:一些孩子没有正确移动,而是丢失了。

我也尝试使用saveAll(),而不是在@Transactional方法中循环,同样的效果。

不支持在父母之间移动孩子并在单个事务中保存所有父母的情况吗?

【问题讨论】:

  • this seems to fail 是什么错误?我认为问题在于,当您在父母之间交换孩子时,大交易中会发生一些冲突。我不是 100% 确定你有一个事务,是有循环的方法,它也用@Transaction 注释吗?否则,您将不会有单笔交易仅供参考
  • 我已经更新了问题:失败是一些孩子迷路了。我有一个 junit 测试,它调用服务 bean 上的一个方法,该方法使用CrudRepository.save(List<Parent> parents) 保存在一个循环中,并用@Transactional 进行注释。
  • 当您更改父级时,您是否同时更新 child.setParent()parent.setChild() ?您的问题非常广泛,您可以尝试测试用例并尝试找到一个有问题的小例子吗?就像当父母A和父母B交换孩子时,父母B没有孩子一样?
  • 是的,这就是我所说的“我更新关系的双方”的意思。我将尝试提取一个干净的测试用例。感谢您的快速回复。

标签: hibernate jpa spring-data-jpa


【解决方案1】:

严格来说,这不是您要查找的内容,但一个选项可能是不重用子实体,而是分配它们的副本。

在每个源父级上,您将删除要移动的子级,然后将其副本添加到目标实体。

然后,您应该能够在以这种方式更改的父实体列表上调用 CrudRepository#saveAll() 并获得预期的结果。

需要注意的是,已移动子项的 id 将在数据库中更改,因为它们将被删除然后重新插入。该解决方案在性能方面并不是最佳的,因为您将在 DB 和 Java 级别上做更多的工作。

【讨论】:

  • 这解决了任务,但可能会导致相当多的数据库流量,因为需要删除并重新插入子项及其子项。如果没有人有更好的解决方案,我会接受答案。
  • 另一个警告:hibernate 在删除原始子项之前将子项作为重复项插入,即子项不能具有需要在相应表中唯一的域属性。
猜你喜欢
  • 1970-01-01
  • 2012-10-16
  • 2014-10-27
  • 2018-01-15
  • 1970-01-01
  • 1970-01-01
  • 2023-03-14
  • 1970-01-01
  • 2021-12-05
相关资源
最近更新 更多