只读数据库访问的事务?

时间:2009-05-03 21:42:00

标签: database transactions data-access

关于使用事务从数据库中读取,似乎有很多不同的意见。

来自DeveloperWorks文章Transaction strategies: Models and strategies overview的引用:

  

为什么你需要交易呢?   你只是在读数据吗?答案   是你没有。开始了   事务执行只读   操作增加了开销   处理线程并可能导致共享   读取数据库上的锁(取决于   您正在使用什么类型的数据库   以及设置的隔离级别   到)。

作为一个相反的意见,Hibernate文档Non-transactional data access and the auto-commit mode

引用了以下引用
  

我们建议不要使用   应用程序中的自动提交模式,以及   仅应用只读事务   当有明显的表现时   好处或未来代码更改时   极不可能。总是喜欢   定期进行ACID交易   您的数据访问操作,   无论你是否阅读或   写数据。

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

真相在哪里呢?交易是否为最佳实践?如果两者都是可行的解决方案,那么使用交易的标准是什么?

据我所知,只有隔离级别高于'read committed'才会有所不同。这是对的吗?

有哪些经验和建议?

3 个答案:

答案 0 :(得分:20)

Steven Devijver为启动事务提供了一些很好的理由,即使操作只是读取数据库:

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

标准SQL要求即使查询必须在当前没有正在进行的事务的情况下启动新事务。有DBMS,其中没有发生的事情 - 例如具有自动提交模式的那些(语句启动事务并在语句完成时立即提交它)。默认情况下,其他DBMS使语句成为原子(有效自动提交),但是使用诸如'BEGIN WORK'之类的语句启动显式事务,取消自动提交直到下一个COMMIT或ROLLBACK(IBM Informix Dynamic Server就是这样 - 当数据库不是MODE时ANSI)。

我不确定永远不会回滚的建议。它对只读事务没有任何影响,并且在它使DBA恼火的程度上,最好避免ROLLBACK。但是如果您的程序在没有执行COMMIT的情况下退出,则DBMS应该对您的未完成事务执行ROLLBACK - 当然,如果它修改了数据库,并且(为简单起见)即使您只选择了数据。

总的来说,如果要更改一系列操作的默认行为,请使用事务,即使事务是只读的。如果您对默认行为感到满意,那么使用事务并不重要。如果您的代码可以在DBMS之间移植,那么最好假设您需要一个事务。

答案 1 :(得分:10)

首先,这听起来像是一个过早的优化。正如Steven所指出的那样,大多数理智的数据库无论如何都会让你进入一个事务,而他们所做的只是在每个语句之后调用commit。因此,从这个角度来看,自动提交可能性能较差,因为每个语句都必须启动一个新事务。或者可能不是。只有基准测试会告诉我并且我敢打赌它不会对你的应用程序产生任何影响。

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

正如所指出的那样,存在隔离级别。这允许您进行多次读取,而不必担心是否有其他进程已经写入您的数据之间,使您的读取有效地处于原子状态。这样可以省去一小时调试竞争条件。

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

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

答案 2 :(得分:9)

如果要为默认超时以外的查询设置特定超时,或者如果要更改隔离级别,则只读事务需要事务。

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

DBA可能正在监视回滚活动,在这种情况下,任何默认的回滚行为都会使它们烦恼。

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