sse*_*sse 32 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
)
;
Run Code Online (Sandbox Code Playgroud)
当插入新主题时,sub_seq用于创建主题id,定义在这里
create sequence sub_seq
MINVALUE 1
MAXVALUE 999999999999999999999999999
START WITH 1
INCREMENT BY 1
CACHE 100
NOCYCLE ;
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
在主题表中,数据库中有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
Run Code Online (Sandbox Code Playgroud)
有几个大的差距:4555至255051,255067至260051,265057至270051
这是浪费而不是理想的行为.
有没有人知道为什么会发生这种情况并且很热
谢谢
JB *_*zet 42
我认为问题来自于序列生成器实际上不是序列生成器,而是序列hilo生成器,默认分配大小为50.如文档所示:http://docs.jboss.org/ 冬眠/稳定/注解/参考/ EN/html_single /#实体-映射标识符
这意味着如果序列值为5000,则下一个生成的值将为5000*50 = 250000.将序列的缓存值添加到等式中,它可以解释您的巨大初始差距.
检查序列的值.它应该小于最后生成的标识符.注意不要将序列重新初始化为最后生成的值+ 1,因为生成的值将呈指数级增长(我们遇到此问题,并且由于溢出而导致负整数ID)
sse*_*sse 37
同意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;
}
Run Code Online (Sandbox Code Playgroud)
如果你使用javax.persistence.SequenceGenerator,hibernate使用hilo并且可能会在序列中产生大的间隙.有一篇文章解决了这个问题:https:
//forum.hibernate.org/viewtopic.php?t = 973682
有两种方法可以解决此问题
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")
}
)
Run Code Online (Sandbox Code Playgroud)我已经测试了两种方式,效果很好.
实际上,如果你的序列INCREMENT VALUE是1并且你不需要持久化很多实体,那么allocateSize = 1就可以了.但是,如果要保留数千或数百万条记录,上述设置可能会成为性能瓶颈,因为每次保存需要获取id因此需要db读取.
为了解决这个问题,我们需要设置allocationSize成类似500和顺序INCREMENT VALUE也DB到500,然后最重要的新增休眠设置hibernate.id.new_generator_mappings来要求它使用新的序列发生器的实现,在这里,我假设你在设置你的Hibernate属性java配置类:
properties.setProperty("hibernate.id.new_generator_mappings", Boolean.toString(true));
Run Code Online (Sandbox Code Playgroud)
这样,Hibernate将使用SequenceStyleGenerator而不是旧的SequenceHiLoGenerator来生成id.SequenceStyleGenerator更友好的是jpa和oracle.它基于序列式数据库结构生成标识符值.变化的范围从实际使用序列到使用表来模拟序列.
如果您在同一条船上,请查看我的帖子以获取更多详细信息:
vcfvct.wordpress.com/2016/04/23/jpa-sequencegenerator-with-allocationsize-1-performance-tuning/
小智 6
另一种解决方案是
使用'GenerationType.AUTO'而不是'GenerationType.SEQUENCE'作为策略@GeneratedValue,如下所示;
@Id
@SequenceGenerator(name = "studentId", sequenceName = "student_Id")
@GeneratedValue(strategy = GenerationType.AUTO, generator="studentId")
private int studentId;
Run Code Online (Sandbox Code Playgroud)
如果您阅读以下链接,您将看到问题是由序列创建命令上的CACHE设置引起的.删除缓存设置将在一定程度上解决问题 - 但不考虑回滚的可能性等.
链接是:http://asktom.oracle.com/pls/apex/f? p = 100:11:0 ::::P11_QUESTION_ID:369390500346406705
现在重新同步序列的唯一方法是重新创建序列,重命名当前表并再次创建表,然后将旧表中的记录重新插入到新表中.
注意:序列的缓存值对于一次分配"x"序列值的大型负载非常有用.如果您正在使用一次只插入一个事务系统 - 那么缓存是没用的(或者我应该说 - 我从未发现它有用).
注意:这是我对序列的缓存选项的理解.您可以在CREATE SEQUENCE命令中查找Oracle文档以获取更多信息.但上面的链接应该为您的问题提供合理的答案.
谢谢.保罗
| 归档时间: |
|
| 查看次数: |
49318 次 |
| 最近记录: |