【问题标题】:Call a stored procedure that do both select and update调用同时执行选择和更新的存储过程
【发布时间】:2013-11-11 17:33:16
【问题描述】:

我正在使用 Spring 框架 SimpleJdbcTemplate 从我的 Java 代码中调用存储过程 (SQL-Server)。

对于执行一些更新/插入的存储过程,我调用simpleJdbcTemplate.update(...),对于仅选择的存储过程,我调用simpleJdbcTemplate.query(...)。两者都可以正常工作。

现在,我有一个存储过程,它首先进行一些更新并在最后运行一个选择查询。

我想知道如何调用这个存储过程?

我已尝试simpleJdbcTemplate.query(...) 并得到错误代码 0。我不确定我的存储过程中是否有更新是问题。

更新 这是我从 java 代码调用时的堆栈:

PreparedStatementCallback; uncategorized SQLException for SQL [EXEC NotificationAlertHourlyReport ?, ?, ?, ?];
SQL state [null]; error code [0]; 
The statement did not return a result set.; nested exception is 
com.microsoft.sqlserver.jdbc.SQLServerException: The statement did not return a result set.
org.springframework.jdbc.UncategorizedSQLException: PreparedStatementCallback; 
uncategorized SQLException for SQL [EXEC NotificationAlertHourlyReport ?, ?, ?, ?]; 
SQL state [null]; error code [0]; The statement did not return a result set.;
nested exception is com.microsoft.sqlserver.jdbc.SQLServerException: The statement did not return a result set.
        at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslat
or.translate(AbstractFallbackSQLExceptionTranslator.java:83)
        at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslat
or.translate(AbstractFallbackSQLExceptionTranslator.java:80)
        at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslat
or.translate(AbstractFallbackSQLExceptionTranslator.java:80)
        at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:602)
        at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:636)
        at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:665)
        at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:673)
        at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:713)
        at org.springframework.jdbc.core.simple.SimpleJdbcTemplate.query(SimpleJdbcTemplate.java:200)
        at com.test.MYCLASS.myMethod(Unknown Source)
        at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
        at java.util.concurrent.FutureTask.run(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: The statement did no
t return a result set.
        at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDriverError(S
QLServerException.java:171)
        at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.doExecutePrep
aredStatement(SQLServerPreparedStatement.java:394)
        at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement$PrepStmtExecC
md.doExecute(SQLServerPreparedStatement.java:340)
        at com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:4575)
        at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLSe
rverConnection.java:1400)
        at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeCommand(SQLSer
verStatement.java:179)
        at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeStatement(SQLS
erverStatement.java:154)
        at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.executeQuery(
SQLServerPreparedStatement.java:283)
        at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeQuery(NewPr
oxyPreparedStatement.java:76)
        at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(Jd
bcTemplate.java:643)
        at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:
586)
        ... 13 more

【问题讨论】:

  • 存储过程在你的 spring 应用程序之外是否正常工作?
  • 是的,经过测试。我唯一关心的存储过程没有输出。它只是在最后一行中选择了一些东西。
  • proc 是否返回 null?
  • 是的,从应用程序中,我得到:SQL state [null]
  • 但是你确定存储过程正在返回一些东西吗?是否返回输出参数?

标签: sql sql-server spring stored-procedures spring-jdbc


【解决方案1】:

只要 SQL Server sproc 实际工作没有错误并返回数据,它也可能执行更新应该没有任何后果(我会确保 sproc 首先进行更新并以选择)。如果是这种情况,那么 simpleJdbcTemplate.query(...) 应该做的伎俩。我不知道它是否在检查行数,但您可以在 sproc 的开头使用 SET NOCOUNT ON / OFF 语句,看看这是否使 java 调用满意。

【讨论】:

  • 我有一个存储过程,它创建了一个临时表,运行一个查询,做了一堆插入然后调用另一个存储过程来运行另一个使用临时表的查询。在查询开始时执行 SET NOCOUNT ON 之前,我无法让它将结果集返回给 java。
【解决方案2】:

如果您的 SQL 由 Statement 或其任何子类(即PreparedStatementCallableStatement)执行,其中包含多个 SQL 语句(可以是 INSERT/UPDATE/DELETE/SELECT),您应该使用语句上的execute() 方法来执行此类SQL,然后调用getMoreResults 浏览响应以执行SQL 中的每个语句。

例如

假设您的 SQL 中包含以下语句:

UPDATE ....
SELECT ....

那么您的代码将如下所示:

// Create statement or prepare the call.
boolean result = stmt.execute();
// result will be false here indicating that the first result is an update count.
int updateCount = stmt.getUpdateCount();
result = stmt.getMoreResults();
// result will be true here indicating that the next result is a ResultSet.
ResultSet rs = stmt.getResultSet();

顺便说一句,尽管文档说对 getMoreResults() 的调用关闭了先前打开的 ResultSet 对象,但它似乎依赖于驱动程序,并且显式关闭这些 ResultSet 以避免资源泄漏是安全的。

// JDK 7 provides try-with-resources that takes care of closing the resources.
try (ResultSet rs = stmt.getResultSet()) {

}

【讨论】:

    【解决方案3】:

    [...] 选择和更新

    SQL2005+: 您可以使用OUTPUT clause 执行 UPDATE 语句并返回(在同一语句中)受影响的行:

    UPDATE dbo.TargetTable
    SET TargetColumn = NewValue
    OUTPUT inserted.ID, inserted.TargetColumn, deleted.TargetColumn /*INTO table1 | @table2 | #table3*/
    --                      ^ new value           ^ old value     
    WHERE ...
    

    【讨论】:

      猜你喜欢
      • 2011-10-11
      • 2021-09-25
      • 1970-01-01
      • 1970-01-01
      • 2017-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多