与 Statement.RETURN_GENERATED_KEYS 一起使用时 PreparedStatement 出现问题

Posted

技术标签:

【中文标题】与 Statement.RETURN_GENERATED_KEYS 一起使用时 PreparedStatement 出现问题【英文标题】:Issue with PreparedStatement while using with Statement.RETURN_GENERATED_KEYS 【发布时间】:2018-02-12 07:14:33 【问题描述】:

当我尝试将 PreparedStatement 与 Statement.RETURN_GENERATED_KEYS 一起使用时,我不知道为什么 PreparedStatement 对象需要额外的参数。我已经用谷歌搜索了所有可能的字符串,但没有得到任何回应。

下面是我用来插入记录的代码。

StringBuilder headerSql = new StringBuilder();
headerSql.append("insert into TABLE_XXX(subscriber_id,company_id,stg_inv_id,inv_loc_id,count_date,count_status,count_type,creation_user,creation_date,update_user,update_date) \n");
headerSql.append("(select ?,?,XXXX_PK.NEXTVAL,?,sysdate,0,0,?,sysdate,?,sysdate from dual \n");
headerSql.append("where not exists(select 1 from TABLE_XXX where subscriber_id=? and company_id=? and inv_loc_id=? and count_status=0 and count_type=0)) \n"); 
String stgInvId=null; 
PreparedStatement ps = null;
ResultSet rs = null;
try            
    ps = con.prepareStatement(headerSql.toString(), Statement.RETURN_GENERATED_KEYS);
    ps.setString(1,Integer.toString(IDObj.getSubscriberID()));
    ps.setString(2,Integer.toString(IDObj.getCompanyID()));
    ps.setString(3,locId);
    ps.setString(4,IDObj.getUserLogin());
    ps.setString(5,IDObj.getUserLogin());
    ps.setString(6,Integer.toString(IDObj.getSubscriberID()));
    ps.setString(7,Integer.toString(IDObj.getCompanyID()));
    ps.setString(8,locId);
    ps.executeUpdate();
    rs = ps.getGeneratedKeys();
    rs.next();
    stgInvId=rs.getString("stg_inv_id");
 catch (Exception e)                  
    System.out.println(headerSql.toString());
    e.printStackTrace();            

下面是绑定的参数列表:

正如您在上面看到的,我现在没有从哪里添加最后一个参数以及我需要在这里传递什么值。请各位大侠指导一下。

下面是堆栈跟踪:

java.sql.SQLException: ORA-00933: SQL command not properly ended

    at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:111)
    at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:330)
    at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:287)
    at oracle.jdbc.driver.T4C8Oall.receive(T4C8Oall.java:742)
    at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:212)
    at oracle.jdbc.driver.T4CPreparedStatement.executeForRows(T4CPreparedStatement.java:951)
    at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1159)
    at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3284)
    at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:3367)
    at com.birchstreet.synergy.countmanagement.dao.CountManagementDAOImpl.inserStgHeader(CountManagementDAOImpl.java:325)
    at com.birchstreet.synergy.countmanagement.dao.CountManagementDAOImpl.inserStgRecord(CountManagementDAOImpl.java:280)
    at com.birchstreet.webservices.synergy.WSCountManagement.setLocationsInStartInventory(WSCountManagement.java:138)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:143)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:160)
    at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:158)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:97)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102)
    at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:303)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
    at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:286)
    at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1072)
    at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:399)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:381)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:344)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:221)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:624)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

【问题讨论】:

你能分享异常的确切文本和堆栈跟踪吗? 您使用的是哪个数据库产品和 JDBC 驱动程序(版本)? parameterString 变量的声明和用法在哪里? 添加了 Stacktrace,我正在使用 Oracle JDBC 驱动程序,即返回 T4CPreparedStatement 的 OJDBC6 这与生成的密钥完全无关。 executeUpdate() 正在抛出错误。查看堆栈跟踪。 @EJP 它与生成的密钥有关,因为当我删除该子句时,插入查询执行没有任何问题。而且 parameterString 仅在这种情况下才具有一个额外的值。在否决任何答案或问题之前,请仔细阅读或做一些研究。 【参考方案1】:

在 oracle DB RETURN_GENERATED_KEYS 中以这种方式工作。

1) RETURN_GENERATED_KEYS 标志

PreparedStatement ps = con.prepareStatement("INSERT INTO XXX(  A, B) VALUES ( xxx_s.nextval, 'aaa')",Statement.RETURN_GENERATED_KEYS);      
    ps.executeUpdate();        
    ResultSet      rs = ps.getGeneratedKeys();
    while(rs.next()) 
        System.out.println(rs.getString(1));
    

Oracle 不知道哪个列是自动生成的,它正在返回 rowidreturning rowid into :? 附加到插入

2) 列列表。

PreparedStatement ps = con.prepareStatement("INSERT INTO XXX(  A, B) VALUES ( xxx_s.nextval, 'aaa')",new String[]"A");        
        ps.executeUpdate();        
        ResultSet      rs = ps.getGeneratedKeys();
        while(rs.next()) 
            System.out.println(rs.getString(1));
        
        con.close();

在这种情况下,我们明确指定自动生成的列。 returning a into :? 附加到插入

在这两种情况下,您都必须使用位置访问来访问生成的列。不支持按列名访问。

但是您正在尝试做 insert as select 。语句被转换为

insert into xxxy  select * from xxxy returning rowid into :var ; 

并且oracle db不支持此语句。还有异常ORA-00933: SQL command not properly ended is raised

【讨论】:

你是对的,当我将插入查询更改为不使用 select 子句时,它执行得很好,你的第二点也是正确的,它返回 rowid。但是有什么方法可以让我为该行插入序列值? 您可以在 pl sql 块中使用bulk collectforall statements 实现此目的。但这个解决方案不是一个简单的查询。 我设法通过在 prepareStatement 中传递列名和我已经完成的另一件事,即将 ojdbc6 更新为 11.2.0.3 来为我工作

以上是关于与 Statement.RETURN_GENERATED_KEYS 一起使用时 PreparedStatement 出现问题的主要内容,如果未能解决你的问题,请参考以下文章

=与==&与&&| 与 || 的区别

与 0 进行比较与与某个值进行比较是不是更快?

三.工具与市场-债券与债务股票与公司

RESTfulREST 与 RESTful 理解与实践

RESTfulREST 与 RESTful 理解与实践

RESTfulREST 与 RESTful 理解与实践