为什么复合键在hibernate时不鼓励?

这是从Hibernate官方教程 :

有一个替代的<composite-id>声明允许用复合键访问遗留数据。 它的用途是强烈的劝阻别的。

为什么复合键不鼓励? 我正在考虑使用3列表,其中所有的列都是外键,并在我的模型中一起形成一个有意义的关系的主键。 我不明白为什么这是一个不好的主意,我很明显会对他们使用索引。

有什么select? 创build一个额外的自动生成的列,并将其用作主键? 反正我仍然需要查询我的3列!

总之,为什么这个陈述是真实的? 还有什么更好的select?

他们劝阻他们有几个原因:

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

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

即使是 – 也许 – 回答你的问题已经太迟了,我想在这里给出另一个观点(更温和的我希望)的需求(是真正的build议?)hibernate使用代理键。

首先 ,我想明确的是,代理键(人工自动生成的)和自然键(由具有域意义的列组成)具有优点缺点 。 我并不是说一种关键types比另一种更好。 我想说,根据您的要求,自然键可能是比替代品更好的select,反之亦然。

神话在自然钥匙

  1. 复合键效率低于代理键。 没有! 这取决于使用的数据库引擎:
    • 神谕
    • MySQL的
  2. 自然键不存在于现实生活中。 对不起,但他们确实存在! 例如,在航空工业中,对于给定的预定航class(航空公司,出发date,航class号,运营单位),以下元组将始终是唯一的。 更一般地说,当一组商业数据被保证是唯一的一个给定的标准,那么这组数据是一个[良好]自然的关键人选。
  3. 自然键“污染子表”的模式。 对我来说,这是一种感觉,而不是一个真正的问题。 具有每个2字节的4列主键可能比单个11字节的列更有效。 此外,可以使用4列直接查询子表(通过使用where子句中的4列)而无需连接到父表。

代理键的缺点

代理键是:

  1. 性能问题的根源:
    • 它们通常使用自动递增的列来实现,这意味着:
      • 每次你想得到一个新的数据库往返数据库(我知道这可以改进使用caching或hilo类似的algorithm,但仍然这些方法有自己的缺点)。
      • 如果有一天你需要将数据从一个模式转移到另一个模式(至less在我的公司经常发生),那么你可能会遇到Id冲突问题。 是的,我知道你可以使用UUID,但最后需要32个hex数字! (如果你关心数据库的大小,那么这可能是一个问题)。
      • 如果你对所有代理键都使用了一个序列,那么 – 当然 – 你最终会争夺你的数据库。
  2. 容易出错。 一个序列有一个max_value的限制,所以作为一个开发者,你必须注意以下事实:
    • 你必须循环你的序列(当达到最大值时,它会回到1,2,…)。
    • 如果您将序列用作数据的sorting(随着时间的推移),那么您必须处理循环的情况(Id 1的列可能比Id最大值 – 1的行更新)。
    • 确保你的代码(甚至你的客户端接口不应该发生,因为它应该是一个内部ID)支持你用来存储序列值的32b / 64b整数。
  3. 他们不保证没有重复的数据。 你可以总是有2行,所有相同的列值,但具有不同的生成值。 对我来说,这是从数据库devise的angular度来看代理键的问题。
  4. 更多维基百科…

为什么Hibernate喜欢/需要代理键?

Java Persistence with Hibernate引用中所述:

更有经验的Hibernate用户专门使用saveOrUpdate(); 让Hibernate决定什么是新的和什么是旧的,特别是在一个更复杂的混合状态的对象networking中更容易。 saveOrUpdate()唯一的(不是真正的严重的)缺点是它有时候不能猜测一个实例是旧的还是新的,而没有在数据库中触发一个SELECT,例如,当一个类使用自然复合键映射时,没有版本或时间戳记属性。

可以在这里find限制的一些performanceforms(我想我们应该这样称呼它)。

结论

请不要太看重你的意见。 使用自然键时,如果使用自然键,使用代理键时更好。

希望这有助于某人!

我会从deviseangular度考虑这个问题。 这不仅仅是Hibernate认为它们的好坏。 真正的问题是: 自然键是否是我的数据的良好标识符?

在您的商业模式中,今天可以方便地通过其中的一些数据来识别logging,但商业模式会及时演变。 发生这种情况时,您会发现您的自然密钥不再适合唯一标识您的数据。 而在其他表中参照完整性,这将使事情变得更加困难。

有一个代理PK是方便的,因为它不链式如何在您的存储中识别您的数据您的业​​务模型结构

自然键不能从一个序列中产生,并且不能由其数据识别的数据的情况频繁得多 。 这是一个证据,certificate自然键与存储键不同,不能把它看作是一个普遍的(好的)方法。

使用代理键简化了应用程序和数据库的devise。 他们更容易使用,更高性能,做一个完美的工作。

自然键带来的只是缺点:我不能想到使用自然键的单一优势。

这就是说,我认为冬眠与自然(组合)键没有真正的问题。 但是,有时候你可能会发现一些问题(或错误),并且遇到文档问题或者试图获得帮助,因为hibernate社区广泛地承认了代理键的好处。 所以,准备一个很好的答案, 为什么你select了一个复合键

使用数据库作为工具开发的应用程序肯定更有利于保持代理键的工作stream,使用聚簇索引进行查询优化。

数据仓库和OLAP风格的系统需要特别小心,然而,它们利用大量的事实表来将尺寸的代理键连接在一起。 在这种情况下,数据决定了可用于维护logging的仪表板/应用程序。

因此,对于另一种方法而言,而不是一种方法比另一种方法更可取,或许对另一种方法是有利的:对于关键构造,您将不会非常容易地开发Hibernate应用程序来直接访问SSAS系统实例。

我开发使用这两种关键混合物,并觉得实施一个坚实的星形或雪花模式与聚集索引代理人通常是我的第一select。

所以,对于OP和其他人来说,如果你想保持db与你的开发(Hibernate专门研究)不变 – 使用代理方法,当数据读取趋于减慢,或者你注意到某些查询消耗性能,恢复到您的特定数据库,并添加优化查询顺序的复合聚集索引。

如果正确理解Hibernate文档:

“有一个替代的<composite-id>声明允许使用复合键访问遗留数据,强烈build议不要使用它。

关于主题5.1.4。 id tag xml <id>它使得主键映射做得太快,我们可以得出结论,hibernate文档不鼓励使用<composite-id>而不是<id>标签来进行复合主键映射,使用复合主键。