3

让我们假设以下场景:

[Start TX]
SELECT userName FROM users WHERE userId = 1; -- returns x
UPDATE users SET userName = 'y' where userId = 1;
SELECT userName FROM users WHERE userId = 1; -- returns y
[End TX]

数据库如何知道第二次返回 y?事务状态如何集成到查询处理中?

另一种情况:

[Start TX]
SELECT userName FROM users, accounts WHERE useres.userId = accounts.userId AND accounts.balance < 0; -- returns x
UPDATE accounts SET balance = 100 where userId = 1;
SELECT userName FROM users, accounts WHERE useres.userId = accounts.userId AND accounts.balance < 0; -- returns nothing
[End TX]

同样的问题 - 数据库如何在事务信息上运行连接?

4

3 回答 3

5

让我们将数据库表视为B-Tree。让我谈谈它的数据结构 - 对于您的主题,我们应该知道 B-tree 是页面组织的。假设您有 9 行(从 标记A..I)和页面大小 = 3 的 B 树。以某种方式,我们在磁盘上有 3 页

Page1: A,B,C,
Page2: D,E,F
Page3: G,H,I

假设您已经更改了 row 中的某些内容E。您的数据库连接将为 page2 分配内存并完全加载它 ( D..F)。您进行了更改,E但未提交事务。现在您尝试选择(在同一连接中)。由于内存已经包含加载的页面,您的 SELECT 将看到已修改的数据。但是,如果另一个连接将尝试加载E它必须加载到内存中的可变D..F页面 2。提交 page2 被持久化后,所有其他连接都可以看到更改。

当然在现实世界中这个过程要复杂得多。

于 2012-12-06T16:12:12.280 回答
2

我建议阅读以下文章:

SQL Server 2005 基于行版本的事务隔离

虽然这篇文章专门针对 Sql Server 2005,但它对各种类型的并发控制进行了很​​好的总结:

控制并发有两种主要模型:悲观并发和乐观并发。

在基于悲观并发控制的系统中,锁用于防止用户以影响其他用户的方式修改数据。应用锁后,其他用户无法执行与锁冲突的操作,直到所有者释放它。这种级别的控制用于数据竞争激烈的环境中,并且在发生并发冲突时使用锁保护数据的成本低于回滚事务的成本。

相反,在基于乐观并发控制的系统中,用户在读取数据时不会锁定数据。执行更新时,系统会检查其他用户是否在读取数据后对其进行了更改。如果另一个用户更新了数据,则会引发错误。通常,收到错误的用户会回滚事务,然后重新提交事务。这被称为乐观并发,因为它主要用于数据争用较少的环境,并且偶尔回滚事务的成本超过读取数据时锁定数据的成本。

使用行版本控制的读取提交隔离介于悲观和乐观并发之间。在此隔离级别下,读取操作不会针对实时数据获取锁。但是,对于更新操作,此隔离级别的过程与默认已提交读隔离级别的过程相同:要更新的行的选择是通过使用阻塞扫描完成的,其中将数据行上的更新锁作为数据获取值被读取。

另一方面,快照隔离是真正乐观的,因为要修改的数据实际上并没有提前锁定,而是在选择修改时锁定了数据。当数据行满足更新条件时,快照事务会验证该数据在快照事务启动后未被其他事务修改。如果数据没有被另一个事务修改,快照事务会锁定数据,更新数据,释放锁,然后继续。如果数据已被另一个事务修改,则会发生更新冲突,快照事务会回滚。

就像建议的评论一样,使用的并发控制类型不仅因所使用的数据库平台而异,而且在平台内也因所使用的设置而异。

于 2012-12-06T16:00:56.660 回答
0

对于任何事务隔离级别,您都可以访问来自同一事务的脏数据。

于 2012-12-06T15:32:14.433 回答