2009-05-03 71 views
40

关于使用事务从数据库中读取,似乎有很不同的观点。只读数据库访问事务?

从developerWorks文章Transaction strategies: Models and strategies overview报价:

为什么你会需要一个事务,如果 你只是读取数据?答案 是你没有。启动 交易执行只读 操作增加了 处理线程的开销,并可能导致数据库共享上 读锁(视 于你正在使用 数据库的类型和什么隔离级别设置 )。

由于相反的意见,有来自Hibernate文档以下报价Non-transactional data access and the auto-commit mode

我们的建议是在应用程序中不使用 自动提交模式,并 申请只读只 时交易有一个明显的表现 好处或当未来的代码更改 是不太可能的。无论您是读取数据还是写入数据,始终优先选择 常规ACID事务,以便将您的数据访问操作分组为 , 或 。

在EclipseLink邮件列表here上也有类似的争论。

那么谎言的真相呢?是否阅读最佳做法的交易?如果两者都是可行的解决方案,那么使用交易的标准是什么?

就我所见,只有当隔离级别高于'读取提交'时才会有所作为。它是否正确?

有什么经验和建议?

回答

16

史蒂芬Devijver提供启动交易一些很好的理由,即使操作只会读取数据库:

  • 设置超时或锁模式
  • 设置隔离级别

标准SQL要求如果没有正在进行的交易,即使查询也必须开始新的交易。有数据库管理系统哪里不会发生什么 - 例如那些与自动提交模式,(语句启动一个事务,并立即提交声明完成)。其他DBMS在默认情况下使语句原子化(有效自动提交),但使用'BEGIN WORK'等语句启动显式事务,取消自动提交,直到下一个COMMIT或ROLLBACK(IBM Informix Dynamic Server就是这样 - 当数据库不是MODE ANSI)。

我不确定永不回滚的建议。这对于只读事务没有什么区别,并且在很大程度上会惹恼DBA,因此最好避免ROLLBACK。但是如果你的程序没有进行COMMIT就退出了,DBMS应该对你的未完成事务做一个ROLLBACK - 当然如果它修改了数据库,并且(为了简单起见),即使你只选择了数据。总体而言,如果要更改一系列操作的默认行为,请使用事务,即使事务处于只读状态也是如此。如果您对默认行为感到满意,那么使用事务并不重要。如果您的代码要在DBMS之间移植,最好假设您需要一个事务。

8

如果您希望为默认超时之外的其他查询设置特定的超时值,或者您想要更改隔离级别,则只读操作需要事务。

此外,每个数据库 - 不知道异常 - 将在内部为每个查询启动一个事务。当不需要回滚时,通常认为没有做回滚事务。

DBA's可能正在监视回滚活动,并且在这种情况下,任何默认的回滚行为都会使他们恼火。

因此,无论您是否开始交易,都会使用交易。如果你不需要它们,不要启动它们,但不要在只读操作上进行回滚。

8

首先,这听起来像是一个不成熟的优化。正如史蒂文指出的那样,大多数理智的数据库都会把你放进一个事务中,而他们真正所做的就是在每次陈述后调用commit。所以从这个角度来看,自动提交可能性能较差,因为每条语句都必须启动一个新的事务。或者可能不是。只有基准测试会告诉我,我敢打赌,它不会让你的应用产生一点变化。

为什么总想使用交易的一个原因是保护的一致性。如果你开始摆弄手动只在“需要”的时候宣布交易,那么你将在关键时刻忘记。或者那个被认为是只读操作的集合突然不是,因为后来的程序员没有意识到它应该是或者因为你的代码调用了一个具有隐藏写操作的函数。例如,我将我的命令行数据库客户端配置为不自动提交。这意味着我可以用手指删除查询并仍然回滚。

正如指出的那样,存在隔离级别。这使您可以执行多次读取操作,而不用担心其他进程是否写入了它们之间的数据,从而使您的读取实际上处于原子状态。这将为您节省很多小时的调试竞争条件。

最后,您通常可以将事务设置为只读。这会检查你的假设,如果有东西试图写入,将会错误。

Here's a nice article summing it all up.详细信息是Oracle特定的,但概念是通用的。