对于 Java 应用程序(Spring Boot、Spring Data、Spring Data JPA),我正在建模一个缓慢变化的维度类型 2 数据库表。
我想知道如何以最佳方式设计按键:
我有:
@Id
private String partId;
@Id
private Date validFrom;
private Date validTo;
如果该行有效,validTo 会获取 9999-12-31
。
如果需要创建新行,旧行将终止:validTo
设置为 now
对于新行,validFrom
设置为 now
。
如何确保只有一行 validTo
= 9999-12-31
存在,并且只有一行 validFrom
= 现在
?
如果我这样设计:
@Id
private String partId;
private Date validFrom;
@Id
private Date validTo;
我可能会失去一致性,因为存在多个具有相同 validFrom 日期的终止行。
如果我将两个日期都设置为键的一部分,我会失去更多的一致性控制。
最佳答案
简短回答:JPA 不允许您轻松执行此类检查。您应该直接验证代码中的数据状态,并且仅在确定对该操作感到满意后才发送一些内容供 JPA 插入。
长答案:一般来说,在 JPA 层执行这种验证的机会很少。从设计上来说,JPA 是保存在数据库中的简单数据模型的愚蠢表示。假设当数据到达应用程序的 JPA 层时,它已经通过了业务逻辑层的业务逻辑验证。
本质上,我们想要实现的业务逻辑如下:
For every
partId
, no more than one entry in the table is allowed to exist which has avalidTo
property set to a future time
现在,碰巧的是,您当前的应用程序实现是这样的,将来应该出现的唯一日期是 9999-12-31
,因此我可以看到您可能会如何考虑利用数据库的独特约束来实现业务逻辑的偷工减料版本。这是一个糟糕的主意,原因很简单:这不是数据库约束的用途。
数据库约束的存在是为了帮助数据库发挥其功能:快速、高效、准确地回答您的查询。数据库的工作不是过滤掉违反业务规则的数据输入,而是数据库的工作是过滤掉会阻止数据库正常运行的数据输入。如果您尝试插入重复的主键,这不是不行,因为它破坏了您的业务逻辑,而是不行,因为它破坏了数据库数据模型。您无法将第二个主键插入到数据库表中,原因与您无法将两个独立但相同的键放入 HashMap
中的原因相同,它只是在功能上不起作用。
If a rule doesn't have to do with helping the database be faster and more reliable (i.e. uptime), then it probably doesn't belong on the database
话虽这么说,很多数据库(包括MySql)确实有在数据库层实现业务逻辑的工具。这是因为确实有开发者认为这是一个好地方。没事儿。然而,JPA 并没有公开该功能,因为 JPA 的设计目的是使数据存储尽可能“愚蠢”。如果您想在 JPA 的范围之外实现这样的约束,可以使用触发器等数据库概念来完成。您可以自由地将这些类型的验证实现为数据库触发器,但 JPA 可能不会参与其中。
关于java - MySQL : Define Non Key as Unique per Compound Key,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47843575/