让我们假设以下情形:
[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]
同样的问题 - 数据库如何通过交易信息运行联接?
答案 0 :(得分:3)
让我们将数据库表视为B-Tree。让我谈谈数据结构上的几个词 - 我们应该知道B-tree页面组织的主题。假设您有9行(标记自A..I
)和B-tree,页面大小= 3。某种方式我们在磁盘上有3个页面
Page1: A,B,C,
Page2: D,E,F
Page3: G,H,I
假设您更改了行E
中的内容。您的数据库连接将为page2分配内存并完全加载它(D..F
)。您对E
进行了更改,但未提交事务。现在您尝试选择(在相同的连接中)。由于内存已包含页面加载,因此SELECT将查看已修改的数据。
但是,如果另一个连接将尝试加载E
,则必须加载到内存in-mutable D..F
page2。在提交第2页后,所有其他连接都可以看到更改。
当然在现实世界中这个过程要复杂得多。
答案 1 :(得分:2)
我建议阅读以下文章:
SQL Server 2005 Row Versioning-Based Transaction Isolation
虽然这篇文章是关于Sql Server 2005的,但它总结了各种类型的并发控制:
有两个主要模型用于控制并发: 悲观并发和乐观并发。
在基于悲观并发控制的系统中,锁被用于 阻止用户以影响其他用户的方式修改数据。 应用锁定后,其他用户无法执行该操作 在所有者释放它之前会与锁冲突。这个级别 控制用于存在高争用的环境中 数据,以及使用锁保护数据的成本较低 如果或当并发时回滚事务的成本 冲突发生。
相反,在基于乐观并发控制的系统中,用户 在读取数据时不要锁定数据。执行更新时, 系统检查后是否有其他用户更改了数据 它被阅读了。如果另一个用户更新了数据,则会引发错误。 通常,收到错误的用户回滚 事务,然后重新提交事务。这就是所谓的 乐观并发,因为它主要用于其中的环境 数据争用率低,偶尔会有成本 回滚事务会超过锁定数据的成本 正在阅读。
使用行版本控制读取已提交的隔离介于两者之间 悲观和乐观的并发。在这种隔离级别下, 读取操作不会获取实时数据的锁定。然而, 对于此隔离,对于更新操作,该过程是相同的 与默认的读提交隔离级别相同的级别: 选择要更新的行是通过使用阻塞扫描来完成的 读取数据值时,将对数据行进行更新锁定。
另一方面,快照隔离真的很乐观,因为 要修改的数据实际上并未事先锁定,而是 选择进行修改时,数据将被锁定。当一个数据行 满足更新条件,快照事务验证 快照后,另一个事务未修改数据 交易开始了。如果数据未被其他人修改 事务,快照事务锁定数据,更新 数据,释放锁定并继续前进。如果数据已被修改 通过另一个事务,发生更新冲突和快照 交易回滚。
与建议的注释一样,所使用的并发控制类型不仅因所使用的数据库平台而异,而且根据所使用的设置在平台内也有所不同。
答案 2 :(得分:0)
对于任何事务隔离级别,您都可以访问同一事务中的脏数据。