数据库在insert时,抛出“不支持的特性”异常

数据库为oracle 11g
经测试,发如今定义PreparedStatement 时,若是采用如下方式,会抛此异常.
PreparedStatement stm = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
PreparedStatement stm = conn.prepareStatement(sql,new String[] {"ID"});
经Google后,发现
Oracle的sequence实现很是灵活,因此也带来一些易用性问题,如何取到新插入记录生成的sequence值与其它数据库有较大差异,本文详国介绍了5种实现读取新插入记录sequence值的方法。html

测试用的数据库脚本:
SQL> create table T
     (
     ID NUMBER
    );

    Table created
    SQL> create sequence SEQ_T1;

    Sequence created

    //公共代码:获得数据库链接
    public Connection getConnection() throws Exception{
    Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
    Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1 :1521:dbname", "username", "password");
    return conn;
    }

    //方法一
    //先用select seq_t1.nextval as id from dual 取到新的sequence值。
    //而后将最新的值经过变量传递给插入的语句:insert into t1(id) values(?)
    //最后返回开始取到的sequence值。
    //这种方法的优势代码简单直观,使用的人也最多,缺点是须要两次sql交互,性能不佳。
    public int insertDataReturnKeyByGetNextVal() throws Exception {
    Connection conn = getConnection();
    String vsql = "select seq_t1.nextval as id from dual";
    PreparedStatement pstmt =(PreparedStatement)conn.prepareStatement(vsql);
    ResultSet rs=pstmt.executeQuery();
    rs.next();
    int id=rs.getInt(1);
    rs.close();
    pstmt.close();
    vsql="insert into t1(id) values(?)";
    pstmt =(PreparedStatement)conn.prepareStatement(vsql);
    pstmt.setInt(1, id);
    pstmt.executeUpdate();
    System.out.print("id:"+id);
    return id;
    }

    //方法二
    //先用insert into t1(id) values(seq_t1.nextval)插入数据。
    //而后使用select seq_t1.currval as id from dual返回刚才插入的记录生成的sequence值。
    //注:seq_t1.currval表示取出当前会话的最后生成的sequence值,因为是用会话隔离,只要保证两个SQL使用同一个Connection便可,对于采用链接池应用须要将两个SQL放在同一个事务内才可保证并发安全。
    //另外若是会话没有生成过sequence值,使用seq_t1.currval语法会报错。
    //这种方法的优势能够在插入记录后返回sequence,适合于数据插入业务逻辑很差改造的业务代码,缺点是须要两次sql交互,性能不佳,而且容易产生并发安全问题。
    public int insertDataReturnKeyByGetCurrVal() throws Exception {
    Connection conn = getConnection();
    String vsql = "insert into t1(id) values(seq_t1.nextval)";
    PreparedStatement pstmt =(PreparedStatement)conn.prepareStatement(vsql);
    pstmt.executeUpdate();
    pstmt.close();
    vsql="select seq_t1.currval as id from dual";
    pstmt =(PreparedStatement)conn.prepareStatement(vsql);
    ResultSet rs=pstmt.executeQuery();
    rs.next();
    int id=rs.getInt(1);
    rs.close();
    pstmt.close();
    System.out.print("id:"+id);
    return id;
    }

    //方法三
    //采用pl/sql的returning into语法,能够用CallableStatement对象设置registerOutParameter取得输出变量的值。
    //这种方法的优势是只要一次sql交互,性能较好,缺点是须要采用pl/sql语法,代码不直观,使用较少。
    public int insertDataReturnKeyByPlsql() throws Exception {
    Connection conn = getConnection();
    String vsql = "begin insert into t1(id) values(seq_t1.nextval) returning id into :1;end;";
    CallableStatement cstmt =(CallableStatement)conn.prepareCall ( vsql);
    cstmt.registerOutParameter(1, Types.BIGINT);
    cstmt.execute();
    int id=cstmt.getInt(1);
    System.out.print("id:"+id);
    cstmt.close();
    return id;
    }

    //方法四
    //采用PreparedStatement的getGeneratedKeys方法
    //conn.prepareStatement的第二个参数能够设置GeneratedKeys的字段名列表,变量类型是一个字符串数组
    //注:对Oracle数据库这里不能像其它数据库那样用prepareStatement(vsql,Statement.RETURN_GENERATED_KEYS)方法,这种语法是用来取自增类型的数据。
    //Oracle没有自增类型,所有采用的是sequence实现,若是传Statement.RETURN_GENERATED_KEYS则返回的是新插入记录的ROWID,并非咱们相要的sequence值。
    //这种方法的优势是性能良好,只要一次sql交互,实际上内部也是将sql转换成oracle的returning into的语法,缺点是只有Oracle10g才支持,使用较少。
    public int insertDataReturnKeyByGeneratedKeys() throws Exception {
    Connection conn = getConnection();
    String vsql = "insert into t1(id) values(seq_t1.nextval)";
    PreparedStatement pstmt =(PreparedStatement)conn.prepareStatement(vsql,new String[]{"ID"});
    pstmt.executeUpdate();
    ResultSet rs=pstmt.getGeneratedKeys();
    rs.next();
    int id=rs.getInt(1);
    rs.close();
    pstmt.close();
    System.out.print("id:"+id);
    return id;
    }

    //方法五
    //和方法三相似,采用oracle特有的returning into语法,设置输出参数,可是不一样的地方是采用OraclePreparedStatement对象,由于jdbc规范里标准的PreparedStatement对象是不能设置输出类型参数。
    //最后用getReturnResultSet取到新插入的sequence值,
    //这种方法的优势是性能最好,由于只要一次sql交互,oracle9i也支持,缺点是只能使用Oracle jdbc特有的OraclePreparedStatement对象。
    public int insertDataReturnKeyByReturnInto() throws Exception {
    Connection conn = getConnection();
    String vsql = "insert into t1(id) values(seq_t1.nextval) returning id into :1";
    OraclePreparedStatement pstmt =(OraclePreparedStatement)conn.prepareStatement(vsql);
    pstmt.registerReturnParameter(1, Types.BIGINT);
    pstmt.executeUpdate();
    ResultSet rs=pstmt.getReturnResultSet();
    rs.next();
    int id=rs.getInt(1);
    rs.close();
    pstmt.close();
    System.out.print("id:"+id);
    return id;
    }

以上5种方法均可以实现功能,如下是5种方法的优缺点汇总,我的推荐性能要求通常的业务采用第一种方法,性能要求很是高业务采用第五种方法。sql

以上5种方法均可以实现功能,如下是5种方法的优缺点汇总,我的推荐性能要求通常的业务采用第一种方法,性能要求很是高业务采用第五种方法。数据库

方法数组

简介安全

优势并发

缺点oracle

方法一性能

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

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

须要两次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对象

来源:http://www.360doc.com/content/11/1102/17/1290342_161130566.shtml

相关文章
相关标签/搜索