需要重置Oracle中序列的值
我正在使用Spring和Hibernate来开发Java应用程序。 假设我有一张桌子。 当我从这个表中删除一些logging时,有时我需要重置主键字段的值。
假设我有一个表中有10条logging,我删除了最后5条logging。 现在,当我插入新logging时,主键字段的值应该从6
开始,但是从11
开始。
如果我需要在MySql中以6
( maximum +1
)启动主键值,那么我只需要执行下面的SQL语句。
alter table table_name auto_increment=1;
这会自动将auto_increment
的值重置为该字段的maximum + 1
值(可能在概念上不正确,但是可行)。
在Oracle(10g)中,我使用主键sequence
。 当Oracle从数据库中删除一些logging时,是否有办法将sequence
的值重置为maximum + 1
值?
如果您正在使用该值,则不应重置该值的原因:
如果你有20条logging,删除5-10条logging会怎么样? 你在中间有一个缺口,重新设定序列不会解决。 序列永远不会产生无间隙的数字序列 ,是一个完美的1,2 … n 。
如果你调用.nextval
,不要使用它的值。 你要丢弃并重新创build序列吗? 如果你开始插入并取消它,Oracle 回滚你所做的那些值,那么这些值就不存在了 。 如果你设置nocache
那么你将有较less的差距,但成本打击性能; 这值得么?
应该将caching设置为您希望在所有会话中一次执行的插入次数,以避免任何性能问题。 序列的目的是提供一个非常快速,可扩展的方式创build一个代理键没有任何锁等不重新生成一组正整数。
在一天结束的时候,丝毫不应该有任何问题。 如果你依靠一个不间断的序列作为你的表的关键,那么你的数据有问题,而不是序列。
回答这个问题:
要真正回答你的问题,你需要:
- 首先,找出你的表中最大的id(sequence)值是多less。
- 然后删除并重新创build序列 。
find最大值意味着你需要重新创build序列dynamic的代价是另一个命中performance。
如果在发生这种情况时尝试向表格中插入某些内容,将会失败,并可能使使用该顺序的任何触发器或其他对象失效:
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; /
正如我所说这不build议,你应该忽略任何差距。
更新 – 又一个更好的答案感谢Jeffrey Kemp :
与文件build议相反,正如杰弗里·肯普(Jeffrey Kemp)在评论中提出的那样,在不丢弃和重新创build序列的情况下 ,可以这样做。
即,通过:
- 计算表中最大的
id
和序列的当前值之间的差异。 - 改变序列以这个负数递增
- 改变顺序再次增加1。
这样做的好处是,对象仍然存在,触发器,赠款等仍然保持。 我认为不利的一面是,如果另一个会议与此同时以这个负数增加,则可能会回到过去。
这是一个示范:
设置testing:
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>
以下也有效(将您的序列值增加100):
select my_sequence.nextval from dual connect by level <= 100;
参考Oracle的ALTER SEQUENCE文档,
- 要以不同的编号重新启动序列,您必须删除并重新创build它。
您需要传递主键列的当前最大值以生成下一个序列号。
如果您不断删除一些最新的logging,并希望重新使用已经生成的序列值,则可能需要一次又一次地重新启动该序列。 如果服务器在序列准备好服务之前接收到下一个值的请求,则删除序列可能会导致SQLException。
您也可以在这里find有关Oracle序列的一些有用的注意事项。
这个把戏适合我。 在我的序列(USERSUTPL_USERUTPL_SQ)中,最后一个数字是53.我表格中的最后一个数字是83
SELECT MAX(ID) FROM USERSUTPL_USERUTPL
那么83 – 53 = 31.所以:
ALTER SEQUENCE USERSUTPL_USERUTPL_SQ INCREMENT BY +31; SELECT USERSUTPL_USERUTPL_SQ.NEXTVAL FROM dual; ALTER SEQUENCE USERSUTPL_USERUTPL_SQ INCREMENT BY 1;
它的变化是最后一个数字。 :d
- 使用额外列映射多对多关联表
- hibernate:LazyInitializationException:无法初始化代理
- JPA 2.0:自动将实体类从不同的jar *添加到PersistenceUnit *
- 如何强制Hibernate返回date为java.util.Date而不是Timestamp?
- JPA最快的方式来在持久性期间忽略一个字段?
- 绕过Hibernate中的GeneratedValue(合并数据不在数据库?)
- hibernate:根据实体类自动创build/更新数据库表
- Hibernate:一对一延迟加载,可选= false
- 如何使用REST API进行身份validation? (浏览器+本机客户端)