对于Java应用程序(Spring Boot,Spring Data,Spring Data JPA),我正在为一个缓慢变化的维度类型2数据库表建模。
我想知道如何以最佳方式设计密钥:
我有:
@Id
private String partId;
@Id
private Date validFrom;
private Date validTo;
如果行有效,则获取9999-12-31
。
如果需要创建新行,旧行将被终止:validTo
设置为now
对于新行,validFrom
设置为now
。
如何确保validTo
= 9999-12-31
只有一行,validFrom
= now
只有一行?
如果我这样设计:
@Id
private String partId;
private Date validFrom;
@Id
private Date validTo;
我可能会失去一致性,因为存在多个具有相同validFrom日期的已终止行。
如果我将两个日期分配给密钥的某些部分,我会失去更多的一致性控制。
答案 0 :(得分:0)
简答:JPA不允许您轻松执行此类检查。您应该直接验证代码中的数据是否存在,并且只有在确定您对该操作感到满意时才发送一些内容供JPA插入。
长答案:一般来说,在JPA层执行此类验证的机会很少。根据设计,JPA是在数据库中持久保存的简单数据模型的愚蠢表示。假设在数据到达应用程序的JPA层时,它已经在业务逻辑层传递了业务逻辑验证。
基本上,我们要实现的业务逻辑如下:
对于每个
partId
,表中只允许存在一个条目 将validTo
属性设置为将来的时间
现在,恰好是你的应用程序的当前实现是这样的,以后唯一应该出现的日期是9999-12-31
,因此我可以看到你如何考虑利用它数据库的唯一约束,以实现业务逻辑的简化版本。出于一个简单的原因,这是一个糟糕的想法:这不是数据库约束的用途。
存在数据库约束以帮助数据库提供其功能:快速,高效且准确地回答您的查询。筛选出破坏业务规则的数据输入不是数据库工作,只有数据库作业才能过滤掉阻止数据库正常运行的数据输入。如果您尝试插入重复的主键,这不是禁止的,因为它会破坏您的业务逻辑,这是不可行的,因为它会破坏数据库数据模型。您不能将第二个主键插入数据库表中,原因与您无法将两个单独但相同的键放入HashMap
的原因相同,它在功能上并不像那样工作。
如果规则与帮助数据库更快并且没有关系 更可靠(即正常运行时间),然后它可能不属于 数据库
话虽这么说,许多数据库(包括MySql)确实拥有在数据库层实现业务逻辑的工具。这是因为确实有开发人员认为它是一个好地方。那样就好。但是,JPA并未公开该功能,因为JPA旨在使数据存储尽可能“愚蠢”。如果你想在JPA的范围之外实现这样的约束,可以使用像触发器这样的数据库概念来完成。您可以自由地将这些类型的验证实现为DB触发器,但JPA可能不会参与其中。