通过JDBC获取刚插入的SEQUENCE值

使用SEQUENCE作为表的主键是一个很常见的方法,在程序处理过程中,常常需要获取刚插入的序列值,如果是PL/SQL就很简单了,直接使用currval返回即可,在jdbc中则需要一点特别的代码来处理。先创建一个表及序列如下:


create table seqtest(i int);
create sequence seq start with 1;

插入及获取插入值的代码片段如下:


Connection con = getConnection();
PreparedStatement pst = con.prepareStatement("insert into seqtest(i) values(seq.nextval) ",new String[] { "i" });
pst.executeUpdate();
Result rst = pst.getGeneratedKeys;
rst.next();
int value = rst.getBigDecimal(1);


这样就得到了通过seq序列插入到数据库中的值。上面这段代码和oracle官方文档(JDBC Developer's Guide)中的写法是一致的。但我们注意到,Connection的prepareStatement方法实际上有6种不同的形式:

1. prepareStatement(String sql)

2. prepareStatement(String sql, int resultSetType, int resultSetConcurrency) 

3. prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)

4. prepareStatement(String sql, String[] columnNames) 

5. prepareStatement(String sql, int[] columnIndexes) 

6. prepareStatement(String sql, int autoGeneratedKeys) 


第四种就是刚才我们使用的形式。经过测试,并非所有的prepareStatement方法都能获得返回值,1、2、3能正确插入记录,但在调用getGeneratedKeys方法时将抛出异常: java.sql.SQLException:operation not allowed.  4、5能正确获取返回值(如果是形式5,第二个参数是自动插入列的序号,对上例来说是new int[]{1})。

这里着重说明一下6,第二个参数的取值范围是Statement.RETURN_GENERATED_KEYS 或者Statement.NO_GENERATED_KEYS。从javadoc和字面上来看,当第二个参数传值Statement.RETURN_GENERATED_KEYS时6应该也能正确获取返回值才对(如果是Statement.NO_GENERATED_KEYS则效果等同123),但对于oracle jdbc来说,如果使用6的形式,的确有返回值,getGeneratedKeys方法也不会抛出异常,但这个结果集里面并非我们刚刚插入的序列号值,而是刚插入记录的ROWID。所以当调用getBigDecimal时将发生错误。oracle这么处理的原因是,采用形式6的时候,oracle并不知道哪个列使用了自动生成的值,实际上自动生成的值的列可以有多个,所以最稳妥的办法是返回刚插入记录的ROWID,可以进一步通过ROWID获取所插入的记录。


oracle  jdbc在处理返回值的时候,实际上根本不关心这个值是不是真的自动生成的,如果使用一个常数替代seq.nextval,同样能得到这个常数的值,所以对于sequence来说,oracle jdbc根本没有使用seq.currval来获取值。在oracle jdbc内部,是通过在原始sql后面拼上returning 子句来完成这个功能的,以上面的例子来说,实际执行的sql其实是insert into seqtest(i)  values(seq.nextval) returning i into :1 这样的形式。所以无论是sequence,sys_guid()还是常量,都能返回值。对于上述形式6,如果传入参数是Statement.RETURN_GENERATED_KEYS的话,oracle jdbc内部是这样的处理逻辑:

this.newSql = (this.originalSql + " RETURNING ROWID INTO " + (this.useNamedParameter ? generateUniqueNamedParameter() : Character.valueOf('?')));
        

因此返回的是ROWID而不是插入的值。(上面的代码位于oracle.jdbc.driver.AutoKeyInfo类里)

实际上如果使用oracle特定的类,可以自己使用returning语句来完成同样的功能:

OraclePreparedStatement opst = (OraclePreparedStatement)con.prepareStatement
				("insert into  seqtest(i) values(seq.nextval) returning i into ?");
		
		opst.registerReturnParameter(1, Types.INTEGER);
		opst.executeUpdate();
		ResultSet rst = opst.getReturnResultSet();
		rst.next();
		int value = rst.getInt(1);

这里需要注意的是不能使用getGeneratedKeys方法,必须使用getReturnResultSet来获取返回值。




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值