繁体   English   中英

为什么 TRY CATCH 成功更新 SSMS 上的行,但从 Tomcat 应用程序运行时却没有?

[英]Why does TRY CATCH successfully update rows on SSMS but not when run from Tomcat application?

我有一个 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 下工作。

这是由于auto_commit设置为 off 造成的,这意味着驱动程序执行命令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 服务器错误日志或 XEvent session 来记录错误。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM