【问题标题】:JDBC commit(): what happens behind the scenes?JDBC commit():幕后发生了什么?
【发布时间】:2011-07-12 01:01:58
【问题描述】:

我正在帮助解决死锁问题。环境:Tomcat 5.5、Java 5、Microsoft SQL Server 2008、jTDS(更换旧驱动程序)。我们有一个旧版连接池。

数据库代码总是遵循这个方案:

connection = connectionPool.getConnection(); // 1
boolean previousAutoCommitStatus = connection.getAutoCommit(); // 2
connection.setAutoCommit(false); // 3

// ... use the connection ...
// execute prepared statement 4
// execute prepared statement 5
// execute prepared statement 6

connection.commit(); // 7
connection.setAutoCommit(previousAutoCommitStatus); // 8
connectionPool.releaseConnection(connection); // 9

当我们寻找错误(请原谅:软件缺陷)时,我想知道:驱动程序是如何工作的?我的猜测:无论我在 (3) 和 (7) 之间做什么,都会由驱动程序/DBMS 排队。只有当我connection.commit() DBMS 开始一个新事务时,才获取操作所需的每个锁(我希望它足够聪明以锁定可能的较小对象集),执行语句并释放锁,从而关闭事务。

或者是我一执行准备好的语句,DBMS 就锁定了表?

编辑:我想了解的是,如果“commit()”转换为一组以“begin trans/lock table”开头并以“commit/unlock table”结尾的 SQL 语句,或者如果任何 Java executeStatement() 立即获取锁。

TIA

【问题讨论】:

  • 你确定setAutoCommit() (at 3) 不应该是setAutoCommit(false)

标签: sql-server jdbc transactions


【解决方案1】:

如果您对内部细节感兴趣, 在 SQLServer JDBC 实现的 connection.commit 上

发出以下命令

IF @@TRANCOUNT > 0 COMMIT TRAN

@@TRANCOUNT = 0 -- 没有打开的交易 @@TRANCOUNT = 1 -- 1 个打开的事务 @@TRANCOUNT =10 -- 10 个打开的交易

将自动提交设置为 false,

set implicit_transactions on

这些是 MS SQLServer 特定的命令。

【讨论】:

    【解决方案2】:

    根据this resource,只要您调用setAutocommit(false);,事务就会开始

    我认为它可能仍然依赖于驱动程序,但这将是典型的。另请参阅MSDN,它也是这么说的。

    //Switch to manual transaction mode by setting
    //autocommit to false. Note that this starts the first 
    //manual transaction.
    con.setAutoCommit(false);
    

    【讨论】:

    • 在链接资源 DevX Pro 中说:“setAutoCommit(false) 和 commit() 隐式标记事务的开始”,至少可以说这是有争议的。我想了解的是“commit()”是否转换为一组以“开始传输/锁定表”开头并以“提交/解锁表”结尾的 SQL 语句,或者是否有任何 Java executeStatements() 获得了锁。跨度>
    • 明白。我会说这真的取决于驱动程序,但我的猜测是通常 setAutocommit(false) 会启动一个事务(有效地在数据库中),当您在 Java 代码中执行准备好的语句时,它会立即将其发送到服务器并因此获得一旦你在 java 中调用 SQL 语句就会锁定。我希望驱动程序充当直接代理。
    • MSDN 资源在这方面似乎更清楚,甚至更相关,因为它直接引用了 MSSQL ...
    • 好的...所以如果在 (3) 和 (7) 之间有人愚蠢地打包了很多耗时的操作,那么表将保持锁定并且可能会发生饥饿。这是一个非常令人不安的想法。重写整个大泥球现在更具吸引力......:-|
    【解决方案3】:
    connection.setAutoCommit(false); 
    

    在数据库服务器上触发“BEGIN TRAN”和

    connection.commit();
    

    会触发“COMMIT TRAN”

    如果您想防止这两个语句之间发生锁定,请将连接的隔离级别设置为“Read Uncommited”。您必须确保它在这种情况下是可接受的。

    setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
    

    【讨论】:

      【解决方案4】:

      究竟发生了什么完全取决于驱动程序的实现,因此您需要查看您正在使用的驱动程序的文档以获得明确的答案。

      setAutoCommit(false) 不一定会在数据库上开始事务,并且正如您推测的那样,当您在代码中调用 execute 函数时,语句不一定会在数据库上执行甚至获取锁。话虽如此,据我所知,共享(读取)锁通常是在执行语句时获取的;更新锁,当调用提交时。您可能遇到了转换死锁(当给定对象上的多个语句的读锁正在等待转换为写锁时会发生这种情况),我会检查您的更新语句是否在其中嵌套了可能导致这种锁的选择。

      【讨论】:

      • jTDS 文档没有这样的运气......我找不到任何东西(也许只是我)
      猜你喜欢
      • 2011-10-19
      • 1970-01-01
      • 1970-01-01
      • 2018-03-29
      • 2019-06-05
      • 1970-01-01
      • 2010-09-06
      • 2018-12-05
      • 2016-02-23
      相关资源
      最近更新 更多