spring-data-jpa 使用自定义约束检查实现SpringDataJPAManyToOne关系的最佳方法是什么?

bxgwgixi  于 2022-11-10  发布在  Spring
关注(0)|答案(1)|浏览(73)

我对Spring比较陌生,我希望有人能帮我指明正确的方向。
假设有一个to-do列表应用程序......假设我有一个名为Task的主实体,一个任务可以包含n嵌套子任务(其中每一个是Task并且可以具有n子任务,等等)我认为表示这种类型关系的最佳方式是使用连接表(请参阅下面的高级定义)。此处的主要问题是对父任务/子任务的循环引用。例如,如果TaskA有一个子任务TaskB,而子任务TaskB有一个子任务TaskA
我纳闷:
1.在spring Boot / JPA中是否有一种方法可以定义某种类型的表验证或SQL CHECK CONSTRAINT,以确保一组任务ID不会被两次输入到连接表中?例如,在上面的场景中,如果Set<TaskA, TaskB>已经存在于表中,则会抛出异常。
1.这是表示这种类型的对象关系的最佳方法吗?在给定需求的情况下,有没有更好的方法来使用Spring Data / JPA来实现这一点?
提前感谢!

@Entity
@Table(name = "task")
public class Task {
  ...
}

@Entity
@Table(name = "subtasks")
public class SubTasks {
  ...
  private Task parentTask;
  private Task childTask;
}
nr7wwzry

nr7wwzry1#

您可以在应用程序或数据库中执行此类操作。
对于普通的Java开发人员来说,在应用程序中进行这种操作通常更容易得到在大多数情况下都能正常工作的东西。但是,要得到真正防水的东西真的很难,而要证明它是防水的就更难了,这里我甚至不考虑数学证明。
以下是我看到的选项:
1.在构建实体的过程中,首先要确保你不会有循环依赖。不需要特殊的框架或库支持。只要层次结构发生变化,就遍历它并收集id,确保你不会两次遇到任何id。
1.你可以在保存之前使用Bean Validation来检查循环。你可以使用create custom validators。这两种方法都有一个问题,即当节点在不同的会话中被操作时,可能会创建它们检测不到的循环:两个会话都加载断开连接的节点AB。会话1连接A-〉B。会话2执行相反的操作。两个会话都没有看到循环。由于两个会话都编辑了不同的Task对象,甚至只是创建了新的Task示例,即使是乐观锁定也无济于事。但是,如果更新层次结构中的所有实体,例如,通过让它们包含最顶层父节点的ID,乐观锁定应该防止该问题。
1.您可以在数据库上编写一个触发器,该触发器获取数据库上的独占锁,并执行检查。使用独占锁,任何循环都不可能通过该检查。显然,这会限制并发性。
1.如果您的数据库支持它,您可以创建一个在每次更改时更新的物化视图,并在该视图上定义一个检查约束。使用CONNECT BY子句,应该可以创建一个视图,例如,该视图包含每个条目的最高父级和一个标志(如果发现循环),然后在该列上放置一个检查约束。这可能与前面的变体的行为相同。但是可能比以前的解决方案更容易维护。

相关问题