【问题标题】:How to use existing Oracle sequence to generate id in hibernate?如何使用现有的Oracle序列在hibernate中生成id?
【发布时间】: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 使用该序列?

【问题讨论】:

标签: oracle hibernate sequence


【解决方案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

        有两种方法可以解决这个问题

        1. 在SequenceGenerator注解中,添加allocationSize = 1, initialValue= 1

        2. 不要使用 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;
          猜你喜欢
          • 2014-02-24
          • 1970-01-01
          • 2012-03-02
          • 1970-01-01
          • 2012-04-09
          • 1970-01-01
          • 2015-12-10
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多