當我們在JDBC中執行一個存儲過程時,我們得到一系列零或多個「結果」。然後我們可以通過調用CallableStatement#getMoreResults()
來順序處理這些「結果」。每一個「結果」可能包含
- 行,我們可以用一個
ResultSet
對象中檢索數據,
- 的DML語句(INSERT,UPDATE,DELETE),我們可以用
CallableStatement#getUpdateCount()
,或 檢索更新計數
- 引發SQLServerException的錯誤。
對於「問題1」,問題通常是存儲過程不是以SET NOCOUNT ON;
開頭,並在執行SELECT之前執行DML語句以生成結果集。 DML的更新計數作爲第一個「結果」返回,並且數據行「卡在它後面」,直到我們調用getMoreResults
。
「問題2」基本上是同樣的問題。在發生錯誤之前,存儲過程會生成一個「結果」(通常是一個SELECT,或者可能是一個更新計數)。該錯誤將在後續的「結果」中返回,並且在使用getMoreResults
「檢索」它之前不會導致異常。
在許多情況下,只需將SET NOCOUNT ON;
作爲存儲過程中的第一個可執行語句添加即可避免此問題。但是,更改了存儲過程並不總是可能的,但事實是,爲了得到一切從存儲過程前,我們需要不斷的打電話getMoreResults
最後,到了Javadoc中說:
There are no more results when the following is true:
// stmt is a Statement object
((stmt.getMoreResults() == false) && (stmt.getUpdateCount() == -1))
那聽起來很簡單,但像往常一樣,「魔鬼在細節中」,如下面的例子所示。對於SQL Server存儲過程...
ALTER PROCEDURE dbo.TroublesomeSP AS
BEGIN
-- note: no `SET NOCOUNT ON;`
DECLARE @tbl TABLE (id VARCHAR(3) PRIMARY KEY);
DROP TABLE NonExistent;
INSERT INTO @tbl (id) VALUES ('001');
SELECT id FROM @tbl;
INSERT INTO @tbl (id) VALUES ('001'); -- duplicate key error
SELECT 1/0; -- error _inside_ ResultSet
INSERT INTO @tbl (id) VALUES ('101');
INSERT INTO @tbl (id) VALUES ('201'),('202');
SELECT id FROM @tbl;
END
...下面的Java代碼將返回一切......
try (CallableStatement cs = conn.prepareCall("{call dbo.TroublesomeSP}")) {
boolean resultSetAvailable = false;
int numberOfResultsProcessed = 0;
try {
resultSetAvailable = cs.execute();
} catch (SQLServerException sse) {
System.out.printf("Exception thrown on execute: %s%n%n", sse.getMessage());
numberOfResultsProcessed++;
}
int updateCount = -2; // initialize to impossible(?) value
while (true) {
boolean exceptionOccurred = true;
do {
try {
if (numberOfResultsProcessed > 0) {
resultSetAvailable = cs.getMoreResults();
}
exceptionOccurred = false;
updateCount = cs.getUpdateCount();
} catch (SQLServerException sse) {
System.out.printf("Current result is an exception: %s%n%n", sse.getMessage());
}
numberOfResultsProcessed++;
} while (exceptionOccurred);
if ((!resultSetAvailable) && (updateCount == -1)) {
break; // we're done
}
if (resultSetAvailable) {
System.out.println("Current result is a ResultSet:");
try (ResultSet rs = cs.getResultSet()) {
try {
while (rs.next()) {
System.out.println(rs.getString(1));
}
} catch (SQLServerException sse) {
System.out.printf("Exception while processing ResultSet: %s%n", sse.getMessage());
}
}
} else {
System.out.printf("Current result is an update count: %d %s affected%n",
updateCount,
updateCount == 1 ? "row was" : "rows were");
}
System.out.println();
}
System.out.println("[end of results]");
}
...產生以下控制檯輸出:
Exception thrown on execute: Cannot drop the table 'NonExistent', because it does not exist or you do not have permission.
Current result is an update count: 1 row was affected
Current result is a ResultSet:
001
Current result is an exception: Violation of PRIMARY KEY constraint 'PK__#314D4EA__3213E83F3335971A'. Cannot insert duplicate key in object '[email protected]'. The duplicate key value is (001).
Current result is a ResultSet:
Exception while processing ResultSet: Divide by zero error encountered.
Current result is an update count: 1 row was affected
Current result is an update count: 2 rows were affected
Current result is a ResultSet:
001
101
201
202
[end of results]
相關:http://stackoverflow.com/questions/14213824/java-sql-statement-hasresultset和http://stackoverflow.com/questions/24694442/expecting-multiple- resultsets-but-only-get-one和http://stackoverflow.com/questions/32561550/jdbc-sql-server-raised-error-handling-in-multi-statement-stored-procedures –