解决Oracle序列重复问题(oracle序列重复)
在开发中,使用Oracle的Sequence经常会用到,用于生成自增的主键字段,意在保证创建的数据每行主键是独一无二的。 但是,由于各种原因,经常会出现Sequence重复,从而引发数据库异常。
要解决这一Oracle序列重复问题,我们可以在并发环境中加入一定的逻辑:
1、使用存储过程来实现:可以在存储过程里,先获取一个Sequence值,然后依次判断数据库中是否存在相同值,如果不存在则插入;如果存在,则重取一个Sequence值,重复执行这个逻辑,直到插入成功;
“`sql
CREATE OR REPLACE PROCEDURE get_nextval_by_seq
(v_seq_name IN VARCHAR2,
v_nextval OUT NUMBER)
IS
v_currval NUMBER;
v_try_times NUMBER;
BEGIN
v_try_times := 0;
LOOP
— 获取 Sequence 值
SELECT seq_name.nextval
INTO v_currval
FROM dual;
— 判断是否存在重复的值
BEGIN
INSERT INTO tab_ (col1)
VALUES (v_currval);
v_nextval := v_currval;
EXIT;
EXCEPTION
WHEN DUP_VAL_ON_INDEX
THEN — 如果重复,则重新 get 一个值
v_try_times := v_try_times + 1;
CONTINUE;
END;
END LOOP;
END get_nextval_by_seq;
2、使用AQ (Advance Queue):AQ本身就是一种先进的队列,可以用来实现高并发环境下的序列号生成,例如:
```sql-- 创建队列
BEGIN SYS.DBMS_AQADM.CREATE_QUEUE(
queue_name => 'seq_aq', queue_table => 'seq_table',
multiple_consumers => FALSE );
END;/
-- 创建生产者BEGIN
SYS.DBMS_AQADM.CREATE_QUEUE_PRODUCER( producer_name => 'seq_producer',
queue_name => 'seq_aq' );
END;/
-- 启动队列BEGIN
SYS.DBMS_AQADM.START_QUEUE(queue_name => 'seq_aq');END;
/
-- 创建序列CREATE SEQUENCE seq_aq
INCREMENT BY 1 START WITH 1
MAXVALUE 999999999999999999 MINVALUE 1
NOCYCLE NOCACHE;
-- 构造函数CREATE OR REPLACE FUNCTION get_nextval_by_aq
RETURN INTEGER IS
enq_opt DBMS_AQ.ENQUEUE_OPTIONS_T; mes_prop DBMS_AQ.MESSAGE_PROPERTIES_T;
message_handle RAW(16); nextval INTEGER;
BEGIN MES_PROP.Correlation := SYS.DBMS_AQ.NEW_CORRELATION;
ENQ_OPT.RetentionTime := 0;
SYS.DBMS_AQ.ENQUEUE( queue_name => 'SEQ_AQ', enqueue_opt => ENQ_OPT,
message_prop => MES_PROP, payload =>
SYS.DBMS_AQ.new_message( nextval => seq_aq.nextval),
msgid => message_handle );
nextval := MES_PROP.message_data.nextval; SYS.dbms_aq.dequeue(
queue_name => 'SEQ_AQ', dequeue_options => NULL,
message_properties => MES_PROP, payload => nextval,
msgid => message_handle );
return nextval; EXCEPTION
WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Error') ;
END;
以上方法可以有效解决Oracle序列重复问题,当前可用方案应该根据实际情况选择,AQ一般用于并发环境比较严格的情景,普通情景可以使用存储过程就可以达到同样的效果。