我发现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。
2条答案
按热度按时间sshcrbum1#
谢谢 你
我 开始 发布 Github 问题 , 他们 请求 的 输出 之 一 是 JDBC 跟踪 。
当 我 这样 做 并 比较 2 个 跟踪 输出 时 :
1.唯一 键 冲突
1.除以 零 错误
" 除以 零 " 测试 用例 显示 了 以下 行 :
在 另 一篇 文章 中 读 到 , 当 SP 返回 结果 集 时 , RAISERROR 的 行为 会 有所 不同 ( 在 我 的 例子 中 是 无意 的 ) , 我 在 * * uspTestRE * * 存储 过程 中 更改 了 以下 代码 :
中 的 每 一 个
至
格式
这 解决 了 我 的 问题 。
现在 , 我 只 需要 确定 要 对 在 存储 过程 中 返回 结果 集 的 错误 进行 哪些 更改
6jygbczu2#
您 可以 使用 ' set nocount on ' 来 取代 将 select 变更 为 set