via*_*tor 5 concurrency transaction isolation-level consistency
到目前为止,我读过的所有谈论事务的书籍都展示了涉及多个 SQL 语句的场景。
但是单个语句又如何呢?他们的隔离程度如何?标准中是否有指定?或者它取决于 RDBMS 和隔离级别?
让我举几个例子。
UPDATE table SET value = value + 1 WHERE id = 1;
这是一个复合read-update-write
操作。read
并行事务可以改变和write
操作之间的值吗?有些书指出,在大多数RDBMS中,此操作是原子的(在多线程编程意义上) 。
SELECT * FROM table t1 JOIN table t2 USING (id);
如果表很大(或者查询会有一些复杂的过滤子句),在某些隔离级别上,列t1.*
和t2.*
列是否可能因并行更新而有所不同?
SELECT * FROM table1 WHERE id IN (SELECT t_id FROM table2);
table1
执行子选择后是否有可能删除一些记录?(这里我假设table2.t_id
引用table1.id
具有级联删除功能。)
热膨胀系数...
还可以提供有用手册的链接,这些手册充分解释了交易的所有细节。
对于 SQL Server:
但是单个语句又如何呢?
在SQL Server中,有4个事务隔离级别(在悲观锁定模型中)。默认事务隔离级别为Read Committed
,锁放置在语句级别。如果您有一个事务,其中有 2 个语句检索相同的数据,并且在该事务的中间(在第一个语句之后但在第二个语句开始之前),某个其他事务修改了第一个事务检索的数据,然后是第一个事务将在第一个和第二个语句中返回不同的数据。
这就是所谓的不可重复读取问题。这可以通过将事务隔离级别增加到REPEATABLE READ
事务级别(而不是语句级别)上发生锁定的位置来解决
UPDATE table SET value = value + 1 WHERE id = 1;
平行交易可以改变价值吗?
不,不能。这是单个语句,在执行期间,排它锁被放置在正在修改的行上。
在我们的更新语句完成之前,没有其他事务或语句可以修改这些行
SELECT * FROM table t1 JOIN table t2 USING (id);
在某些隔离级别,t1.* 和 t2.* 列是否可能因并行更新而有所不同?
是的,inREAD UNCOMMITED
是可能的(或者当指定 with (NOLOCK) 提示时),因为未应用共享锁。在其他隔离级别 - 否,因为共享锁被放置在 t1 和 t2 的行上,并且在此期间不能修改行(其他事务无法获取独占锁)
SELECT * FROM table1 WHERE id IN (SELECT t_id FROM table2)
执行子查询后是否有可能删除 table1 中的某些记录?
在READ UNCOMMITTED
是可能的。在更高的隔离级别 - 不可能,因为在执行该语句期间,共享锁被放置在 table1 和 table2 的所有选定行上,并且没有其他事务能够修改 table1 和 table2 的行(放置排他锁),直到我们选择语句完成并从 table1 和 table2 释放共享锁
在这里您可以阅读有关 SQL Server 隔离级别的更多信息: https://learn.microsoft.com/en-us/sql/t-sql/statements/set-transaction-isolation-level-transact-sql ?view=sql-服务器版本15