繁体   English   中英

只读数据库访问的事务?

[英]Transactions for read-only DB access?

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

引自 DeveloperWorks 文章交易策略:模型和策略概述

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

作为相反的观点,以下引用来自 Hibernate 文档Non-transactional data access and the auto-commit mode

我们的建议是不要在应用程序中使用自动提交模式,并且仅在有明显的性能优势或未来代码更改的可能性很小时才应用只读事务。 无论您是读取数据还是写入数据,始终倾向于使用常规 ACID 事务来对数据访问操作进行分组。

也有EclipseLink的邮件列表上一个类似的争论在这里

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

据我所知,只有在隔离级别高于“已提交读”时才会有所作为。 这样对吗?

有哪些经验和建议?

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

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

如果当前没有正在进行的事务,标准 SQL 要求即使是查询也必须启动一个新事务。 有些 DBMS 不会发生这种情况——例如,那些具有自动提交模式的数据库管理系统(语句启动事务并在语句完成后立即提交)。 默认情况下,其他 DBMS 使语句具有原子性(有效地自动提交),但使用诸如“开始工作”之类的语句启动显式事务,在下一次提交或回滚之前取消自动提交(IBM Informix 动态服务器就是这样 - 当数据库不是 MODE 时) ANSI)。

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

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

首先,这听起来像是过早的优化。 正如 Steven 指出的那样,大多数健全的数据库无论如何都会将您置于事务中,而他们真正做的就是在每个语句之后调用 commit。 因此,从这个角度来看,自动提交的性能可能会降低,因为每个语句都必须启动一个新事务。 或者可能不是。 只有基准测试才能说明问题,我敢打赌它不会对您的应用程序产生任何影响。

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

正如所指出的,有隔离级别。 这使您可以进行多次读取,而不必担心是否有其他进程在它们之间写入了您的数据,从而使您的读取有效地原子化。 这将使您免于调试竞争条件的许多小时。

最后,您通常可以将事务设置为只读。 这会检查您的假设,并且在尝试写入时会出错。

这里有一篇很好的文章总结了这一切。 细节是特定于 Oracle 的,但概念是通用的。

如果要为查询设置特定超时而不是默认超时,或者要更改隔离级别,则只读操作需要事务。

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM