通过在实体持久保存到数据库之前为实体分配ID,但是在构造函数中立即获得了很大的价值:你的equals / hashcode实现变得微不足道,and it saves many headaches。
当实体相等性基于==
时,我遇到了问题:代理进入会话,当它作为真实对象被解包时,你得到equals()
返回false
当您覆盖equals
和hashcode
以使用生成的ID时,因为该ID仅在persist()
上生成,所有非持久化实体都具有ID null
和因此彼此都是一样的。
从我读到的内容来看,当你使用传统的ID生成技术(自动增量让我们说)时,在刷新实体管理器时会生成ID。当您使用基于序列的解决方案时,它会在持续时间生成。
那篇文章和我目前的理解说最简单的解决方案是在创建时分配ID,而不是持久或刷新时间。并且序列似乎可以到达,但JPA决定反对它。通过序列获取ID是便宜的(因为你可以预取),为什么JPA至少没有提供在对象构建时获得基于序列的ID的选项?如果实体最终没有持久存在,则存在浪费一些ID的风险,但我认为这不是一个大问题。
除此之外,就解决方案的简单性和可理解性而言,唯一的“不妥协”似乎是UUID,它们都有自己的问题。
我错过了什么吗?是否有某些JPA身份生成器或某些库可以基于序列并允许在构建时提供ID?答案 0 :(得分:2)
从写作的角度来看,使用assigned identifier是最好的方法。它在所有entity state transitions中也是一致的,您甚至可以在JDBC级别批量多个插入。
在阅读和索引方面,数字列表现更好,分配的标识符是唯一逻辑密钥(社会安全号码)或唯一标识符(例如UUID)。使用应用程序级唯一分配的标识符很复杂,因为您可能有多个应用程序节点(在群集中),或者您希望在应用程序内部以及从外部源(数据库客户端实用程序)同步插入。
对于数据库分配的标识符,您需要考虑您的选择如何影响刷新。 Hibernate试图推迟Persistence Context flushing up until the last possible moment。这种策略传统上称为事务性后写。
后写与Hibernate刷新更相关,而不是任何逻辑或物理事务。在交易期间,冲洗可能会多次发生。
刷新的更改仅对当前数据库事务可见。在提交当前事务之前,其他并发事务不会看到任何更改。
IDENTITY requires flushing,虽然序列是非事务性的,因此它不需要刷新。 IDENTITY禁用JDBC插入批处理,它不支持预分配。
JPA无法在Entity构造时分配标识符,因为新实例只能通过EntityManager.persist()调用保持持久化。 JPA要求明确的"实体状态转换"。
浪费序列标识符不是什么大问题。即使序列值存在间隙,数据库也能正常运行。使用bigint列可以保证您几乎不会用完序列标识符。让非事务性序列标识符分配偶尔出现间隙比使事务分配具有更高的死锁争用风险更好。