MySQL:将非密钥定义为每个复合密钥唯一

时间:2017-12-16 07:35:05

标签: java jpa spring-data-jpa data-warehouse business-intelligence

对于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日期的已终止行。

如果我将两个日期分配给密钥的某些部分,我会失去更多的一致性控制。

1 个答案:

答案 0 :(得分:0)

简答:JPA不允许您轻松执行此类检查。您应该直接验证代码中的数据是否存在,并且只有在确定您对该操作感到满意时才发送一些内容供JPA插入。

长答案:一般来说,在JPA层执行此类验证的机会很少。根据设计,JPA是在数据库中持久保存的简单数据模型的愚蠢表示。假设在数据到达应用程序的JPA层时,它已经在业务逻辑层传递了业务逻辑验证。

基本上,我们要实现的业务逻辑如下:

  

对于每个partId,表中只允许存在一个条目   将validTo属性设置为将来的时间

现在,恰好是你的应用程序的当前实现是这样的,以后唯一应该出现的日期是9999-12-31,因此我可以看到你如何考虑利用它数据库的唯一约束,以实现业务逻辑的简化版本。出于一个简单的原因,这是一个糟糕的想法:这不是数据库约束的用途。

存在数据库约束以帮助数据库提供其功能:快速,高效且准确地回答您的查询。筛选出破坏业务规则的数据输入不是数据库工作,只有数据库作业才能过滤掉阻止数据库正常运行的数据输入。如果您尝试插入重复的主键,这不是禁止的,因为它会破坏您的业务逻辑,这是不可行的,因为它会破坏数据库数据模型。您不能将第二个主键插入数据库表中,原因与您无法将两个单独但相同的键放入HashMap的原因相同,它在功能上并不像那样工作。

  

如果规则与帮助数据库更快并且没有关系   更可靠(即正常运行时间),然后它可能不属于   数据库

话虽这么说,许多数据库(包括MySql)确实拥有在数据库层实现业务逻辑的工具。这是因为确实有开发人员认为它是一个好地方。那样就好。但是,JPA并未公开该功能,因为JPA旨在使数据存储尽可能“愚蠢”。如果你想在JPA的范围之外实现这样的约束,可以使用像触发器这样的数据库概念来完成。您可以自由地将这些类型的验证实现为DB触发器,但JPA可能不会参与其中。