如何使用现有的Oracle序列在hibernate中生成id?
Posted
技术标签:
【中文标题】如何使用现有的Oracle序列在hibernate中生成id?【英文标题】:How to use existing Oracle sequence to generate id in hibernate? 【发布时间】:2011-01-10 10:53:45 【问题描述】:我有一个旧版 Oracle 数据库,其序列名为 PRODUCT_ID_SEQ
。
这是Product
类的映射,我需要为其生成正确的ID:
public class Product
@GeneratedValue(strategy = GenerationType.SEQUENCE,
generator = "retailerRaw_seq")
@SequenceGenerator(name = "retailerRaw_seq",
sequenceName = "PRODUCT_ID_SEQ")
private Long id;
...
但是看起来 ids 是以 50 的间隔生成的,比如 1000、1050、1100 等。这对应于默认值 allocationSize
property = 50。所以这意味着 Hibernate 实际上并没有使用序列已在数据库中定义。
如何让 Hibernate 使用该序列?
【问题讨论】:
重复问题:见***.com/questions/1729723/… 不,它不是重复的。答案见下文 【参考方案1】:首先:您应该在数据库中创建如下序列:
CREATE SEQUENCE "PRODUCT_ID_SEQ" MINVALUE 0 MAXVALUE 1000000000 INCREMENT BY 1 START WITH 1 CACHE 500 NOORDER NOCYCLE ;
并在您的文件 Product.hbm.xml 中配置 make :
<class name="ProductPersistant" table="Product">
<id name="id" type="java.lang.Long" column="productID" >
<generator class="sequence">
<param name="sequence">PRODUCT_ID_SEQ</param>
</generator>
</id>
【讨论】:
【参考方案2】:allocationSize 和 incrementBy 是完全不同的东西。
Hibernate 当然会使用您在 DB 中创建的序列,但根据 allocationSize,您可能会发现生成值的差距。
例如- 假设当前序列值为 5,在 db 中增加 1,allocationSize 默认为 50。
现在你想通过hibernate保存3个元素的集合,然后 Hibernate 将分配生成的 id 250、251、252
这是为了优化目的。 Hibernate 不必返回 db 并获取下一个增量值。
如果您不希望这样做,只需将 allocationSize = 1
设置为已回答即可达到目的
【讨论】:
【参考方案3】:我从 3.5.5 升级到 5.0.6.Final 时遇到了同样的问题。
我通过在 HBM 文件中重新配置映射解决了这个问题:
<generator class="sequence">
<param name="sequence">PRODUCT_ID_SEQ</param>
</generator>
到:
<generator class="org.hibernate.id.enhanced.SequenceStyleGenerator">
<param name="prefer_sequence_per_entity">true</param>
<param name="optimizer">none</param>
<param name="increment_size">1</param>
<param name="sequence_name">PRODUCT_ID_SEQ</param>
</generator>
【讨论】:
是否需要将increment_size设置为1?不是默认值吗?【参考方案4】:在 Oracle 中创建您的序列名称,例如contacts_seq。 在您的 POJO 类中。为您的序列定义以下注释。
@Id
@GeneratedValue(strategy=GenerationType.AUTO, generator="my_seq_gen")
@SequenceGenerator(name="my_seq_gen", sequenceName="contacts_seq")
【讨论】:
【参考方案5】:我在 PostgreSQL 上使用以下功能,效果很好。
@Id
@GeneratedValue(generator = "my_gen")
@SequenceGenerator(name = "my_gen", sequenceName = "my_seq_in_db")
private int userId;
【讨论】:
PostgreSQL 和 Oracle 是不同的数据库类型【参考方案6】:如果你使用 javax.persistence.SequenceGenerator,hibernate 使用 hilo 并且可能会在序列中产生很大的间隙。有一个帖子解决了这个问题:https://forum.hibernate.org/viewtopic.php?t=973682
有两种方法可以解决这个问题
在SequenceGenerator注解中,添加allocationSize = 1, initialValue= 1
不要使用 javax.persistence.SequenceGenerator,而是使用 org.hibernate.annotations,如下所示:
@javax.persistence.SequenceGenerator(name = "Question_id_sequence", sequenceName = "S_QUESTION")
@org.hibernate.annotations.GenericGenerator(name="Question_id_sequence", strategy = "sequence", parameters = @Parameter(name="sequence", value="S_QUESTION") )
两种方法我都测试过了,效果很好。
【讨论】:
【参考方案7】:原问题的答案:
@SequenceGenerator(name="EL_SEQ", sequenceName="EL_SEQ",allocationSize=1)
allocationSize
将值设置为递增。
【讨论】:
赞成,因为这是一个正确的 JPA 解决方案,而不是特定于 Hibernate。但是,allocationSize=1 意味着每次插入都需要从数据库中获取一个数字,而不是一次缓存很多 Id,因此它的性能下降非常小。【参考方案8】:这是一个带有注释的工作示例,这样,将使用现有的 DB 序列(您也可以使用“序列”策略,但插入时性能较差):
@Entity
@Table(name = "USER")
public class User
// (...)
@GenericGenerator(name = "generator", strategy = "sequence-identity", parameters = @Parameter(name = "sequence", value = "USER_SEQ"))
@Id
@GeneratedValue(generator = "generator")
@Column(name = "ID", unique = true, nullable = false, precision = 22, scale = 0)
public Long getId()
return this.id;
【讨论】:
我发现在使用这种技术时它有效,但我的数据库将它的 id 值增加了 2 而不是 1。有什么想法吗? 检查您在 Oracle 中的序列定义,您可能有类似“CREATE SEQUENCE my_sequence START WITH 1 INCREMENT BY 2”的内容【参考方案9】:默认情况下,Hibernate 使用序列 HiLo 生成器,除非您有特殊需要,否则它很好(性能方面)。您可以在我的博客here
中阅读更多内容艾尔
【讨论】:
有什么想法改变算法,使用 JPA 注释说池化而不是 hilo?【参考方案10】:我不习惯使用注释,这是我的 *.hbm.xml 中的:
<id name="id" type="java.lang.Integer">
<column name="ID_PRODUCT" />
<generator class="sequence-identity" >
<param name="sequence">PRODUCT_ID_SEQ</param>
</generator>
</id>
您可以轻松地将其映射到注释。生成器 sequence-identity 使用序列自动递增。
【讨论】:
这是正确的做法(使用 xml),请参阅下面的注释示例 +1 并记得在您的hibernate.cfg.xml
文件中添加<property name="hibernate.jdbc.use_get_generated_keys">true</property>
。以上是关于如何使用现有的Oracle序列在hibernate中生成id?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 @ID 和 @GeneratedValue 从 Hibernate + JPA 中的序列中获取 Oracle 生成的值
用于从序列生成 id 的 Oracle 触发器的 HIbernate 问题