如何使用现有的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】:

allocationSizeincrementBy 是完全不同的东西。

Hibernate 当然会使用您在 DB 中创建的序列,但根据 allocationSize,您可能会发现生成值的差距。

例如- 假设当前序列值为 5,在 db 中增加 1allocationSize 默认为 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 文件中添加&lt;property name="hibernate.jdbc.use_get_generated_keys"&gt;true&lt;/property&gt;

以上是关于如何使用现有的Oracle序列在hibernate中生成id?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 @ID 和 @GeneratedValue 从 Hibernate + JPA 中的序列中获取 Oracle 生成的值

让Oracle触发ID而不是Hibernate的序列?

用于从序列生成 id 的 Oracle 触发器的 HIbernate 问题

如何配置 Hibernate 以使用 SSL 与数据库服务器通信?

hibernate oracle 序列产生大的间隙

hibernate.hbm2ddl.auto + Oracle 中的自定义 sql 类型