【问题标题】:How can I execute a stored procedure with JDBC / jTDS without using a transaction?如何在不使用事务的情况下使用 JDBC / jTDS 执行存储过程?
【发布时间】:2010-07-26 08:35:57
【问题描述】:

我们运行一个用 Java 编写的网站,该网站使用 JDBC 和 jTDS 来访问 SQL Server 数据库。

我们的数据库包含一个复杂的存储过程,通常需要 10 分钟才能运行。如果我们直接执行存储过程(例如从 SQL Server Management Studio 执行),存储过程可以正常工作,因为它不在事务中运行。但是如果我们使用 jTDS 执行它,它会锁定整个网站 10 分钟。发生这种情况是因为 jTDS 在事务中运行它,因此所有网站请求都处于暂停状态,等待事务完成。

例如,以下因交易而锁定网站:

Connection connection = DriverManager.getConnection("jdbc:jtds:sqlserver://example/example");
CallableStatement callableStatement = connection.prepareCall("exec dbo.procTest");
callableStatement.execute();

有什么方法可以让我们使用 JDBC / jTDS 运行存储过程,而不需要在事务中运行?

请注意,在 jTDS 连接上调用它是无效的:

connection.setTransactionIsolation(Connection.TRANSACTION_NONE);

这会引发一个异常,指出 jTDS 不支持 Connection.TRANSACTION_NONE 参数。


编辑:我可能会问这个问题更好:核心问题不是事务本身,问题是事务导致数据库锁定保持 10 分钟。要么我需要摆脱事务,要么我需要在事务期间释放锁

【问题讨论】:

  • “不在事务中运行”?你确定吗? AFAIK 每个 SQL 语句都在事务中运行。最接近“无事务”的可能是自动提交,即每条语句都在其自己的会话中执行。
  • 我可以用实际的术语解释我的意思:如果我运行“EXEC dbo.procTest;”使用 SQL Server Management Studio 然后网站不会锁定。但是如果我运行“BEGIN TRANSACTION; EXEC dbo.procTest; COMMIT;”然后网站在事务期间锁定 - 监视数据库锁定表明网站连接都在等待执行该存储过程的线程。也许交易不是这里的重点。我可以说的另一种方式是“我不希望数据库在事务期间锁定更新的对象”。
  • 你试过Connection.TRANSACTION_READ_UNCOMMITTED吗?

标签: java sql-server jdbc jtds


【解决方案1】:

在我们的例子中,必须调用 StoredProcedure,当从 jtds 调用时抛出异常:

无法在事务中执行备份或恢复操作。

我发现了什么@https://communities.bmc.com/docs/DOC-66239 exec 调用是否需要在前面加上“SET IMPLICIT_TRANSACTIONS OFF;”

这是基于弹簧的 sn-p 的样子:

try {
  jdbcTemplate.getJdbcOperations.execute("SET IMPLICIT_TRANSACTIONS OFF;")
  //noinspection ConvertExpressionToSAM   // we have 1.6 code version
  jdbcTemplate.getJdbcOperations.call(new CallableStatementCreator {
    override def createCallableStatement(con: Connection): CallableStatement = {
      val callableStatement = con.prepareCall(
        s""" EXEC dbo.RestoreLatestCopy
           |      @ID = ?
           |""".stripMargin)
      callableStatement.setInt(1, getMappedRestoreId(fromDbName))
      callableStatement
    }
  }, parameters ++ rsParams)
} catch {

【讨论】:

    【解决方案2】:

    调用Connection#close()Connection#commit() 应该提交并结束交易。您是否关闭了finally 块中的Connection 之类的数据库资源?

    【讨论】:

    • 是的,Connection#close() 和 Connection#commit() 确实提交并结束了事务......这不是我遇到的问题。问题是,在到达这些行之前,我们有一个 10 分钟长的事务,它锁定了所有内容。所以这不是事务是否正确提交的问题,而是我是否可以避免在事务中首先运行它的问题。
    【解决方案3】:

    我最终使用了以下丑陋的解决方法。如果有人能解释我如何正确地做到这一点,我仍然很感兴趣;但解决方法暂时可行。

    数据库在网络服务器上的同一台机器上运行,因此我可以使用标准的 SQL Server 命令行工具来运行存储过程。触发它的 Java 代码是:

        try {
            Process process = Runtime.getRuntime().exec("sqlcmd -E -d \"example\" -Q \"EXEC dbo.procTest;\"");
            process.waitFor();
        } catch (IOException e) {
            // Handler here
        } catch (InterruptedException e) {
            // Handler here
        }
    

    因此运行完全相同的存储过程 — 不同之处在于网络服务器不会锁定,因为 sqlcmd 不是在单个事务中运行它。是的,它很丑……但这是我所知道的唯一可行的选择!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-02-07
      • 2019-08-01
      • 1970-01-01
      • 2019-07-06
      • 1970-01-01
      • 1970-01-01
      • 2012-10-14
      • 2010-09-12
      相关资源
      最近更新 更多