如何获取新插入Oracle数据库Sequence值的5种方法

本文介绍了Oracle数据库中sequence的灵活实现方式,并提供了5种不同方法来获取新插入记录生成的sequence值。包括使用nextval和currval、PL/SQL的returning into语法、PreparedStatement的getGeneratedKeys方法以及Oracle特有的returning into语法等。每种方法都有其优缺点,适用于不同性能需求的业务场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

          Oracle的sequence实现非常灵活,所以也带来一些易用性问题,如何取到新插入记录生成的sequence值与其它数据库有较大差别,下面介绍了5种实现读取新插入记录sequence值的方法。

测试用的数据库脚本:

  1. SQL> create table T1  
  2.   2  (  
  3.   3    ID NUMBER  
  4.   4  );  
  5.    
  6. Table created  
  7. SQL> create sequence SEQ_T1;  
  8.    
  9. Sequence created  

  1. //公共代码:得到数据库连接  
  2. public Connection getConnection() throws Exception{  
  3.     Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();  
  4.     Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:dbname""username""password");  
  5.     return conn;  
  6. }  
  7.   
  8. //方法一  
  9. //先用select seq_t1.nextval as id from dual 取到新的sequence值。  
  10. //然后将最新的值通过变量传递给插入的语句:insert into t1(id) values(?)   
  11. //最后返回开始取到的sequence值。  
  12. //这种方法的优点代码简单直观,使用的人也最多,缺点是需要两次sql交互,性能不佳。  
  13. public int insertDataReturnKeyByGetNextVal() throws Exception {  
  14.     Connection conn = getConnection();  
  15.     String vsql = "select seq_t1.nextval as id from dual";  
  16.     PreparedStatement pstmt =(PreparedStatement)conn.prepareStatement(vsql);  
  17.     ResultSet rs=pstmt.executeQuery();  
  18.     rs.next();  
  19.     int id=rs.getInt(1);  
  20.     rs.close();  
  21.     pstmt.close();  
  22.     vsql="insert into t1(id) values(?)";  
  23.     pstmt =(PreparedStatement)conn.prepareStatement(vsql);  
  24.     pstmt.setInt(1, id);  
  25.     pstmt.executeUpdate();  
  26.     System.out.print("id:"+id);  
  27.     return id;  
  28. }  
  29.   
  30. //方法二  
  31. //先用insert into t1(id) values(seq_t1.nextval)插入数据。  
  32. //然后使用select seq_t1.currval as id from dual返回刚才插入的记录生成的sequence值。  
  33. //注:seq_t1.currval表示取出当前会话的最后生成的sequence值,由于是用会话隔离,只要保证两个SQL使用同一个Connection即可,对于采用连接池应用需要将两个SQL放在同一个事务内才可保证并发安全。  
  34. //另外如果会话没有生成过sequence值,使用seq_t1.currval语法会报错。  
  35. //这种方法的优点可以在插入记录后返回sequence,适合于数据插入业务逻辑不好改造的业务代码,缺点是需要两次sql交互,性能不佳,并且容易产生并发安全问题。  
  36. public int insertDataReturnKeyByGetCurrVal() throws Exception {  
  37.     Connection conn = getConnection();  
  38.     String vsql = "insert into t1(id) values(seq_t1.nextval)";  
  39.     PreparedStatement pstmt =(PreparedStatement)conn.prepareStatement(vsql);  
  40.     pstmt.executeUpdate();  
  41.     pstmt.close();  
  42.     vsql="select seq_t1.currval as id from dual";  
  43.     pstmt =(PreparedStatement)conn.prepareStatement(vsql);  
  44.     ResultSet rs=pstmt.executeQuery();  
  45.     rs.next();  
  46.     int id=rs.getInt(1);  
  47.     rs.close();  
  48.     pstmt.close();  
  49.     System.out.print("id:"+id);  
  50.     return id;  
  51. }  
  52.   
  53. //方法三  
  54. //采用pl/sql的returning into语法,可以用CallableStatement对象设置registerOutParameter取得输出变量的值。  
  55. //这种方法的优点是只要一次sql交互,性能较好,缺点是需要采用pl/sql语法,代码不直观,使用较少。  
  56. public int insertDataReturnKeyByPlsql() throws Exception {  
  57.     Connection conn = getConnection();  
  58.     String vsql = "begin insert into t1(id) values(seq_t1.nextval) returning id into :1;end;";  
  59.     CallableStatement cstmt =(CallableStatement)conn.prepareCall ( vsql);   
  60.     cstmt.registerOutParameter(1, Types.BIGINT);  
  61.     cstmt.execute();  
  62.     int id=cstmt.getInt(1);  
  63.     System.out.print("id:"+id);  
  64.     cstmt.close();  
  65.     return id;  
  66. }  
  67.   
  68. //方法四  
  69. //采用PreparedStatement的getGeneratedKeys方法  
  70. //conn.prepareStatement的第二个参数可以设置GeneratedKeys的字段名列表,变量类型是一个字符串数组  
  71. //注:对Oracle数据库这里不能像其它数据库那样用prepareStatement(vsql,Statement.RETURN_GENERATED_KEYS)方法,这种语法是用来取自增类型的数据。  
  72. //Oracle没有自增类型,全部采用的是sequence实现,如果传Statement.RETURN_GENERATED_KEYS则返回的是新插入记录的ROWID,并不是我们相要的sequence值。  
  73. //这种方法的优点是性能良好,只要一次sql交互,实际上内部也是将sql转换成oracle的returning into的语法,缺点是只有Oracle10g才支持,使用较少。  
  74. public int insertDataReturnKeyByGeneratedKeys() throws Exception {  
  75.     Connection conn = getConnection();  
  76.     String vsql = "insert into t1(id) values(seq_t1.nextval)";  
  77.     PreparedStatement pstmt =(PreparedStatement)conn.prepareStatement(vsql,new String[]{"ID"});  
  78.     pstmt.executeUpdate();  
  79.     ResultSet rs=pstmt.getGeneratedKeys();  
  80.     rs.next();  
  81.     int id=rs.getInt(1);  
  82.     rs.close();  
  83.     pstmt.close();  
  84.     System.out.print("id:"+id);  
  85.     return id;  
  86. }  
  87.   
  88. //方法五  
  89. //和方法三类似,采用oracle特有的returning into语法,设置输出参数,但是不同的地方是采用OraclePreparedStatement对象,因为jdbc规范里标准的PreparedStatement对象是不能设置输出类型参数。  
  90. //最后用getReturnResultSet取到新插入的sequence值,  
  91. //这种方法的优点是性能最好,因为只要一次sql交互,oracle9i也支持,缺点是只能使用Oracle jdbc特有的OraclePreparedStatement对象。  
  92. public int insertDataReturnKeyByReturnInto() throws Exception {  
  93.     Connection conn = getConnection();  
  94.     String vsql = "insert into t1(id) values(seq_t1.nextval) returning id into :1";  
  95.     OraclePreparedStatement pstmt =(OraclePreparedStatement)conn.prepareStatement(vsql);  
  96.     pstmt.registerReturnParameter(1, Types.BIGINT);  
  97.     pstmt.executeUpdate();  
  98.     ResultSet rs=pstmt.getReturnResultSet();  
  99.     rs.next();  
  100.     int id=rs.getInt(1);  
  101.     rs.close();  
  102.     pstmt.close();  
  103.     System.out.print("id:"+id);  
  104.     return id;  
  105. }  

     以上5种方法都可以实现功能,以下是5种方法的优缺点汇总,个人推荐性能要求一般的业务采用第一种方法,性能要求非常高业务采用第五种方法。

