我有一個 TSQL 程序,在 Azure 的 SQL 上。這是一個最小的可重現示例。
CREATE PROCEDURE MyPROC
AS
BEGIN
BEGIN TRY
SELECT 1/0
END TRY
BEGIN CATCH
UPDATE error_log SET error_desc='test'
END CATCH
END
當直接從 SSMS 運行時,則error_log成功更新。
當從我的 Tomcat 應用程式(使用 Tomcat 用戶)運行時,程式會執行但error_log不會更新。
Tomcat 使用以下 Java 代碼執行該程序
DBConnection dbConn = DBConnection.getInstance();
Connection conn = null;
try {
conn = dbConn.getConnection();
conn.setAutoCommit(false);
CallableStatement stmt = conn.prepareCall("{CALL MyPROC}");
stmt.execute();
result = stmt.getInt(fields.size());
if (result == DBProcedures.RESULT_FAILED) { // error
conn.rollback();
} else { // ok
conn.commit();
}
} catch (SQLException e) {
result = DBProcedures.RESULT_FAILED;
try {
conn.rollback();
} catch (SQLException e1) {
System.out.println("Exception on " this.toString() " " e.toString());
}
System.out.println("Exception on " this.toString() " " e.toString());
} finally {
try {
conn.setAutoCommit(true);
} catch (SQLException e) {
System.out.println("Exception on " this.toString() " " e.toString());
}
dbConn.returnConnection(conn);
}
我已經檢查過 Tomcat 用戶對error_log表有權限。
我錯過了什么?我了解并非所有錯誤都被捕獲,TRY CATCH 并且我了解有時事務無法執行任何會生成寫入操作的 Transact-SQL 陳述句。但是,我的示例似乎不屬于這兩個類別中的任何一個。此外,它確實在 SSMS 下作業。
uj5u.com熱心網友回復:
這是由設定為off的事實引起的auto_commit,這意味著驅動程式執行命令SET IMPLICIT_TRANSACTIONS ON;
您可以在這個 fiddle中看到這一點。
要繞過它,您可以先顯式回滾原始事務。理想情況下,您還應該使用它XACT_ABORT來防止掛起事務,并使用它THROW;來重新拋出原始錯誤。
CREATE PROCEDURE MyPROC
AS
BEGIN
SET XACT_ABORT ON;
BEGIN TRY
SELECT 1/0;
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
ROLLBACK;
UPDATE error_log SET error_desc = 'test';
THROW; -- only if you want the error to propagate back to Tomcat
END CATCH;
END;
老實說,我不建議使用BEGIN CATCH來記錄錯誤,因為并非所有錯誤都可以捕獲。相反,使用 SQL Server 錯誤日志或 XEvent 會話來記錄錯誤。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/507034.html
