是否应该有一个读取查询的事务?

Posted

技术标签:

【中文标题】是否应该有一个读取查询的事务?【英文标题】:Should there be a Transaction for Read Queries? 【发布时间】:2010-09-23 11:03:43 【问题描述】:

我一直在阅读一些开发人员/dbas 建议在所有数据库调用中使用事务,甚至是只读调用。虽然我了解在事务中插入/更新,但在事务中读取有什么好处?

【问题讨论】:

【参考方案1】:

因此,您可以获得一致的数据库视图。想象一下,您有两个相互链接的表,但由于某种原因,您在伪代码中做了 2 次选择……

myRows = query(SELECT * FROM A)
moreRows = query(SELECT * FROM B WHERE a_id IN myRows[id])

如果在两个查询之间,有人更改 B 以删除一些行,那么您将遇到问题。

【讨论】:

并非总是如此。您的客户端实现可能会获取表的完整快照并显示预期结果。 ADO.NET 允许离线查询。 实际上这取决于很多事情,包括服务器的配置。问题问你为什么要在事务中放置一个 SELECT ......这就是原因。 +1 这个非常清晰的解释。是的,它取决于其他的东西(例如,当使用 Hibernate 或 NHibernate 时,对象在读取后会被缓存)但隔离是事务的四个原则之一,不应该忘记。【参考方案2】:

与 RoBorg 所说的类似,您将使用事务执行 SELECTS 以防止在语句之间读取幻像数据。 但是需要注意的是,SQL Server 中的默认事务隔离级别是 READ COMMITTED,它只会防止脏读;为了防止幻像数据,您至少必须使用可重复读取。 “仅在必要时使用此选项。”

http://msdn.microsoft.com/en-us/library/ms173763.aspx

【讨论】:

【参考方案3】:

过去几分钟我一直在检查这个,因为这是我应该了解的更多内容。这是我发现的。

如果您想在某人正在阅读记录时锁定该行并且不希望它被修改或读取,则事务在选择周围很有用。例如运行这些查询:

(在查询窗口 1 中)

开始传输 从 MYTABLE 中选择 * (ROWLOCK XLOCK) 其中 ID = 1

(在查询窗口 2 中)

从 MYTABLE 中选择 * 其中 ID = 1

(在窗口 1 中运行之前,查询窗口 2 不会返回结果)

提交传输

有用的链接:

http://msdn.microsoft.com/en-us/library/aa213039.aspx

http://msdn.microsoft.com/en-us/library/aa213026.aspx

http://msdn.microsoft.com/en-us/library/ms190345.aspx

我的目标是阻止某些东西 - 在那里添加 XLOCK 后它终于起作用了。简单地使用 ROWLOCK 是行不通的。我假设它正在发出共享锁(并且数据已被读取)..但我仍在探索这个。

添加 - WITH (UPDLOCK ROWLOCK) - 将让您选择行并将其锁定以进行更新,这将有助于并发。

小心使用表格提示。如果您开始随意应用它们,即使您的应用程序只有少量用户,您的系统也会变得缓慢。这是我在研究之前就知道的一件事;)

【讨论】:

【参考方案4】:

我会说,事务的主要目的之一是在出现任何问题时提供回滚潜力 - 仅在读取时已失效。

【讨论】:

【参考方案5】:

我发现“事务”在不同的 SQL 服务器上的行为非常不同。在某些情况下,启动事务会锁定所有其他连接,使其无法执行任何 SQL,直到事务提交或回滚 (MS SQLServer 6.5)。其他的没有任何问题,只有在有修改的时候才加锁(oracle)。锁甚至可以扩展到仅包含您的更改 - 单元锁/行锁/页锁/表锁。

通常我只在必须维护多个插入/删除/更新语句之间的数据完整性时才使用事务。尽管如此,我还是更喜欢使用 DB 定义的级联删除来实现这一点,以便数据库自动且原子地执行此操作。

如果您可以预见到要回滚多个修改的情况,请使用事务,否则,数据库将执行原子更新,而无需额外的代码来处理它。

【讨论】:

【参考方案6】:

为读取和插入而持有多个事务的另一个充分理由是,您希望根据从选择查询中获得的数据插入记录,并且您还希望提交插入的每个 X 行。

两笔交易:

    用于读取\选择。 用于插入并提交每 X 行。

将让你正确地做到这一点,而一个事务不分开读取和写入不会让你在不失去读者的情况下进行提交。

【讨论】:

【参考方案7】:

我建议您阅读快照隔离作为读取数据的事务有用性示例。

此外,这里是 Martin Kleppmann 所著的 Designing Data-Intensive Applications 一书中的摘录,其中指出了两种情况,即使您只是从数据库中读取数据,也需要一些类似事务的行为:

备份 进行备份需要制作整个数据库的副本,这可能需要 大型数据库上的小时数。在备份过程运行期间, 将继续对数据库进行写入。因此,您最终可能会得到 包含旧版本数据的备份的某些部分,以及其他部分 包含较新的版本。如果您需要从此类备份中恢复,则 不一致(例如消失的钱)成为永久性的。

分析查询和完整性检查 有时,您可能希望运行一个扫描大部分数据的查询- 根据。此类查询在分析中很常见(请参阅“事务处理或分析 溶解剂?”第 90 页),或者可能是定期完整性检查的一部分 是有序的(监控数据损坏)。这些查询可能会返回 如果他们在不同的时间点观察数据库的某些部分,则会得出无意义的结果 时间。

【讨论】:

以上是关于是否应该有一个读取查询的事务?的主要内容,如果未能解决你的问题,请参考以下文章

在同一事务上读取和修改 - Bigtable

使事务锁定一行以在 MariaDB 上读取

如何读取 Zookeeper 事务日志?

SQL Server 死锁与事务隔离级别读取未提交

事务的隔离级别

mysql pdo 事务和会话存储