SQL Server RAISERROR -Java客户端中SQLException行为的差异

bttbmeg0  于 2022-11-21  发布在  Java
关注(0)|答案(2)|浏览(110)

我发现Java在处理RAISERROR引发的SQL Server错误时会有不同的行为,具体取决于实际的错误是什么,具体表现在:

  • 唯一约束冲突:SQL异常由Java Catch块捕获和处理
  • 除以零:未捕获SQL异常错误

为了证明:

1.存储过程:usp测试RE

ALTER PROCEDURE demo.uspTestRE (
  @inKey    VARCHAR(5),    --Primary Key value in TestRE table
  @inDBZ    VARCHAR(1)     --Y/N flag to trigger Divide By Zero error
)
AS
BEGIN

  SET XACT_ABORT, NOCOUNT ON;

  BEGIN TRY
    BEGIN TRANSACTION

      --Insert record into TestRE table
      INSERT INTO TestRE (tREKey) VALUES (@inKey);

      --Trigger DBZ error
      IF @inDBZ = 'Y'
       BEGIN
         SELECT 1/0;
       END;

    --Transaction is in a state to be committed
    IF (XACT_STATE())=1
      BEGIN
        COMMIT TRANSACTION;
      END;
  END TRY

  BEGIN CATCH
    DECLARE
      @errorMessage  NVARCHAR(MAX) = ERROR_MESSAGE(),
      @errorState    INT           = ERROR_STATE(),
      @errorSeverity INT           = ERROR_SEVERITY();

    --Transaction is uncommitable so rollback
    IF (XACT_STATE()) = -1
      BEGIN
        ROLLBACK TRANSACTION;
      END;

    RAISERROR(@errorMessage,@errorSeverity,@errorState);

    RETURN 23;
  END CATCH

END;

从SQLCMD执行SP时,会产生下列错误消息:
测试1:密钥冲突

Msg 50000, Level 14, State 1, Server WW-HV5FQV2, Procedure demo.uspTestRE, Line 44
Violation of PRIMARY KEY constraint 'PK__TestRE__0FEE01A3EEF4E2AE'. Cannot insert duplicate key in object 'dbo.TestRE'. The duplicate key value is (UKV).

测试2:除以零

Msg 50000, Level 16, State 1, Server WW-HV5FQV2, Procedure demo.uspTestRE, Line 42
Divide by zero error encountered.

即两者的预期行为。
然而,我的Java程序没有给予同样的行为。

**2. Java程序:uspTestRE.java

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.CallableStatement;

public class uspTestRE {

    // Connect to DEMO_INST database as svcDemoInst Login
    public static void main(String[] args) {
        String connectionUrl =
                "jdbc:sqlserver://localhost:1433;"
                + "database=DEMO;"
                + "user=svcDemoLogin;"
                + "password=Demo;"
                + "trustServerCertificate=true;"
                + "loginTimeout=30;";

        ResultSet resultSet = null;
        CallableStatement cstmt = null;

        try {cstmt = DriverManager.getConnection(connectionUrl).prepareCall("{? = call demo.uspTestRE(?,?)}");
             int i = 0;
             cstmt.registerOutParameter(++i,java.sql.Types.INTEGER);

             cstmt.setString(++i,args[0]);
             cstmt.setString(++i,args[1]);
             cstmt.execute();

             int returnCode = cstmt.getInt(1);
             System.out.println("Success: Stored Procedure Return Status: " + returnCode);
        }
        catch (SQLException e) {
              System.out.println("Error Code: " + e.getErrorCode() +", Error Message: "+e.getMessage());
              // e.printStackTrace();
        }
    }
}

当我在这里运行相同的测试用例时,我得到以下结果:
测试1:密钥冲突(按预期行为)

C:\>java uspTestRE UKV N
Error Code: 50000, Error Message: Violation of PRIMARY KEY constraint 'PK__TestRE__0FEE01A3EEF4E2AE'. Cannot insert duplicate key in object 'dbo.TestRE'. The duplicate key value is (UKV).

测试2:除以零(不陷印)

C:\>java uspTestRE DBV Y
Success: Stored Procedure Return Status: 23

有人能向我解释一下为什么Java代码没有捕获“除以零”错误(该错误在SQL Server中捕获并在SP Catch块中处理)吗?
我能看到的2个错误之间的唯一区别是“除以零”错误的严重性为16。

sshcrbum

sshcrbum1#

谢谢 你
我 开始 发布 Github 问题 , 他们 请求 的 输出 之 一 是 JDBC 跟踪 。
当 我 这样 做 并 比较 2 个 跟踪 输出 时 :
1.唯一 键 冲突
1.除以 零 错误
" 除以 零 " 测试 用例 显示 了 以下 行 :

      • 2020 年 6 月 10 日 下午 5 点 28 分 50 秒
      • 精细 : SQL 服务 器 结果 集 : 1 由 ( SQL 服务 器 可 调用 语句 : 1 ) 创建 * *

在 另 一篇 文章 中 读 到 , 当 SP 返回 结果 集 时 , RAISERROR 的 行为 会 有所 不同 ( 在 我 的 例子 中 是 无意 的 ) , 我 在 * * uspTestRE * * 存储 过程 中 更改 了 以下 代码 :

IF @inDBZ = 'Y'
  BEGIN
    SELECT 1/0;
  END;

中 的 每 一 个

IF @inDBZ = 'Y'
  BEGIN
    SET @dbz = 1/0;
  END;

格式
这 解决 了 我 的 问题 。
现在 , 我 只 需要 确定 要 对 在 存储 过程 中 返回 结果 集 的 错误 进行 哪些 更改

6jygbczu

6jygbczu2#

您 可以 使用 ' set nocount on ' 来 取代 将 select 变更 为 set

相关问题