【发布时间】:2011-05-26 02:58:16
【问题描述】:
我一直想知道为什么 JDBC API 提供自动提交模式 (java.sql.Connection.setAutocommit())。这似乎是一种有吸引力的滋扰,只会引诱人们陷入困境。我的理论是,它只是被添加到 JDBC 中,以便为想要创建使用 JDBC 编辑和运行 SQL 的工具的供应商简化生活。是否有任何其他原因打开自动提交,或者它总是一个错误?
【问题讨论】:
我一直想知道为什么 JDBC API 提供自动提交模式 (java.sql.Connection.setAutocommit())。这似乎是一种有吸引力的滋扰,只会引诱人们陷入困境。我的理论是,它只是被添加到 JDBC 中,以便为想要创建使用 JDBC 编辑和运行 SQL 的工具的供应商简化生活。是否有任何其他原因打开自动提交,或者它总是一个错误?
【问题讨论】:
在全局级别启用“自动提交”时,需要仔细查看某些条件:
a.) 查询级别的事务管理将留给用户,例如,如果需要一堆查询一起成功或失败,则需要将其包装在 BEGIN 下并提交事务。
b.) 请记住,启用“自动提交”时不会回滚。
c.) 编写(提交)每个事务也会产生开销。
d.) 对于只读查询,没有明确需要“自动提交”,但通过启用“自动提交”,它会自动对所有查询强制执行。
如果表锁定是启用自动提交的唯一问题,那么这可能不是一个好主意,而是可以求助于较低的锁定超时。
【讨论】:
自动提交很方便;但随着对 JDBC 3 规范的更改,它变得不那么有用了。
由于“自动提交”模式下的 JDBC 3 连接不能打开多个语句。执行另一个语句,将关闭第一个语句——包括任何 ResultSet。
因此,在 SELECT 中循环并发出 UPDATE(甚至是嵌套的 SELECT)往往会失败。显然这是一种犯罪行为,实际上想要做某事用你的外部 SELECT 的结果!
无论如何,取决于特定的驱动程序和版本。但总的来说,JDBC 3 规范似乎强制执行这种无益的行为。升级驱动程序也可能无益地“发现”这种行为。
为什么要使用自动提交?最初,它很有帮助且方便。正如其他答案所说,JDBC 需要大量的 GUFF 和 HANDLING 才能正确调用.. JDBC 并不是一个设计良好的 API :(
现在,您最好使用 Hibernate 或 Spring 的 JdbcTemplate。如果您正在做 servlet/Web 应用程序,请将您的事务管理(开始/结束)或 Hibernate 会话(将其绑定到线程本地)在“用户请求”的边界。
例如,在 ServletRequest 开始时绑定您的连接/事务;并在最后归还。
您可以使用 javax.servlet.Filter 或类似的,并将其绑定到线程本地,制作静态助手来获取它或 require 它等等。
【讨论】:
不幸的是,使用自动提交是特定于数据库的(就像事务行为一样)。我认为如果你没有一个全局的、程序化的事务策略,自动提交可能比仅仅希望每个人都正确地关闭/回滚事务更好。
对于 MySQL,您可以默认打开 autocommit=true,当您开始事务时它会自动关闭它。设置 autocommit=false 的唯一原因是,如果有人尝试在没有 BEGIN 的情况下启动事务,您想强制出错。
为了简化当今典型的 Java + MySQL 应用程序,我或多或少会忽略自动提交设置,使用 open-session-in-view 模式并称之为好。
我强烈反对显式的 RDBMS 行锁,而是使用乐观锁。 Hibernate 提供了对乐观锁的内置支持,但即使是手动代码也很容易采用这种模式并提供更好的性能。
【讨论】:
我几乎总是使用 autocommit=true 运行。 99% 的时间,我的更新都是原子的。当然,在某些情况下,如果您写入借方,然后尝试写入您想要回滚的贷方失败。但根据我的经验,这些比较少见。通常我写的每条记录都是独立的。在这种情况下,每次写入后无需费心进行提交是很方便的。它在这里和那里节省了一行代码。如果考虑到程序的结构,它可能会节省更多,这意味着我不需要额外的 try/catch 块,或者我不需要在函数之间传递连接对象。它可以避免有人忘记提交的烦人错误。
我看到它可能“引诱某人陷入麻烦”的唯一方法是他认为关闭自动提交并执行提交或回滚太麻烦了,因此他执行了应该单独在事务中的更新。然后,只要没有发生任何应该中止事务的事情,一切似乎都可以正常工作。如果测试场景不足,我可以想象这会进入生产环境。
但是你几乎可以对语言的任何特性说同样的话。比如,假设你编写了一个程序,它处理的数字在 90% 的时间内都适合,但有时可能会更大。面对这种情况,正确的做法是使用 BigInteger 或创建一个新类来处理更大的数字。一个懒惰的程序员可能会被引诱使用 long,因为它通常会起作用,而其他替代方案太麻烦了。因此,您是否会得出结论认为 Java 不应该包含 long(或 int),因为有人可能会在它们不合适时被引诱使用它们?
如果在您的程序中大部分更新必须在事务上下文中完成,则关闭自动提交。它的存在不会伤害你。它在方便时就在那里,但在不方便时,您可以将其关闭。
【讨论】:
我现在使用的 95% 的代码库都涉及单个更新,其中自动提交是完全合理的。所以,我们默认开启它。只需将其关闭足够长的时间以执行需要成为事务的代码部分,然后自动提交就会重新开启!
【讨论】:
我能看到的唯一合理原因是在小型应用程序的简单单查询事务中摆脱 connection.commit() 和 connection.rollback() 样板。原始形式的 JDBC 本身就需要很多样板文件。每行少一点,JDBC 对初学者来说就不那么可怕了。
【讨论】:
提交模式改变了数据库持有锁的方式。
建议仅在事务模式期间禁用自动提交模式。这样,您可以避免为多个语句持有数据库锁,从而增加与其他用户发生冲突的可能性。
...
为避免事务期间发生冲突,DBMS 使用锁,这是一种阻止其他人访问事务正在访问的数据的机制。 (请注意,在自动提交模式下,每条语句都是一个事务,只为一个语句持有锁。)
http://download.oracle.com/javase/tutorial/jdbc/basics/transactions.html
【讨论】: