Java 为什么在hibernate中不鼓励使用复合键?

Java 为什么在hibernate中不鼓励使用复合键?,java,database,hibernate,orm,composite-key,Java,Database,Hibernate,Orm,Composite Key,这是来自: 还有一种替代的声明,允许使用复合键访问遗留数据。强烈反对将其用于任何其他用途 为什么不鼓励使用复合键?我正在考虑使用一个3列表,其中所有列都是外键,共同构成一个主键,这在我的模型中是一个有意义的关系。我不明白为什么这是一个坏主意,特别是我将对它们使用索引 替代方案是什么?创建其他自动生成的列并将其用作主键?我仍然需要查询我的3列 简言之,为什么这一说法是正确的?还有什么更好的选择呢?他们出于以下几个原因不鼓励他们: 它们使用起来很麻烦。每次需要引用对象(或行)时,例如web应用程序

这是来自:

还有一种替代的
声明,允许使用复合键访问遗留数据。强烈反对将其用于任何其他用途

为什么不鼓励使用复合键?我正在考虑使用一个3列表,其中所有列都是外键,共同构成一个主键,这在我的模型中是一个有意义的关系。我不明白为什么这是一个坏主意,特别是我将对它们使用索引

替代方案是什么?创建其他自动生成的列并将其用作主键?我仍然需要查询我的3列


简言之,为什么这一说法是正确的?还有什么更好的选择呢?

他们出于以下几个原因不鼓励他们:

  • 它们使用起来很麻烦。每次需要引用对象(或行)时,例如web应用程序中的eexample,都需要传递3个参数,而不仅仅是一个参数
  • 他们效率低下。数据库需要散列一个由3列组成的组合,而不是简单地散列一个整数
  • 它们会导致错误:开发人员不可避免地错误地实现主键类的equals和hashCode方法。或者使其可变,并在存储在HashSet或HashMap中后修改其值
  • 它们污染了模式。如果另一个表需要引用此3列表,则它需要有3列而不是一列作为外键。现在假设您遵循相同的设计,并将此3列外键作为此新表的主键的一部分,您将很快拥有一个4列主键,然后在下一个表中拥有一个5列主键,以此类推,从而导致数据重复和脏模式

另一种选择是,除了其他三列之外,还有一列自动生成的主键。如果要使三列的元组唯一,则使用唯一的约束。

< P>我会从设计的角度考虑这个问题。不仅仅是Hibernate认为它们是好是坏。真正的问题是:自然键是我的数据的好标识符吗

在您的业务模型中,现在可以方便地通过记录的一些数据来识别记录,但业务模型会随着时间的推移而变化。当这种情况发生时,您会发现您的自然密钥不再适合唯一地标识您的数据。由于其他表中的引用完整性,这将使事情更难更改

拥有代理PK很方便,因为它不会将存储中的数据标识方式与业务模型结构联系起来

自然密钥不能从序列中生成,并且不能通过其数据识别的数据的情况更为常见。这是自然密钥不同于存储密钥的证据,不能将其视为通用(良好)方法

使用代理键简化了应用程序和数据库的设计。它们更易于使用,性能更高,工作也更出色

自然键只带来缺点:我想不出使用自然键有什么好处


也就是说,我认为hibernate在自然(合成)键方面没有真正的问题。但是您有时可能会发现一些问题(或bug),文档或试图获得帮助时也会遇到问题,因为hibernate社区广泛承认代理键的好处。因此,为您为什么选择复合键准备一个好的答案。

即使现在回答您的问题可能已经太晚了,我想在这里就Hibernate使用代理键的必要性(这真的是一个建议吗?)给出另一个观点(我希望更温和)

首先,我想明确一个事实,代理键(人工自动生成的键)和自然键(由具有域含义的列组成)都有优点缺点。我并不是说一种键类型比另一种更好。我想说的是,根据您的需求,自然键可能是比代理键更好的选择,反之亦然

关于自然钥匙的神话
  • 复合键的效率低于代理键。不它取决于所使用的数据库引擎:
  • 现实生活中不存在自然键。对不起,它们确实存在!例如,在航空行业中,对于给定的计划航班(航空公司、出发日期、航班号、后缀),以下元组始终是唯一的。更一般地说,当给定的标准保证一组业务数据是唯一的时,那么这组数据就是一个[好的]自然的关键候选数据
  • 自然键“污染了子表的模式”。对我来说,这更多的是一种感觉,而不是一个真正的问题。拥有4列主键(每个主键2字节)可能比一列主键11字节更有效。此外,这4列可用于直接查询子表(通过使用where子句中的4列),而无需连接到父表 代理键的缺点 代理键包括:

  • 性能问题的来源:
    • 它们通常使用自动递增的列来实现,这意味着:
      • 每次您想要获得一个新Id时,都要往返数据库(我知道这可以通过使用缓存或类似[seq]hilo的算法来改进,但这些方法仍有其自身的缺点)
      • 如果有一天您需要将数据从一个模式移动到另一个模式(至少在我的公司是这样),那么您可能会遇到Id冲突问题。是的,我知道您可以使用UUID,但这些UUID需要32位十六进制数字!(如果您关心数据库大小,那么这可能是一个问题)
      • 如果您对所有代理项密钥使用一个序列,那么-当然-您将在数据库上产生争用<