美文网首页
Oracle 数据库 Sequence Pre-allocati

Oracle 数据库 Sequence Pre-allocati

作者: 吉祥如意酥 | 来源:发表于2018-07-19 06:32 被阅读0次

    事件背景:

    之前我手里的一个项目需要升级weblogic从11g到12c,要将Toplink转化为Eclipselink,然后当时遇到一个方法:databaseLogin.setSequencePreallocationSize(1);这个方法已经无法使用,就先将他注释掉了。然后在测试中发现启动后运行一段时间,DB就会报出主键冲突的错误。经过排查发现每次重新启动Server,各个数据库表的插入数据的id几乎都会是原来最大id减去50的值,使得再插入新的数据会有id相同的情况。而且这种情况是周期性的,每增加50个id,就会将id减去50重新处理。

    相关知识:

    首先,什么是Sequence:Sequence是数据中一个特殊存放等差数列的表,该表受数据库系统控制,任何时候数据库系统都可以根据当前记录数大小加上步长来获取到该表下一条记录应该是多少,这个表没有实际意义,常常用来做主键用。以下是他的表结构:

    SequenceTable表结构

    increment_by(增长间隔),max_value (最大值),min_value (最小值),cache (制定存入缓存序列值的个数) ,last_number (当前可取的最后一个number)

    其中重点说一下increment_by,每当表将已有的Sequence用完之后,将会预加载的sequence大小。然后Last_number = last_number + increment_by。之后Sequence就会从预加载的这一块Sequence的第一个开始读。

    开发中用到的相关方法:

    先说明一下为什么会产生背景中介绍的那样的问题。首先看一下EclipseLink在试图取得下一段可使用Sequence所使用的方法:

    protected Vector createVector(Number sequence, String seqName, int size) {

            long nextSequence = sequence.longValue();

            Vector sequencesForName = new Vector(size);

            nextSequence -= (long)size;

            if(nextSequence < -1L) {

                throw ValidationException.sequenceSetupIncorrectly(seqName);

            } else {

                for(int index = size; index > 0; --index) {

                    ++nextSequence;

                    sequencesForName.add(Long.valueOf(nextSequence));

                }

                return sequencesForName;

            }

        }

    SequenceForName是接下来所能使用的Sequence列表,从代码中可以看出,取得的sequence区间是 nextSequence - size ~ nextSequence。sequece得到的值和DB中sequence table相关,如上图我们的设置,下一个要取的sequence id是最后一个id + 1,而size = 50 (之后会说明为什么=50),所以新的sequence区间相当于后退了49个id。

    然后我们看一下之前被我们注释的方法的官方说明:

    setSequencePreallocationSize

    public voidsetSequencePreallocationSize(int size)

    Deprecated.use getDefaultSequence().setPreallocationSize(int) instead

    OBSOLETE:

    TopLink supports sequence number preallocation.

    This improves the performance and concurrency of inserts by selecting new object IDs in batches and caching them on the client.

    The preallocation size can be configured, and the default is 50.

    By default a sequence table is used. Using a sequence table is recommended as it supports preallocation.

    This MUST be 1 if native sequencing is used on Sybase, Informix, or SQL Server.

    This MUST match the SEQUENCE increment if Oracle native sequencing is used.

    注意最后两行,由于我们使用了Nactive sequence(Many databases have built in support for sequencing. This can be a SEQUENCE object such as in Oracle,or a auto-incrementing column such as the IDENTITY field in Sybase. For an auto-incrementing column the preallocation size is always 1.For a SEQUENCE object the preallocation size must match the SEQUENCE objects "increment by".)所以是要主动设置这个增量size的(50 -> 1)Squence table不用做改动 (因为本来就是1)

    这里有一点比较奇怪,就是如果直接使用databaseLogin.useNativeSequencing();还是会去取this.getPlatform().getDefaultSequence().getPreallocationSize() 作为Pre-allocation,就是还是会赋默认值50... 所以我们采取的解决方案是用默认的Sequecing并修改Pre-allocation的值:databaseLogin.setDefaultSequence(new NativeSequence(login.getPlatform().getDefaultSequence().getName(),1, login.getPlatform().getDefaultSequence().getInitialValue())); 这样问题就解决了。

    还有一点就是为什么其他的application升级eclipseLink时候没有问题,可能是最初就用的DefaultSequencing或者使用getDefaultSequence().setPreallocationSize(int)设置的Pre-allocation吧,因为setSequencePreallocationSize(1) 在Toplink的时候已经废弃了。

    以上就是这个问题的解决过程。其实也不用特别在升级的时候留意,因为EclipseLink中如果有setSequencePreallocationSize(1)这个方法会标红,这样自然而然会用新的方法设置default值,就不会有问题了。

    相关文章

      网友评论

          本文标题:Oracle 数据库 Sequence Pre-allocati

          本文链接:https://www.haomeiwen.com/subject/oxmepftx.html