如何在JDBC中启动事务?

时间:2011-02-09 02:09:29

标签: java jdbc transactions

Connection.setTransactionIsolation(int)警告:

  

注意:如果在事务期间调用此方法,则结果是实现定义的。

这提出了一个问题:如何在JDBC中开始事务?很清楚如何结束事务,但不知道如何开始事务。

如果在事务内部启动Connection,我们应该如何在事务外部调用Connection.setTransactionIsolation(int)以避免特定于实现的行为?

8 个答案:

答案 0 :(得分:47)

回答我自己的问题:

  • JDBC连接以启用自动提交模式开始,其中每个SQL语句都使用事务隐式划分。
  • 希望每次执行多个语句的用户必须转为auto-commit off
  • 更改自动提交模式会触发当前事务的提交(如果一个处于活动状态)。
  • 如果启用了自动提交,则可以随时调用
  • Connection.setTransactionIsolation()
  • 如果禁用自动提交,则只能在事务之前或之后调用Connection.setTransactionIsolation()。在事务中调用它会导致未定义的行为。

来源:

答案 1 :(得分:24)

JDBC隐式划分您在与事务的连接上执行的每个查询/更新。您可以通过调用 setAutoCommit(false)来关闭自动提交模式并调用 commit()/ rollback()以指示事务结束来自定义此行为。 Pesudo代码

try
{
  con.setAutoCommit(false);

   //1 or more queries or updates

   con.commit();
}
catch(Exception e)
{
   con.rollback();
}
finally
{
   con.close();
}

现在,您显示的方法中有一种类型。它应该是 setTransactionIsolation(int level),而不是用于事务划分的api。它管理一个操作所做的更改如何/何时对其他并发操作可见,“ICI” ACID (http://en.wikipedia.org/wiki / Isolation_(database_systems))

答案 2 :(得分:18)

我建议你阅读this,你会看到

  因此,第一次打电话   setAutoCommit(false)和每次调用   commit()隐式标记开头   交易。交易可以   在他们承诺之前撤消   调用

修改

查看有关JDBC事务的官方文档

  

创建连接时,它处于自动提交模式。这意味着   将每个单独的SQL语句视为事务并且是   执行后立即自动提交。 (更多   精确,默认情况下是SQL语句提交时   完成,而不是在执行时。所有声明都完成了   已检索到其结果集和更新计数。几乎   但是,所有情况下,声明都已完成,因此已经提交,   它被执行后立即。)

     

允许将两个或多个语句分组为a的方法   事务是禁用自动提交模式。这是证明   在以下代码中,con是活动连接:

     

con.setAutoCommit(假);

来源:JDBC Transactions

答案 3 :(得分:9)

实际上,this page from the JDBC tutorial会更好。< 你会得到你的连接,设置你的隔离级别,然后做你的更新和东西,然后提交或回滚。

答案 4 :(得分:3)

也许这会回答你的问题: 每个连接只能有一个事务。 如果启用了自动提交(默认),则每个选择,更新,删除都将自动启动并提交(或回滚)事务。 如果将autocommit设置为off,则启动“新”事务(意味着不会自动执行提交或回滚)。在一些语句之后,您可以调用commit或rollback,它完成当前事务并自动启动一个新事务。 您不能在纯JDBC上的一个JDBC连接上主动打开两个事务。

答案 5 :(得分:3)

首先,您可以手动运行交易,如果您希望将连接保留在&#34; setAutoCommit(true)&#34;模式,但仍然想要一个交易:

 try (Statement statement = conn.createStatement()) {
      statement.execute("BEGIN");
      try {
        // use statement ...
        statement.execute("COMMIT");
      }
      catch (SQLException failure) {
        statement.execute("ROLLBACK");
      }
  }

答案 6 :(得分:2)

您可以将这些方法用于交易:

  1. 您必须创建类似con
  2. 的连接对象
  3. con.setAutoCommit(false);
  4. 您的疑问
  5. 如果全部为真con.commit();
  6. else con.rollback();

答案 7 :(得分:0)

使用一个连接进行多个事务(重用,池化或链接),一些奇怪的问题可能会潜伏着人们不得不生存的问题,因为它们通常无法确定原因。

想到以下情况:

  1. (重新)使用与正在进行的/未提交的事务的连接
  2. 错误的连接池实现
  3. 某些数据库(尤其是分布式SQL和NoSQL)中更高的隔离级别实现

第1点是直截了当且可以理解的。 点2基本上指向点1或(和)点3。

第3点全部涉及在发出第一条语句之前已开始新事务的系统。从数据库的角度来看,这样的事务可能早在发出“第一条”实际语句之前就已经开始。如果并发模型基于快照的思想,即仅读取在事务开始时有效的状态/值,但是以后没有更改,则在提交当前事务的完整读取集时非常重要也经过验证。

由于NoSQL和某些隔离级别(例如MS SQL-Server Snapshot)通常不验证读集(以正确的方式),因此所有押注通常都不符合预期。尽管始终存在这个问题,但是当处理从上一次提交开始的事务时,或者当连接被池化而不是实际使用的连接时,情况变得更糟,通常重要的是确保事务真正开始预计何时开始。 (如果使用回滚式只读事务,这也非常重要。)

在JAVA中处理JDBC时,我使用以下规则:

  1. 如果公司将纯JDBC与任何缓冲机制结合使用,则在使用它之前总是回滚JDBC连接(取消所有内容并开始新事务)
  2. 即使仅对纯SQL使用会话管理的JDBC连接,也可以使用Hibernate进行事务处理。到目前为止,交易从未遇到任何问题。
  3. 使用BEGIN / COMMIT / ROLLBACK作为SQL语句(如前所述)。如果在活动事务期间发出BEGIN语句,大多数实现将失败(对数据库进行测试,并记住测试数据库不是生产数据库,并且JDBC Driver和JDBC Server端实现的行为与在SQL Server上运行SQL控制台的行为可能有所不同)。实际服务器)。
  4. 在自己的包装器中使用3个JDBC连接实例。这种方式的事务处理总是正确的(如果不使用任何反射并且连接池没有缺陷)。

3 + 4我仅在响应时间很关键或休眠不可用时使用。 4允许在特殊情况下使用一些更高级的性能(响应时间)改进模式