2010-12-15 118 views
28

我想了很久为什么JDBC API提供了一个自动提交模式(java.sql.Connection.setAutocommit())。这似乎是一个诱人的麻烦,只是引诱人们陷入困境。我的理论是,它只添加到JDBC中,以便简化使用JDBC创建编辑和运行SQL的工具的供应商的生活。是否有其他理由打开自动提交,还是总是出错?为什么设置Autocommit为true?

回答

11

不幸的是,使用自动提交是数据库特定的(就像事务行为一样)。我认为,如果你没有一个全球的,程序化的交易策略,自动提交可能比只希望每个人都能正确地关闭/回滚交易要好。

说到MySQL,您可以在默认情况下保持autocommit = true,并且在您开始事务时它会自动关闭它。设置autocommit = false的唯一原因是,如果您想要在没有BEGIN的情况下尝试启动事务时强制执行错误。

为了简化今天典型的Java + MySQL应用程序,我会或多或少地忽略自动提交设置,使用开放会话视图模式并称其为好。

我强烈劝阻显式RDBMS行锁,并使用乐观锁。 Hibernate为乐观锁定提供了内置支持,但即使对于手写代码,它也是一种简单的模式,并且可以提供更好的性能。

+2

为了澄清典型的Ja va + MySQL应用程序:将自动提交设置为true。在传入请求(网页或REST/JSON)开始时,打开一个会话(并开始一个事务)一次。如果请求处理正常,请在请求处理结束时提交事务。然后,添加一个回滚到你的500页面的请求渲染。例如,这基本上是Play Framework如何处理事物的。这对用户和开发人员来说很直观。 – 2013-01-11 18:32:09

+0

这是一个很好的答案 - “web请求”应该与web应用程序中的“数据库事务”非常相关。因此我们需要依靠乐观,而不是数据库锁定。它有助于使用OpenSessionInView在整个请求中保持会话打开,包括视图渲染,然后在请求结束时刷新/提交。 – 2013-11-21 09:52:16

+0

在我看来,这不是一个好的答案,如果典型的Java + MySQL应用程序不仅仅是“几个星期的项目”,还可以将会话视为反模式。您会很快失去对应用程序中发生的事情的控制,它几乎可以确定是否会出现性能问题或并发性问题,自动提交将使您无需事务超时或事务超时,如同“一般请求处理超时”一样工作。我会说在90%以上的情况下,web请求NO与SQL事务没有关系 – 2017-12-29 08:30:23

5

提交模式改变数据库持有锁的方式。

建议仅在事务模式下禁用自动提交模式。这样,您可以避免为多个语句保留数据库锁定,从而增加与其他用户发生冲突的可能性。

...

为了避免交易过程中出现冲突,数据库管理系统使用的锁,机制,阻止他人访问正由事务访问的数据。 (请注意,在自动提交模式,其中每条语句是一个事务,持有锁只有一个声明。)

http://download.oracle.com/javase/tutorial/jdbc/basics/transactions.html

+0

鉴于即使mySQL和DB2最近都是多版本的,该教程也变得有些过时。 :( – Affe 2010-12-15 19:40:26

+0

快照隔离级别不是免费的:http://blogs.msdn.com/b/sqlserverstorageengine/archive/2008/03/30/overhead-of-row-versioning.aspx您可以获得并发快照隔离,但是会增加额外的开销 – hythlodayr 2010-12-15 19:50:47

+0

理解你获得锁的方式始终是相关的 – 2010-12-15 20:01:17

18

只需要合理的理由,我可以看到的是摆脱connection.commit()connection.rollback()简单的单一查询事务处理小应用程序中的样板。原始形式的JDBC本身就需要很多样板。每一行都使JDBC对于初学者来说不那么可怕。

3

我正在使用的代码库的95%现在涉及单个更新,其中自动提交是完全合理的。所以,我们默认它。只需将它关闭足够长的时间以完成需要成为事务的代码段,然后自动提交即可重新开始!

+0

请记住,交易可能会导致交易管理器发生交易超时。你在每个查询中设置了超时时间吗? – 2017-12-29 08:33:36

8

我几乎总是以autocommit = true运行。 99%的时间,我的更新是原子。当然,在某些情况下,如果您编写借方,然后尝试写入您希望回滚的信用额度失败。但根据我的经验,这些比较少见。通常我写的每个记录都是独立的。在这种情况下,在每次写入都很方便之后,不需要费心提交一次提交。它在这里和那里保存了一行代码。如果考虑到程序的结构,这意味着我不需要额外的try/catch块或者我不需要在函数之间传递连接对象,它可以节省更多的时间。它可以节省那些忘记做提交的烦人的错误。

我发现它可以“引诱某人陷入麻烦”的唯一方法是他决定关闭自动提交并进行提交或回滚比较麻烦,因此他更新了应该在事务中单独进行的更新。然后,只要没有任何事情会中止交易,所有事情都可以正常工作。如果测试场景不足,我可以想象这会滑入生产。

但是你几乎可以对任何语言的任何特征说几句话。就像,假设你编写一个程序来处理数字,90%的时间适合长时间,但是现在或许会变得更长。面对这种情况,正确的做法是使用BigInteger或创建一个新类来处理更大的数字。一个懒惰的程序员可能会被诱使用很长的时间,因为它通常会起作用,而其他替代方法则很麻烦。您是否因此得出结论:Java不应该包含long(或int),因为有人可能会在不恰当时引诱它们使用它们?

如果在您的程序中大部分更新必须在事务上下文中完成,请关闭自动提交。它的存在并不会伤害你。当它方便时,它在那里,但当它不是时,你可以关闭它。

+1

由于JDBC 3规范,“自动提交”模式下的连接不能有多个Statement打开。因此,在外部SELECT循环内嵌套的UPDATE甚至SELECT会导致问题。 – 2012-06-05 00:36:01

+0

这不仅是原子性,如果事务管理器支持事务,事务也可以分配超时。使用自动提交和无查询超时可以使您陷入未检测到的SQL性能问题,挂起沉重的查询等。 – 2017-12-29 08:35:28

+0

我已经离开了Javaland多年,所以也许新版本的Java不同或者我只是误解了事情。但是我确信在执行带有自动提交的查询时,我得到了SQL超时。我对在开发环境中发现的查询有很多美好的回忆,但在产品中超时。也许默认值是不同的或者什么的。无论如何,依靠暂停来告诉你,你有一个性能问题是一个非常钝的工具。 – Jay 2017-12-29 16:31:24

6

自动提交很方便;但随着JDBC 3规范的变化,变得不那么有用。

由于“自动提交”模式下的JDBC 3连接不能打开多个语句。执行另一个语句,将关闭第一个 - 包括任何ResultSet。

因此,在SELECT中循环并发布UPDATE(甚至嵌套的SELECT)将会失败。显然这是一种犯罪,实际上想做些什么与你的外部SELECT的结果!


不管怎么说,依赖于特定的驱动程序版本& ..但在一般的JDBC 3.0规范似乎强制此无益的行为。升级驱动程序也可能无益地“发现”这种行为。

为什么使用自动提交?本来,这很有帮助&方便。至于其他的答案说,JDBC需要丰富金额废话和处理能正确调用.. JDBC是不是一个真正的精心设计的API :(


这些天来,你最好使用Hibernate或Spring的JdbcTemplate。 。如果你正在做servlet/web应用程序,在“用户请求”的边界放置事务管理(开始/结束)或Hibernate会话(绑定到线程本地)。

例如,get在ServletRequest的开始处绑定你的连接/事务;并在最后返回它

你可以使用javax.servlet.Filter或类似的方法,并绑定它到线程局部,使静态帮手得到它或需要它,等

+0

请不要建议绑定到Web请求ANTI模式的连接/交易/会话......如果您希望您的交易跨越例如请求处理,multiplart上传处理,发送正文给客户端连接速度慢,你可以做到这一点,但在几乎所有情况下,我都会说这是非常糟糕的主意。 – 2017-12-29 08:38:12

+0

谢谢@PiotrMüller - 任何推理或参考?我可以预料,对于几乎所有的模式,你都可以想出0.001%的不好的情况,但把“孤立的问题角落案例可能”与“几乎所有案例”区别开来可能会更好 - 当时我给出了这个建议(2012年),我相信这是很好的建议。用户请求边界是HT​​TP服务应用程序中最基本和重要的边界。因此,这是一个强大而明显的候选设计。任何替代解决方案可能会更复杂。 – 2018-01-08 03:34:50

+0

在Web应用程序中,大多数提到的“不好的情况”将适用(对于任何典型的Web应用程序)。在视图中启用会话,您应确保立即解决很多技术问题,例如,响应缓冲:确保事务和SQL连接在整个客户端连接拉动响应的时间内不是跨度(为什么在客户端具有低带宽的情况下长时间保持SQL连接)。如果应用程序很快就会遇到设计/性能问题增长。对于快速的几个星期小项目,这可能是一些解决方案,但我不会推荐它有任何大的 – 2018-01-26 08:45:10

2

那么有需要仔细看一下,同时启用“自动提交”在全球层面一定的条件:

a。)查询级别的事务管理将留给用户,对于一个实例,如果需要一堆查询来一起成功或失败,那么它需要在BEGIN下进行包装并提交事务。 )请记住,启用“自动提交”时不会回滚。

c)还有写作(提交)每一笔交易的开销。 d))对于只读查询,没有明确需要“自动提交”,但通过启用“自动提交”,它会自动执行所有查询。

如果表锁定是启用自动提交的唯一考虑因素,那么它可能不是一个好主意,相反可能会采取较低的锁定超时。

相关问题