hibernate oracle序列产生很大的差距

时间:2011-03-17 22:38:38

标签: oracle hibernate sequence gaps-in-data

我正在使用hibernate 3,oracle 10g。我有一张桌子:主题。定义在这里

CREATE TABLE SUBJECT
    ( 
     SUBJECT_ID NUMBER (10), 
     FNAME VARCHAR2(30)  not null, 
     LNAME VARCHAR2(30)  not null, 
     EMAILADR VARCHAR2 (40),
     BIRTHDT  DATE       not null,
     constraint pk_sub primary key(subject_id) USING INDEX TABLESPACE data_index
    ) 
;

当插入新主题时,sub_seq用于创建主题id,定义在这里

create sequence sub_seq
       MINVALUE 1 
       MAXVALUE 999999999999999999999999999 
       START WITH 1
       INCREMENT BY 1 
       CACHE 100 
       NOCYCLE ;

Subject类是这样的:

@Entity
@Table(name="ktbs.syn_subject")
public class Subject {

    @Id 
    @Column(name="subject_id")
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SUB_SEQ")
    @SequenceGenerator(name="SUB_SEQ", sequenceName = "SUB_SEQ")
    private long subjectId;
    private String fname;
    private String lname;
    private String emailadr;
    private Date birthdt;
}

在主题表中,数据库中有4555个主题由excel的plsql脚本加载,sub_sequence工作正常。主题ID范围为1--4555。

然而,当我使用hibernate从我的应用程序添加主题时, 序列号跳到255050.运行几天后,hibernate生成的主题id看起来像这样

270079
270078
270077
270076
270075
270074
270073
270072
270071
270070
270069
270068
270067
270066
270065
270064
270063
270062
270061
270060
270059
270058
270057
270056
270055
270054
270053
270052
270051
270050
265057
265056
265055
265054
265053
265052
265051
265050
260059
260058
260057
260056
260055
260054
260053
260052
260051
260050
255067
255066
255065
255064
255063
255062
255061
255060
255059
255058
255057
255056
255055
255054
255053
255052
255051
255050
4555
4554
4553
.
.
.
.
1

有几个大的差距:4555至255051,255067至260051,265057至270051

这是浪费而不是理想的行为。

有谁知道为什么会发生这种情况并且很难解决它

由于

9 个答案:

答案 0 :(得分:40)

我认为问题来自于序列生成器实际上不是序列生成器,而是序列hilo生成器,默认分配大小为50.如文档所示:http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#entity-mapping-identifier

这意味着如果序列值为5000,则下一个生成的值将为5000 * 50 = 250000.将序列的缓存值添加到等式中,它可以解释您的巨大初始差距。

检查序列的值。它应该小于最后生成的标识符。注意不要将序列重新初始化为最后生成的值+ 1,因为生成的值会以指数方式增长(我们遇到此问题,并且由于溢出而导致负整数ID)

答案 1 :(得分:36)

同意JB。但还是要感谢PaulJ。

更具体到我的注释代码:

@Entity
@Table(name="ktbs.syn_subject")
public class Subject {

  @Id 
  @Column(name="subject_id")
  @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SUB_SEQ")
  @javax.persistence.SequenceGenerator(name="SUB_SEQ", sequenceName = "SUB_SEQ")
  private long subjectId;
  private String fname;
  private String lname;
  private String emailadr;
  private Date birthdt;
}

如果你使用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") 
        }
    )
    
  3. 我已经测试了两种方式,效果很好。

答案 2 :(得分:6)

另一种解决方案是:

使用'GenerationType.AUTO'代替'GenerationType.SEQUENCE'作为@GeneratedValue的策略,如下所示;

@Id
@SequenceGenerator(name = "studentId", sequenceName = "student_Id")
@GeneratedValue(strategy = GenerationType.AUTO, generator="studentId")  
private int studentId;

答案 3 :(得分:6)

如果您的序列INCREMENT VALUE为1并且您不需要持久化大量实体,那么实际上allocateSize = 1就可以了。 但是,如果您要保留数千或数百万条记录,则上述设置可能会成为性能瓶颈,因为每次保存都需要获取ID,因此需要进行数据库读取。

要解决这个问题,我们需要将allocationSize设置为类似于500且序列INCREMENT VALUE的数据库也设置为500,然后最重要的是添加一个休眠设置hibernate.id.new_generator_mappings来询问它使用新的序列生成器实现,这里我假设你在java Config类中设置你的hibernate属性:

properties.setProperty("hibernate.id.new_generator_mappings", Boolean.toString(true));

这样,Hibernate将使用SequenceStyleGenerator而不是旧的SequenceHiLoGenerator来生成ID。 SequenceStyleGenerator更加jpa和oracle友好。它基于序列式数据库结构生成标识符值。变化的范围从实际使用序列到使用表来模拟序列。

如果你在同一条船上,请查看我的帖子了解更多细节:

vcfvct.wordpress.com/2016/04/23/jpa-sequencegenerator-with-allocationsize-1-performance-tuning /

答案 4 :(得分:5)

如果您阅读以下链接,您将看到问题是由序列创建命令上的CACHE设置引起的。删除缓存设置将在一定程度上解决问题 - 但不考虑回滚的可能性等。

链接是:http://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:369390500346406705

现在重新同步序列的唯一方法是重新创建序列,重命名当前表并再次创建表,然后将旧表中的记录重新插入到新表中。

注意:序列的缓存值对于一次分配“x”序列值的大型负载非常有用。如果你使用的交易系统一次只进行一次插入 - 那么缓存是没用的(或者我应该说 - 我从来没有发现它有用)。

注意:这是我对序列的缓存选项的理解。您可以在CREATE SEQUENCE命令中查找Oracle文档以获取更多信息。但上面的链接应该为你的问题提供合理的答案。

感谢。 保罗

答案 5 :(得分:2)

对此的一种解决方案,我们可以将sequence Generator的分配大小配置为:

@SequenceGenerator(name = "gen_name", sequenceName = "seq_name", allocationSize= 1)

答案 6 :(得分:1)

最成功的答案是:

@Id
@SequenceGenerator (name = "id_sequence", sequenceName = "sq50")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "id_sequence")
public int getId() {
return id;
}

答案 7 :(得分:1)

我有类似的问题。序列发生器和序列hilo发生器非常相似但有差异。在休眠3中,hilo生成器与默认值50相乘。因此无需增加DB序列。另一方面,hibernate的更高版本默认使用序列生成器。因此,DB增量需要50。

https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/6.3/html/Migration_Guide/Preserve_the_Existing_Behavior_of_the_Hibernate_Identity_Auto_Generated_Value1.html

我遇到了这个有多个hibernate版本(3和5)的问题。相同的配置工作正常(在DB中递增1)。但在hibernate 5中失败了。因此我更新了我的persistence.xml,如下所示。这确保了hilo的生成

        <property name="hibernate.id.new_generator_mappings" value="false" />

答案 8 :(得分:0)

如上所述[{3}},请尝试使用您的数据库序列SequenceGenerator.allocationSize编号调整INCREMENT BY