与 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 不知道哪个列是自动生成的,它正在返回 rowid
。 returning 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 collect
和forall statements
实现此目的。但这个解决方案不是一个简单的查询。
我设法通过在 prepareStatement 中传递列名和我已经完成的另一件事,即将 ojdbc6 更新为 11.2.0.3 来为我工作以上是关于与 Statement.RETURN_GENERATED_KEYS 一起使用时 PreparedStatement 出现问题的主要内容,如果未能解决你的问题,请参考以下文章