35

我正在使用休眠 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 ;

主题类是这样的:

@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 个主题由 plsql 脚本从 excel 加载,并且 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

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

有谁知道为什么会发生这种情况并且热修复它

谢谢

4

9 回答 9

45

我认为问题在于序列生成器并不是真正的序列生成器,而是序列 hilo 生成器,默认分配大小为 50。如文档所示:http ://docs.jboss.org/休眠/稳定/注释/参考/en/html_single/#entity-mapping-identifier

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

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

于 2011-03-17T23:22:44.183 回答
38

同意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,休眠使用 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") 
        }
    )
    

我已经测试了两种方法,效果很好。

于 2011-03-17T23:58:31.033 回答
8

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

为了解决这个问题,我们需要将其设置为500 并将DB 中的allocationSize序列也设置为 500,然后最重要的是添加一个休眠设置以要求它使用新的序列生成器实现,这里我假设您将休眠属性设置为java配置类:INCREMENT VALUEhibernate.id.new_generator_mappings

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

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

如果您在同一条船上,请查看我的帖子以获取更多详细信息:

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

于 2016-04-23T21:42:22.423 回答
6

另一种解决方案是:

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

@Id
@SequenceGenerator(name = "studentId", sequenceName = "student_Id")
@GeneratedValue(strategy = GenerationType.AUTO, generator="studentId")  
private int studentId;
于 2012-11-22T18:15:18.237 回答
5

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

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

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

注意:序列的缓存值对于一次性分配“x”序列值的大负载很有用。如果您使用的是一次执行一个插入的事务系统 - 那么缓存是没有用的(或者我应该说 - 我从来没有发现它有用)。

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

谢谢。保罗

于 2011-03-17T22:45:25.367 回答
3

对此的一种解决方案是,我们可以将具有 allocationSize 的序列生成器配置为:

@SequenceGenerator(name = "gen_name", sequenceName = "seq_name", allocationSize= 1)
于 2018-08-30T12:05:40.150 回答
2

最成功的答案是:

@Id
@SequenceGenerator (name = "id_sequence", sequenceName = "sq50")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "id_sequence")
public int getId() {
return id;
}
于 2013-05-23T11:46:38.443 回答
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

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

        <property name="hibernate.id.new_generator_mappings" value="false" />
于 2016-05-05T10:51:03.350 回答
0

这里所说,尝试SequenceGenerator.allocationSize使用您的数据库序列INCREMENT BY号进行调整。

于 2015-02-05T09:04:16.967 回答