REPEATABLE_READ
不会挡住桌子。它保证事务在任何时候都看到相同的行。让我通过一个例子来解释它:
Time Transaction 1 Transaction2
1 Begin Tx 1
2 Begin Tx 2
4 Select count(*) from my_tab;
5 Select count(*) from my_tab;
6 Insert into ... my_tab;
7 Commit;
8 Select count(*) from my_tab;
9 Insert into ... my_tab;
10 Select count(*) from my_tab;
11 Commit;
12 Begin Tx3
13 Select count(*) from my_tab;
如果 my_tab 有 10 行,那么计数的结果将是:
- 时间 4 : 10 行
- 时间 5 : 10 行
- 时间 8 : 10 行,因为表处于 repeateble_read 模式,如果事务模式为 read_commited 也将是 10 行。但如果 Tx 设置为 en read_uncommited,则行数将为 11。
- 时间 10:由于它处于可重复读取模式,因此计数将为 11 行(十个原件加上当前事务中的一个插入)。如果 tx 模式为 read_commited,则行数将为 12(10 个原件加上 tx1 的 1 个插入和当前 tx 的 1 个插入)。
- 时间 13:这里所有事务模式的行数都是 12。
在可序列化模式下,每个事务都以单一模式执行,因此当事务不以提交或回滚结束时,没有一个事务可以启动。如果这种模式保证数据库的一致性会有严重的性能问题。
编辑
来自http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt中托管的 SQL-92 标准(第 67 和 68 页)(从维基百科获得):
SQL 事务的隔离级别为 READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ 或 SERIALIZABLE。SQL 事务的隔离级别定义了对该 SQL 事务中的 SQL 数据或模式的操作受并发 SQL 事务中的 SQL 数据或模式的操作影响的程度,并可能影响对 SQL 数据或模式的操作。SQL 事务的隔离级别默认为 SERIALIZABLE。级别可以由 .
在隔离级别 SERIALIZABLE 的并发 SQL 事务的执行保证是可序列化的。可串行执行被定义为并行执行 SQL 事务的操作的执行,其产生与那些相同 SQL 事务的某些串行执行相同的效果。串行执行是每个 SQL 事务在下一个 SQL 事务开始之前执行完成。
隔离级别指定并发 SQL 事务执行期间可能发生的现象类型。可能出现以下现象:
1) P1 ("Dirty read"): SQL-transaction T1 修改一行。SQL 事务 T2 然后在 T1 执行 COMMIT 之前读取该行。如果 T1 然后执行 ROLLBACK,则 T2 将读取从未提交的行,因此可能被认为从未存在过。
2)P2(“Non-repeatable read”):SQL-transaction T1 读取一行。SQL-事务 T2 然后修改或删除该行并执行 COMMIT。如果 T1 然后尝试重新读取该行,它可能会收到修改后的值或发现该行已被删除。
3) P3 ("Phantom"):SQL 事务 T1 读取满足 some 的行集 N。SQL 事务 T2 然后执行 SQL 语句,生成满足 SQL 事务 T1 使用的一个或多个行。如果 SQL 事务 T1 然后用相同的 重复初始读取,它将获得不同的行集合。
四个隔离级别保证每个 SQL 事务将被完全执行或根本不执行,并且不会丢失任何更新。对于现象 P1、P2 和 P3,隔离级别不同。表 9,“SQL 事务隔离级别和三种现象”指定了给定隔离级别可能和不可能的现象。
Level P1 P2 P3
---------------------------------------------------------
| READ UNCOMMITTED | Possible | Possible | Possible |
---------------------------------------------------------
| READ COMMITTED | Not | | |
| | Possible | Possible | Possible |
---------------------------------------------------------
| REPEATABLE READ | Not | Not | |
| | Possible | Possible | Possible |
---------------------------------------------------------
| SERIALIZABLE | Not | Not | Not |
| | Possible | Possible | Possible |
---------------------------------------------------------------
| |
| Note: The exclusion of these phenomena or SQL-transactions |
| executing at isolation level SERIALIZABLE is a |
| consequence of the requirement that such transactions |
| consequence of the be serializable. |
---------------------------------------------------------------
编辑 2
好的,您对锁和块感兴趣,此时 RDMS 提供程序如何实现这一点可能会有所不同(例如 SQL Server 太奇怪了),但对于全局而言,这可能很有用,以下解释适用于您尝试修改/读取相同的数据(行)。RDMS 执行事务时有两种类型的锁:
- 共享锁:这种锁允许其他事务访问数据。例如,许多事务可以同时读取相同的数据。
- 排他锁:这种锁会阻塞资源,避免其他事务访问它,例如两个事务不能同时修改相同的数据,尝试修改资源的事务必须检查是否没有排他锁资源。如果资源上没有排他锁,则事务获得排他锁,直到它释放锁,没有一个事务可以获得锁,必须等待排他锁的释放。
这里的第二点是:什么被锁定?通常有两种类型的锁:
- 表级锁:当一个事务试图修改数据时,该事务获得所有表的排他锁,其他事务必须等待该事务释放锁。
- 行级锁:当一个事务试图修改数据时,该事务获得了该事务所涉及的行的排他锁,其他想要修改同一行子集的事务必须等到第一个事务结束。
关于死锁的注意事项,想象以下场景:
Time Transaction 1 Transaction 2
1 Begin Tx 1
2 Begin Tx 2
4 Update table X set... where id = 5
5 Update table X set ... where id = 5;
6 Update table X set... where id = 6
7 Commit;
8 Commit;
如果数据库配置为行级锁,那么事务 2 将在时间 5 等待到时间 7,因为事务 1 首先获得排他锁。现在想象以下示例:
Time Transaction 1 Transaction 2
1 Begin Tx 1
2 Begin Tx 2
4 Update table X set... where id = 5
5 Update table X set ... where id = 6;
6 Update table X set... where id = 6
7 Update table X set ... where id = 5;
8 Commit;
9 Commit;
这种情况被称为“死锁”,因为在时间 6 中,事务 1 将等待在时间 5 上由事务 2 获得的锁的释放,但在时间 7 中,事务 2 必须等待由事务 1 及时获得的锁4.不同的RDBMS管理死锁的方式不同,例如MySQL with InnoDB会为Transaction 2引发死锁异常,让Transaction 1正常完成。
有一些有趣的文章:
最好的祝福