带有 ResultSet、返回值和输出参数的 JDBC SQL Server 存储过程

问题描述

我正在将应用程序从 Jython 转换为已编译的 Java。该应用程序使用大量 sql Server 存储过程来执行 CRUD 操作。所有过程都定义了一个指示状态的返回值,以及一些用于向应用程序提供反馈的输出参数。大多数过程还返回一个结果集。我正在苦苦思索如何检索返回值、结果集和输出参数。

我通常使用 C#,因此 JDBC 的细微差别对我来说是新的。我一直在使用对数据库进行插入然后对插入的对象进行选择的过程之一进行测试。

这是一个简化的示例过程仅用于说明目的。实际的程序比这更复杂。

CREATE PROCEDURE [dbo].[sp_Thing_Add]
(
   @Name NVARCHAR(50),@Description NVARCHAR(100),@ResultMessage NVARCHAR(200) = N'' OUTPUT
)
AS
BEGIN
   SET NOCOUNT ON
   
   DECLARE @Result INT = -1
   DECLARE @ResultMessage = 'Procedure incomplete'
   
   BEGIN TRY
      INSERT INTO Things (Name,Description) VALUES (@Name,@Description)

      SELECT * FROM Things WHERE ThingID = ScopE_IDENTITY()
   END TRY
   BEGIN CATCH
      SELECT @Result = CASE WHEN ERROR_NUMBER() <> 0 THEN ERROR_NUMBER() ELSE 1 END,@ResultMessage = ERROR_MESSAGE()
      GOTO EXIT_SUB
   END CATCH
SUCCESS:
   SET @Result = 0
   SET @ResultMessage = N'Procedure completed successfully'
   RETURN @Result
EXIT_SUB:
   IF @Result <> 0
   BEGIN
   -- Do some error handling stuff
   END
   RETURN @Result

      

我可以使用以下代码成功检索 ResultSet。

var conn = myConnectionProvider.getConnection();
String sql = "{? = call dbo.sp_Thing_Add(?,?,?)}"

call = conn.prepareCall(sql);
call.registerOutParameter(1,TYPES.Integer); // Return value
call.setString("Name",thing.getName());
call.setString("Description",thing.getDescription());
call.registerOutParameter("ResultMessage",TYPES.NVARCHAR);
ResultSet rs = call.executeQuery();

// Try to get the return value. This appears to close the ResultSet and prevents data retrieval.
//int returnValue = call.getInt(1);
// normally there'd be a check here to make sure things executed properly,// and if necessary the output parameter(s) may also be Leveraged

if (rs.next()) {
   thing.setId(rs.getLong("ThingID"));
   // Other stuff actually happens here too...
}

如果我尝试使用注释掉的行检索返回值,我会收到一条错误消息,指出 ResultSet 已关闭

com.microsoft.sqlserver.jdbc.sqlServerException: 结果集已关闭

我已经阅读了文档并了解了如何处理返回值、输出参数和结果集。但我如何才能充分利用这 3 个因素?

解决方法

输出在从 ResultSet rs 检索的 executeQuery() 中。

您可能希望使用 excute 方法:

    call.execute();
    String returnValue = call.getString("ResultMessage");

您还希望正确映射到输出类型。

,

执行查询后,您的连接已关闭。基本上 mysql jdbc 连接隐式扩展到 AutoCloseable。由于您的结果只是过程中的实体,请通过索引 0 获取值并进行适当的索引越界异常处理。