java - 需要重新设置oracle中sequence的值

标签 java oracle spring hibernate oracle10g

我正在使用 Spring 和 Hibernate 开发 Java 网络应用程序。假设我有一张 table 。当我从这个表中删除一些记录时,有时我需要重新设置主键字段的值。

假设我在一个表中有 10 条记录,我删除了最后 5 条记录。现在,当我插入新记录时,主键字段的值应该从 6 开始,但它会从 11 开始。

如果我需要在MySql中从6开始主键值(最大+1),只需要执行下面的SQL语句即可。

alter table table_name auto_increment=1;

这会自动将 auto_increment 的值重置为该字段的 maximum + 1 值(概念上可能不正确,但它有效)。

在 Oracle (10g) 中,我将 sequence 与主键一起使用。当从数据库中删除某些记录时,Oracle 中是否有一种方法可以将 sequence 的值重置为 maximum + 1 值?

最佳答案

在使用中不应重置该值的原因:

如果您有 20 条记录并删除第 5-10 条记录会怎样?您在中间有一个间隙,重新设置序列将无法解决。序列将 never generate a gap free sequence of numbers , 一个完美的 1, 2 .. n

如果您调用 .nextval 并且不使用该值,它就会消失。您要删除并重新创建序列吗?如果您开始插入并取消它,Oracle rolls back你所做的这些值(value)观消失了。如果你设置 nocache 那么你会有更少的差距,但代价是性能受到影响;这值得么?

你的缓存应该设置为你希望在任何时候执行的插入次数across all sessions以避免任何性能问题。序列旨在提供一种非常快速、可扩展的方式来创建代理键,而无需任何锁等不是来重新生成正整数集。

归根结底,这一点都不重要。如果您依赖一个完整的序列作为表的键,那么您的数据而不是序列有问题。


回答问题:

要真正回答您的问题,您需要:

  1. 首先,找出表中的最大 id(序列)值是多少。
  2. 然后 drop and re-create the sequence .

找到最大值意味着您需要以性能再次受到影响为代价动态地重新创建序列。

如果您在发生这种情况时尝试向您的表中插入某些内容,它将失败,并且可能使任何触发器或其他使用该序列的对象无效:

declare

   l_max_value number;

begin

   select max(id)
     into l_max_value
     from my_table;

   execute immediate 'drop sequence my_sequence_name';

   -- nocache is not recommended if you are inserting more than
   -- one row at a time, or inserting with any speed at all.
   execute immediate 'create sequence my_sequence_name
                           start with ' || l_max_value
                      || ' increment by 1
                           nomaxvalue
                           nocycle
                           nocache';

end;
/

正如我所说,不推荐这样做,您应该忽略任何差距。


更新 - 又名更好的答案感谢Jeffrey Kemp :

与文档的建议相反,正如 Jeffrey Kemp 在评论中所建议的那样,有一种方法可以删除并重新创建序列。

即,通过:

  1. 找出表中最大 id 与序列当前值之间的差值。
  2. 改变序列以增加这个负数
  3. 改变序列以再次递增 1。

这样做的好处是对象仍然存在,触发器、授权等仍然保持不变。如我所见,不利的一面是,如果另一个 session 与您的 session 同时递增这个负数,您可能会倒退太多。

这是一个演示:

设置测试:

SQL> create sequence test_seq
  2   start with 1
  3   increment by 1
  4   nomaxvalue
  5   nocycle
  6   nocache;

Sequence created.

SQL>
SQL> create table tmp_test ( id number(16) );

Table created.

SQL>
SQL> declare
  2     l_nextval number;
  3  begin
  4
  5    for i in 1 .. 20 loop
  6       insert into tmp_test values ( test_seq.nextval );
  7    end loop;
  8
  9  end;
 10  /

PL/SQL procedure successfully completed.

SQL>
SQL> select test_seq.currval from dual;

   CURRVAL
----------
        20

SQL>
SQL> delete from tmp_test where id > 15;

5 rows deleted.

SQL> commit;

Commit complete.

反转序列

SQL>
SQL> declare
  2
  3     l_max_id number;
  4     l_max_seq number;
  5
  6  begin
  7
  8     -- Get the maximum ID
  9     select max(id) into l_max_id
 10       from tmp_test;
 11
 12     -- Get the current sequence value;
 13     select test_seq.currval into l_max_seq
 14       from dual;
 15
 16     -- Alter the sequence to increment by the difference ( -5 in this case )
.
 17     execute immediate 'alter sequence test_seq
 18                          increment by ' || ( l_max_id - l_max_seq );
 19
 20     -- 'increment' by -5
 21     select test_seq.nextval into l_max_seq
 22       from dual;
 23
 24     -- Change the sequence back to normal
 25     execute immediate 'alter sequence test_seq
 26                          increment by 1';
 27
 28  end;
 29  /

PL/SQL procedure successfully completed.

SQL>
SQL> select test_seq.currval from dual;

   CURRVAL
----------
        15

SQL>

关于java - 需要重新设置oracle中sequence的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10159840/

相关文章:

java - 使用 "Object"关键字在 Java 中创建对象

java - 为什么这个 while 循环是无限的?

java - 当外部事务被标记为回滚时回滚所有嵌套事务

java - mybatis嵌套异常是org.apache.ibatis.reflection.ReflectionException

spring - servletcontext.addservlet 未定义

java - 如何在日志记录中更改 Akka 线程名称?

sql-server - SSIS - 由于可能会丢失数据,因此无法转换该值

sql - 在 Oracle 中使用 SQL 检查表是否相同

java - 无法执行spring boot jar

sql - 在 Oracle 中将数据从一个数据库复制到另一个数据库