Wenn wir eine gespeicherte Prozedur in JDBC ausführen, erhalten wir eine Reihe von null oder mehr "Ergebnisse". Wir können diese "Ergebnisse" dann sequentiell verarbeiten, indem wir CallableStatement#getMoreResults()
aufrufen. Jedes „Ergebnis“ kann enthalten
- Reihen von Daten, die wir mit einem
ResultSet
Objekt,
- eine Aktualisierungszählwert für eine DML-Anweisung abrufen können (INSERT, UPDATE, DELETE), die wir mit
CallableStatement#getUpdateCount()
abrufen können, oder
- ein Fehler, der eine SQLServerException auslöst.
Für „Ausgabe 1“ das Problem ist oft, dass die gespeicherte Prozedur beginnt nicht mit SET NOCOUNT ON;
und führt eine DML-Anweisung, bevor Sie eine SELECT tun eine Ergebnismenge zu erzeugen. Die Aktualisierungsanzahl für die DML wird als erstes "Ergebnis" zurückgegeben, und die Datenzeilen bleiben "festgefahren", bis wir getMoreResults
aufrufen.
"Problem 2" ist im Wesentlichen das gleiche Problem. Die gespeicherte Prozedur erzeugt ein "Ergebnis" (normalerweise eine SELECT- oder möglicherweise eine Aktualisierungsanzahl), bevor der Fehler auftritt. Der Fehler wird in einem nachfolgenden "Ergebnis" zurückgegeben und verursacht keine Ausnahme, bis wir ihn mit getMoreResults
"abrufen".
In vielen Fällen kann das Problem durch einfaches Hinzufügen SET NOCOUNT ON;
als erste ausführbare Anweisung in der gespeicherten Prozedur vermieden werden. Allerdings ist eine Änderung der gespeicherten Prozedur nicht immer möglich, und die Tatsache bleibt, dass, um alles zurück aus der gespeicherten Prozedur erhalten wir getMoreResults
bis anrufen, halten müssen wie die Javadoc sagt:
There are no more results when the following is true:
// stmt is a Statement object
((stmt.getMoreResults() == false) && (stmt.getUpdateCount() == -1))
That klingt einfach genug, aber wie immer "der Teufel steckt im Detail", wie das folgende Beispiel zeigt. Bei einer SQL Server gespeicherte Prozedur ...
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
... der folgende Java-Code wird alles zurückgeben ...
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]");
}
...Herstellung der folgenden Konsolenausgabe:
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]
Verwandte: http://stackoverflow.com/questions/14213824/java-sql-statement-hasresultset und http://stackoverflow.com/questions/24694442/expecting-multiple- resultsets-but-only-get-one und http://stackoverflow.com/questions/32561550/jdbc-sql-server-raised-error-handling-in-multi-statement-stored-procedures –