zoukankan      html  css  js  c++  java
  • Java step by step(2): Hibernate and Oracle Sequence

    在Hibernate中, 可以用类似Oracle中的sequence来生成对象的标示。如下例所示,通过是用SequenceGenerator这个Annotation, 将Oracle的sequence -- SEQ_LIMITS_CHANGES ”绑定“ (通过GeneratedValue这个annotation)到了Class LimitsChangeDO 中ID这个field上。

    public class LimitsChangeDO {

    @GeneratedValue(generator
    = "limits_review_limit_sequence")
    @SequenceGenerator(name
    = "limits_review_limit_sequence", sequenceName = "SEQ_LIMITS_CHANGE")
    @Id
    @Column(name
    = "ID")
    private Long id;

      

    SequenceGenerator这个Annotation的定义如下...

    public @interface SequenceGenerator {

    /**
    * (Required) A unique generator name that can be referenced
    * by one or more classes to be the generator for primary key
    * values.
    */
    String name();

    /**
    * (Optional) The name of the database sequence object from
    * which to obtain primary key values.
    * <p> Defaults to a provider-chosen value.
    */
    String sequenceName()
    default "";

    /**
    * (Optional) The value from which the sequence object
    * is to start generating.
    */
    int initialValue() default 1;

    /**
    * (Optional) The amount to increment by when allocating
    * sequence numbers from the sequence.
    */
    int allocationSize() default 50;
    }

      

    本来以为Hibernate只是简单的用Oracle Sequence,每次插入数据的时候简单地用类似于(select seq_name.nextval from dual)的方式取得sequence的值,然后给对应的java object的ID赋值。但是最近发现一个奇怪的问题,数据库中有张表的主键ID的值变得非常非常巨大,但是记录条数也不过寥寥几百条而已,如果是简单通过sequence.nextval的方式取值的话,不太可能造成这么巨大的值,虽然我们知道oracle sequence的值不是连续的,会因为一些原因(比如session的异常中断等, sequence的cache值大于1)造成生成的序列有一定的gap。 那么究竟是什么原因造成这个诡异的结果的呢?

    经过一些原因,最后发现这个问题的造成跟Hibernate生成sequence的算法有一定的关系,但是这也不能全怪在Hibernate头上,因为是几个原因共同造成的。

    首先,数据库在创建表的时候给对应的主键创建了sequence, 同时在一张表里记录了sequence跟该表主键的对应关系。这么做的原因是如果对该表进行了一些数据批量导入,很显然这个过程中sequence的值并没有增加,那么在数据导入结束之后,很显然最后要进行sequence的synchronization的工作,即把表的主键对应的sequence的nextval提升到这个表中主键的(最大值+1),这样下次再通过seq_name.nextval来往表里插入数据的时候就不会报错unique key constraint violation的错误了。通过sequence和表主键对应的关系,很容易从表和视图user_sequence中找到当前sequence的value和主键的最大值,然后看是否需要更改sequence的next value (更改increment by 之类的操作)。

    这么做是没有任何问题的,但是不幸的是,这张表也用在了Hibernate中,由于Hibernate不是简单地用oracle sequence来取值,它是用了Hi/Lo算法,会在oracle sequence的值的基础上乘上(*) SequenceGenerator中定义的aollocationSize的值(默认是50), 公式如下 (参考http://itdevworld.wordpress.com/2009/12/20/hibernate-sequencegenerator-with-allocationsize1-leads-to-huge-contention/

    DBSequence*allocationSize<= IDs < (DBSequence+1)*allocationSize

    所以如果经常进行sequence 的 synchorization的操作,很显然这个ID会越来越大,基本上每进行一次sequence sync操作(尤其是在用了Hibernate之后进行这种sync操作),造成的sequence的gap会以50(allocationSize)的倍数增长,自然结果表里的ID的值会搞得很巨大!

  • 相关阅读:
    OpenGL_ES-纹理
    GCD 初步学习
    关于心理的二十五种倾向(查理&#183;芒格)-3
    黑马day18 jquery高级特性&amp;Ajax的load方法
    九度 1138
    FusionCharts简单教程---建立第一个FusionCharts图形
    【转】第二课.配置和初始化
    【转】Git详解之一:Git起步
    【转】1.5 起步
    【转】Cygwin的包管理器:apt-cyg
  • 原文地址:https://www.cnblogs.com/fangwenyu/p/2123929.html
Copyright © 2011-2022 走看看