Ketika kami menjalankan prosedur tersimpan di JDBC, kami mendapatkan kembali serangkaian "hasil" nol atau lebih. Kami kemudian dapat memproses "hasil" tersebut secara berurutan dengan memanggil CallableStatement#getMoreResults()
. Setiap "hasil" dapat berisi
- nol atau lebih baris data yang dapat kita ambil dengan
ResultSet
objek, - jumlah pembaruan untuk pernyataan DML (INSERT, UPDATE, DELETE) yang dapat kita ambil dengan
CallableStatement#getUpdateCount()
, atau - kesalahan yang memunculkan SQLServerException.
Untuk "Masalah 1" masalahnya sering kali prosedur tersimpan tidak dimulai dengan SET NOCOUNT ON;
dan mengeksekusi pernyataan DML sebelum melakukan SELECT untuk menghasilkan kumpulan hasil. Jumlah pembaruan untuk DML dikembalikan sebagai "hasil" pertama, dan baris data "terjebak di belakangnya" hingga kita memanggil getMoreResults
.
"Masalah 2" pada dasarnya adalah masalah yang sama. Prosedur tersimpan menghasilkan "hasil" (biasanya SELECT, atau mungkin hitungan pembaruan) sebelum kesalahan terjadi. Kesalahan dikembalikan dalam "hasil" berikutnya dan tidak menyebabkan pengecualian sampai kami "mengambilnya" menggunakan getMoreResults
.
Dalam banyak kasus, masalah dapat dihindari hanya dengan menambahkan SET NOCOUNT ON;
sebagai pernyataan yang dapat dieksekusi pertama dalam prosedur tersimpan. Namun, perubahan pada prosedur tersimpan tidak selalu memungkinkan dan faktanya tetap bahwa untuk mendapatkan semuanya kembali dari prosedur tersimpan kita harus terus memanggil getMoreResults
sampai, seperti yang dikatakan Javadoc:
There are no more results when the following is true:
// stmt is a Statement object
((stmt.getMoreResults() == false) && (stmt.getUpdateCount() == -1))
Kedengarannya cukup sederhana tetapi seperti biasa, "setan ada di dalam detail", seperti yang diilustrasikan oleh contoh berikut. Untuk prosedur tersimpan 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
... kode Java berikut akan mengembalikan semuanya ...
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]");
}
... menghasilkan keluaran konsol berikut:
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]