如何使用 JDBC 从存储过程中获取*所有内容*

2023-12-22

当使用 JDBC 处理 SQL Server 存储过程时,我偶尔会遇到两种奇怪的行为:

Issue 1:我在 SQL Server Management Studio (SSMS) 中运行一个存储过程,它返回一个结果集。然而,当我尝试

try (CallableStatement cs = conn.prepareCall("{call dbo.TroublesomeSP}")) {
    ResultSet rs = cs.executeQuery();

我得到了例外

com.microsoft.sqlserver.jdbc.SQLServerException:该语句未返回结果集。

Issue 2:我在 SSMS 中运行一个存储过程,它引发了一个错误,但是当我使用 JDBC 来.execute存储过程没有抛出异常。

为什么会出现这些问题以及如何避免它们?


当我们在 JDBC 中执行存储过程时,我们会返回一系列零个或多个“结果”。然后我们可以通过调用顺序处理这些“结果”CallableStatement#getMoreResults()。每个“结果”可以包含

  • 我们可以使用以下命令检索零行或多行数据ResultSet object,
  • 我们可以检索的 DML 语句(INSERT、UPDATE、DELETE)的更新计数CallableStatement#getUpdateCount(), or
  • 引发 SQLServerException 的错误。

对于“问题 1”,问题通常是存储过程不以SET NOCOUNT ON;并在执行 SELECT 之前执行 DML 语句以生成结果集。 DML 的更新计数作为第一个“结果”返回,并且数据行“卡在它后面”,直到我们调用getMoreResults.

“问题2”本质上是同样的问题。存储过程在错误发生之前生成一个“结果”(通常是一个 SELECT,或者可能是一个更新计数)。该错误在后续“结果”中返回,并且在我们使用“检索”它之前不会导致异常getMoreResults.

在许多情况下,只需添加即可避免该问题SET NOCOUNT ON;作为存储过程中的第一个可执行语句。然而,对存储过程的更改并不总是可能的,事实仍然是为了获得一切从存储过程返回我们需要继续调用getMoreResults直到,正如 Javadoc 所说:

There are no more results when the following is true: 

     // stmt is a Statement object
     ((stmt.getMoreResults() == false) && (stmt.getUpdateCount() == -1))

这听起来很简单,但像往常一样,“细节决定成败”,如下例所示。对于 SQL Server 存储过程...

ALTER PROCEDURE dbo.TroublesomeSP AS
BEGIN
    -- note: no `SET NOCOUNT ON;`
    DECLARE @tbl TABLE (id VARCHAR(3) PRIMARY KEY);

    DROP TABLE NonExistent;
    INSERT INTO @tbl (id) VALUES ('001');
    SELECT id FROM @tbl;
    INSERT INTO @tbl (id) VALUES ('001');  -- duplicate key error
    SELECT 1/0;  -- error _inside_ ResultSet
    INSERT INTO @tbl (id) VALUES ('101');
    INSERT INTO @tbl (id) VALUES ('201'),('202');
    SELECT id FROM @tbl;
END

...下面的Java代码将返回所有内容...

try (CallableStatement cs = conn.prepareCall("{call dbo.TroublesomeSP}")) {
    boolean resultSetAvailable = false;
    int numberOfResultsProcessed = 0;
    try {
        resultSetAvailable = cs.execute();
    } catch (SQLServerException sse) {
        System.out.printf("Exception thrown on execute: %s%n%n", sse.getMessage());
        numberOfResultsProcessed++;
    }
    int updateCount = -2;  // initialize to impossible(?) value
    while (true) {
        boolean exceptionOccurred = true; 
        do {
            try {
                if (numberOfResultsProcessed > 0) {
                    resultSetAvailable = cs.getMoreResults();
                }
                exceptionOccurred = false;
                updateCount = cs.getUpdateCount();
            } catch (SQLServerException sse) {
                System.out.printf("Current result is an exception: %s%n%n", sse.getMessage());
            }
            numberOfResultsProcessed++;
        } while (exceptionOccurred);

        if ((!resultSetAvailable) && (updateCount == -1)) {
            break;  // we're done
        }

        if (resultSetAvailable) {
            System.out.println("Current result is a ResultSet:");
            try (ResultSet rs = cs.getResultSet()) {
                try {
                    while (rs.next()) {
                        System.out.println(rs.getString(1));
                    }
                } catch (SQLServerException sse) {
                    System.out.printf("Exception while processing ResultSet: %s%n", sse.getMessage());
                }
            }
        } else {
            System.out.printf("Current result is an update count: %d %s affected%n",
                    updateCount,
                    updateCount == 1 ? "row was" : "rows were");
        }
        System.out.println();
    }
    System.out.println("[end of results]");
}

...产生以下控制台输出:

Exception thrown on execute: Cannot drop the table 'NonExistent', because it does not exist or you do not have permission.

Current result is an update count: 1 row was affected

Current result is a ResultSet:
001

Current result is an exception: Violation of PRIMARY KEY constraint 'PK__#314D4EA__3213E83F3335971A'. Cannot insert duplicate key in object 'dbo.@tbl'. The duplicate key value is (001).

Current result is a ResultSet:
Exception while processing ResultSet: Divide by zero error encountered.

Current result is an update count: 1 row was affected

Current result is an update count: 2 rows were affected

Current result is a ResultSet:
001
101
201
202

[end of results]
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 JDBC 从存储过程中获取*所有内容* 的相关文章

随机推荐

  • 圆角的QDialog有黑角而不是半透明

    我需要创建一个QDialog https doc qt io qt 5 qdialog html带有半透明的圆角 问题是这样做时 角是半透明的 但以某种方式被窗口的 alpha 属性填充 使其变黑 这是我对问题原因的理解 清晰可见的是圆形边
  • belongs_to 关联上的 :conditions 的目的是什么?

    假设我与附加条件有以下关联 belongs to admin user class name gt User foreign key gt admin user id conditions gt users admin TRUE or an
  • javascript element.scrollLeft 不工作

    我正在尝试使用滑块 我希望能够滚动到滑块的特定位置 从 MDN 文档看来 我可以使用 element scrollLeft 滚动到特定位置 虽然我似乎不为我工作 var container document getElementById c
  • Oracle 11G 中的限制/偏移

    我正在尝试更新 Oracle 中的表 但遇到了一些困难 我正在从 MySQL 移植代码 但 Oracle 不支持 MySQL 允许的一些命令 这是 MySQL 代码 update table1 t1 set c5 select Contra
  • 在同一文件中找不到类[重复]

    这个问题在这里已经有答案了 可能的重复 稍后在同一文件中定义的派生类 不存在 https stackoverflow com questions 12617188 derived class defined later in the sam
  • 是否有一个Matlab条件IF运算符可以像VBA的IIF一样放置在INLINE中

    在 VBA 中我可以执行以下操作 A B IIF C gt 0 C 0 所以如果 C gt 0 我得到A B C和 CA B 是否有一个运算符或函数可以让我执行这些条件inline在 MATLAB 代码中 简单地利用 MATLAB 在操作需
  • 使用 Twisted Python 的 SMTP 模块清理资源

    这与之前回答的问题有关 使用 Twisted 记录 SMTP 连接 https stackoverflow com questions 12164557 logging smtp connections with twisted 我有一个在
  • 调用“pip install”时运行自定义任务

    我想让我的 python 包 pip installable 问题是该包具有必须源自用户的 init shell 脚本的 shell 脚本 例如 bashrc 但安装后 用户并不确切知道脚本去了哪里 大概是 usr bin 但我们不能保证
  • rubyracer 或 libv8 在 Rails 应用程序中的用途是什么?

    我当时正在做一个项目 经常遇到 therubyracer 和 libv8 的问题 所以我决定删除它们 似乎唯一使用它们作为依赖项的是 less rails 无论如何我都想删除它 我的主要问题是它们的用途是什么 我在普通应用程序中是否需要它们
  • 拆分 BigIntegers 数字

    我正在尝试分割一个大整数的数字 让我说得更具体一些 我正在使用斐波那契序列生成一个大整数 现在使用这个算法我需要循环 直到找到一个 BigInteger 其中前 9 位数字和最后 9 位数字是泛数字 唯一的问题是我必须循环的数量是 300K
  • 对从 Ansible Tower (awx) 执行的 fetch_module 进行故障排除

    我正在尝试从远程主机执行一个非常简单的获取文件 不知怎的 我从来没有让它发挥作用 从远程 Linux 机器获取到 Ansible Tower awx 主机 也是 Linux 机器 这是 Ansible 代码 name get new pri
  • 活动 onCreate 中的 java.util.ConcurrentModificationException

    在最近的一个版本中 我通过 Admob 广告中介添加了 MoPub 我在崩溃日志中看到了一堆 ConcurrentModificationException 这一切似乎都是本机代码 我使用的是所有广告相关和 google android 相
  • Android FragmentTab 宿主和 Fragments 内的 Fragments

    我有一个具有如下层次结构的应用程序 FragmentTabHost Main Activity Fragment tab 1 content splitter view Fragment lhs list Framment rhs cont
  • PHP - fopen($url) 无法打开流:权限被拒绝

    我的网站必须具有非常相似的 php 配置 实际上在同一个托管帐户上 具有几乎相同的 php 代码和相同的文件结构 在某个时刻 我打电话fopen http example com rssfedd xml 检索 RSS 提要 on http
  • 具有多个 X 轴列的 ASP 图表

    我有一个包含两列的 SQL 表 销售人员和状态 状态可以是金 银 铜三种状态之一 如何创建一个图表 其中销售人员姓名沿 x 轴出现一次 但其姓名上方有三列用于显示每种状态的计数 谢谢 乔诺 如果我理解正确的话 你正在尝试做类似这篇文章的事情
  • 在QTabBar中隐藏底线

    似乎没有办法为底线 如下图所示 设置样式表QTabBar 我想将其删除 我怎样才能删除它 现在已经 6 7 个月没有使用 Qt 了 所以我不确定这是否有效 也无法测试它 给QTabBar drawBase http qt project o
  • 在Javascript中,为什么“this”运算符不一致?

    在 JavaScript 中 this 运算符在不同场景下可以指代不同的事物 通常 在 JavaScript 对象 内的方法中 它指的是当前对象 但当用作回调时 它变成对调用对象的引用 我发现这会导致代码出现问题 因为如果您使用 JavaS
  • 当无法推断 Rust 借用检查器中的生命周期时?

    在大多数情况下 Rust 编译器可以推断生命周期 如果生命周期范围是在运行时确定的 则表示必须显式标记生命周期 fn longest lt a gt x a str y a str gt a str if x len gt y len x
  • 如何让 Powershell 等到命令完成后再继续?

    我的脚本会在安装较新版本之前卸载 Windows 应用商店应用程序 我需要确保在安装之前卸载已完成 那么如何确保我已经等待了足够长的时间 Remove Appxpackage MyAppName wait here Add Appxpack
  • 如何使用 JDBC 从存储过程中获取*所有内容*

    当使用 JDBC 处理 SQL Server 存储过程时 我偶尔会遇到两种奇怪的行为 Issue 1 我在 SQL Server Management Studio SSMS 中运行一个存储过程 它返回一个结果集 然而 当我尝试 try C