方法

简介

优点

缺点

方法一

先用seq.nextval取出值,然后用转入变量的方式插入

代码简单直观,使用的人也最多

需要两次sql交互,性能不佳

方法二

先用seq.nextval直接插入记录,再用seq.currval取出新插入的值

可以在插入记录后返回sequence,适合于数据插入业务逻辑不好改造的业务代码

需要两次sql交互,性能不佳,并且容易产生并发安全问题

方法三

用pl/sql块的returning into语法,用CallableStatement对象设置输出参数取到新插入的值

只要一次sql交互,性能较好

需要采用pl/sql语法,代码不直观,使用较少

方法四

设置PreparedStatement需要返回新值的字段名,然后用getGeneratedKeys取得新插入的值

性能良好,只要一次sql交互

只有Oracle10g才支持,使用较少

方法五

returning into语法,用OraclePreparedStatement对象设置输出参数,再用getReturnResultSet取得新增入的值

性能最好,因为只要一次sql交互,oracle9i也支持

只能使用Oracle jdbc特有的OraclePreparedStatement对象

 
 
### Oracle 数据库序列重置报错问题及获取数据插入行号的方法Oracle 数据库中,当尝试使用 `ALTER SEQUENCE ... RESTART WITH` 语法时,可能会遇到 ORA-00933 错误。此错误表明 SQL 命令未正确结束或语法不被支持。以下内容详细说明了解决方案以及如何获取数据插入的行号。 #### 序列重置报错解决方案 Oracle 数据库中的 `ALTER SEQUENCE` 不支持直接通过 `RESTART WITH` 来重置序列[^1]。需要采取其他方法来实现序列的重置。 #### 方法一:删除并重创建序列 如果可以接受删除现有序列并重创建,则可以通过以下 SQL 语句完成: ```sql -- 删除现有序列 DROP SEQUENCE st_sequence; -- 重创建序列,设置起始为 1 CREATE SEQUENCE st_sequence START WITH 1 INCREMENT BY 1; ``` #### 方法二:手动调整序列 如果不希望删除序列,可以通过修改序列的当前来实现类似效果。以下是具体实现代码: ```sql BEGIN -- 修改序列增量为负 EXECUTE IMMEDIATE 'ALTER SEQUENCE st_sequence INCREMENT BY -1'; -- 消耗多余的增量 SELECT st_sequence.NEXTVAL INTO :dummy FROM dual; -- 消耗掉多余的增量 -- 恢复序列增量为正 EXECUTE IMMEDIATE 'ALTER SEQUENCE st_sequence INCREMENT BY 1'; END; / ``` 这种方法通过将序列的增量临时设置为负,并消耗多余的增量,从而实现序列的重置[^2]。 #### 获取数据插入行号的方法Oracle 中,可以通过以下几种方式获取插入数据的行号: #### 方法一:使用 RETURNING 子句 在插入数据时,可以通过 `RETURNING` 子句获取插入行的主键或其他字段。例如: ```sql DECLARE inserted_id NUMBER; BEGIN INSERT INTO my_table (column1, column2) VALUES ('value1', 'value2') RETURNING id INTO inserted_id; DBMS_OUTPUT.PUT_LINE('Inserted ID: ' || inserted_id); END; / ``` #### 方法二:结合序列和触发器 如果表中存在由序列生成的主键,可以在插入后查询该。例如: ```sql -- 插入数据 INSERT INTO my_table (id, column1, column2) VALUES (my_sequence.NEXTVAL, 'value1', 'value2'); -- 查询刚刚插入的行号 SELECT my_sequence.CURRVAL FROM dual; ``` #### 注意事项 - 如果序列已经被引用(例如作为触发器的一部分),删除和重创建序列可能会导致依赖对象失效。在这种情况下,建议使用方法二。 - 在执行任何修改之前,确保备份相关对象以防止意外数据丢失[^3]。 ```sql -- 备份序列定义 SELECT DBMS_METADATA.GET_DDL('SEQUENCE', 'ST_SEQUENCE') FROM dual; ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值