在检索输出参数的值之前应该调用 commit() 吗?

commit() should be called before retrieving the values for out parameters?

在编写 java JDBC 代码来调用我正在使用的存储过程时 con.setAutoCommit(false); 我的问题是以下方法有什么区别:

方法一:

        con = DBConnection.getConnection();
        con.setAutoCommit(false);
        stmt= con.prepareCall("{call updateEmp(?,?,?,?,?,?)}");
        stmt.setInt(1, id);
        stmt.setString(2, name);
        stmt.setString(3, role);            
        stmt.registerOutParameter(6, java.sql.Types.VARCHAR);

        stmt.executeUpdate();
        con.commit();
        //read the OUT parameter AFTER commit
        String result = stmt.getString(6);

或方法 2:

        // Read the OUT parameter BEFORE commit
        String result = stmt.getString(6);
        con.commit();

我认为这取决于您调用的存储过程是否自行提交。我希望有一个更新过程接受参数,并设置参数以在内部进行提交或回滚。

在这种情况下,调用 setAutoCommit(true) 或调用 con.commit() 将没有任何效果,无论您何时调用 stmt.getString(6),out 参数都会有一个值。如果存储过程本身没有提交,如果您在调用 stmt.getString(6).

之后调用 con.commit() ,我希望您的 out 参数为 null

主要区别在于您持有交易的时间超过了必要的时间。您应该始终尽可能快地提交,以尽量减少阻塞其他事务的可能性。特别是如果您正在做一些事情,比如传输 BLOB 或大文本字段,这可能会占用大量事务日志 space(并且需要更多时间通过网络传输)。

区别在于异常处理。如果 getString 抛出异常,那么后面的提交将不会执行。后果取决于当前交易是否有任何变化**。如果您要跟踪代码的两个版本(从不抛出任何异常),然后比较两个跟踪文件,您将无法分辨哪个版本的代码创建了每个跟踪,除非您留下某种标记(或保留每个用户进程的 spid)。

你要问自己一个问题:即使抛出异常我也要提交吗?然后你就会知道怎么写代码了。

** 您的连接始终有一个交易打开。有些交易有变化,有些则没有。

在我看来,在输出参数是简单类型的情况下,这在很大程度上是一种风格问题。但是,out 参数可以是游标等。在自动提交的情况下,只有当游标类型输出参数或存储过程返回的所有结果集都关闭时,才会发生提交操作。如果在游标完全获取之前发出提交,则数据一致性有问题。为避免这种歧义,我建议在读取所有输出参数后 committing/rolling 返回事务。

只是将以上答案总结在一个答案中,作为一个快速总结:

1-如果commit,在读取所有out参数之前,数据一致性有问题。所以这里的方法2是不可取的。

2-假设在读取输出参数时发生异常,则事务不会被提交。另一方面,如果我们希望在不关心out参数的情况下提交事务,我们可以在读取它们之前提交。

3- 在方法 2 中,我们会更长时间地阻止交易。在上面的示例代码中,这没什么大不了的,但如果我们在提交之前做了很多事情,这可能是一个问题。