我一直在阅读一些开发人员/数据库管理员建议在所有数据库调用中使用事务,甚至是只读调用。虽然我了解在事务中插入/更新,但在事务中读取有什么好处?
7 回答
因此,您可以获得一致的数据库视图。想象一下,您有两个相互链接的表,但由于某种原因,您在伪代码中做了 2 次选择:
myRows = query(SELECT * FROM A)
moreRows = query(SELECT * FROM B WHERE a_id IN myRows[id])
如果在两个查询之间,有人更改 B 以删除一些行,那么您将遇到问题。
与 RoBorg 所说的类似,您将使用事务执行 SELECTS 以防止读取语句之间的幻像数据。但重要的是要注意 SQL Server 中的默认事务隔离级别是 READ COMMITTED,它只会防止脏读;为了防止幻像数据,您至少必须使用可重复读取。“仅在必要时使用此选项。”
过去几分钟我一直在检查这个,因为这是我应该了解更多的事情。这是我发现的。
如果您想在某人正在阅读记录时锁定该行并且不希望它被修改或读取,则事务在选择周围很有用。例如运行这些查询:
(在查询窗口 1 中)
BEGIN TRAN SELECT * FROM MYTABLE WITH (ROWLOCK XLOCK) WHERE ID = 1
(在查询窗口 2 中)
从 ID = 1 的 MYTABLE 中选择 *
(在窗口 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) - 将允许您选择行并将其锁定为更新,这将有助于并发。
注意表格提示。如果您开始随意应用它们,即使您的应用程序只有少量用户,您的系统也会变得缓慢。这是我在研究之前就知道的一件事;)
我想说,事务的主要目的之一是在出现任何问题时提供回滚潜力——这在简单阅读时已经失效。
我发现“事务”在不同的 SQL 服务器上表现得非常不同。在某些情况下,启动事务会锁定所有其他连接,使其无法执行任何 SQL,直到事务提交或回滚 (MS SQLServer 6.5)。其他的没有任何问题,只有在有修改的时候才加锁(oracle)。锁甚至可以扩展到仅包含您的更改 - 单元锁/行锁/页锁/表锁。
通常,我仅在必须维护多个插入/删除/更新语句之间的数据完整性时才使用事务。尽管如此,我还是更喜欢使用 DB 定义的级联删除来实现这一点,以便数据库自动且原子地执行此操作。
如果您可以预见到要回滚多个修改的情况,请使用事务,否则,数据库将执行原子更新,而无需额外的代码来处理它。
为读取和插入而持有多个事务的另一个很好的理由是,您希望根据从选择查询中获得的数据插入记录,并且您还希望提交插入的每个 X 行。
两笔交易:
- 对于读取\选择。
- 用于插入并提交每 X 行。
将让你正确地做到这一点,而一个事务不分离读取和写入不会让你在不失去读者的情况下进行提交。
我建议您阅读快照隔离作为读取数据的事务有用性的示例。
此外,这里是 Martin Kleppmann 所著的 Designing Data-Intensive Applications 一书的摘录,其中指出了两种情况,即使您只从数据库中读取数据,也需要一些类似于事务的行为:
备份
进行备份需要制作整个数据库的副本,这在大型数据库上可能需要数小时。在备份过程运行期间,将继续对数据库进行写入。因此,您最终可能会得到包含旧版本数据的备份的某些部分,而其他部分包含更新版本的数据。如果您需要从此类备份中恢复,则不一致(例如消失的钱)将成为永久性的。
分析查询和完整性检查
有时,您可能希望运行一个扫描大部分数据库的查询。此类查询在分析中很常见(请参阅第 90 页的“事务处理或分析?”),或者可能是定期完整性检查以确保一切正常(监控数据损坏)的一部分。如果这些查询在不同时间点观察数据库的某些部分,它们可能会返回无意义的结果。