代码之家  ›  专栏  ›  技术社区  ›  gutch

如何在不使用事务的情况下使用JDBC/JTDS执行存储过程?

  •  0
  • gutch  · 技术社区  · 14 年前

    我们运行一个用Java编写的网站,它使用JDTC与JTDS访问SQL Server数据库。

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

    例如,由于交易,以下内容会锁定网站:

    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);
    

    这将引发一个异常,说明jtd不支持connection.transaction_none参数。


    编辑: 我可能问得更好:核心问题不是事务本身,而是事务导致数据库锁保持10分钟。要么我需要 摆脱交易 或者我需要 事务期间释放的锁 .

    3 回复  |  直到 6 年前
        1
  •  1
  •   mikhalytch    6 年前

    在我们的例子中,必须调用StoredProcedure,从JTD调用时引发异常:

    无法在事务中执行备份或还原操作。

    我发现了什么 https://communities.bmc.com/docs/DOC-66239 exec调用是否需要预先设置为“set implicit_transactions off;”

    下面是基于Spring的代码片段:

    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
  •  0
  •   BalusC    14 年前

    打电话 Connection#close() Connection#commit() 应提交并结束事务。关闭数据库资源,比如 Connection finally 街区?

        3
  •  0
  •   gutch    14 年前

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

    数据库在Web服务器上的同一台计算机上运行,因此我可以使用标准的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
        }
    

    所以运行的存储过程完全相同,区别在于Web服务器没有锁定,因为 实用工具 不是在单个事务中运行它。是的,很难看…但这是我知道的唯一可行的选择!