给出以下SQL伪代码:
... open transaction ...
SELECT * FROM users WHERE users.id = 5
... some calculation here ...
INSERT INTO users (id) VALUES (5)
... commit transaction ...
REPEATABLE_READ isolation是否可以防止并发连接在查询和插入之间插入Users[id=5]
,或者我是否需要使用SERIALIZABLE
隔离?
注意:如果可能,我正在寻找与数据库无关的解决方案。如果没有,请提供来自多个数据库的经验证据,以便我们可以反对某种行业共识。
更新:原始问题包含使用范围锁定的错误查询。由于此问题的目的是关注不需要范围锁定的查询,因此我更新了问题。
答案 0 :(得分:3)
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行,则计数结果为:
在可序列化模式下,每个事务都以单一模式执行,因此当事务不以提交或回滚结束时,没有一个事务可以启动。如果这种模式保证数据库的一致性有严重的性能问题。
修改强>
来自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的隔离级别 事务默认为SERIALIZABLE。级别可以明确 由。设置。
在隔离级别执行并发SQL事务 SERIALIZABLE保证可序列化。可序列化的exe- cution被定义为执行同意的操作 正在执行产生与之相同效果的SQL事务 一些串行执行那些相同的SQL事务。连续执行 cution是每个SQL事务执行完成的一个 在下一个SQL事务开始之前。
隔离级别指定可能发生的现象类型 在并发SQL事务的执行期间。下列 现象是可能的:
1)P1("脏读"):SQL事务T1修改一行。 SQL- 然后,事务T2在T1执行COMMIT之前读取该行。 如果T1然后执行ROLLBACK,T2将读取一行 从来没有承诺,因此可能被认为从来没有 存在。
2)P2("不可重复读"):SQL事务T1读取一行。 SQL- 事务T2然后修改或删除该行并执行 一个COMMIT。如果T1然后尝试重新读取该行,它可能会收到 修改后的值或发现该行已被删除。
3)P3(" Phantom"):SQL事务T1读取行集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将等待事务2在时间5上获得的锁定释放,但在时间7中,事务2 mus等待时间4中事务1获得的锁定。不同的RDBMS管理死锁以不同的方式举例来说,带有InnoDB的MySQL将为事务2引发死锁异常,让事务1完成。
有一些有趣的文章:
祝你好运
答案 1 :(得分:1)
没有。 REPEATABLE_READ
隔离级别仅保证在同一事务中重复SELECT
时将看到相同的数据,这意味着(SQL)实现可能会隐藏其他事务执行的事务插入。
能够阻止插入的唯一隔离级别是SERIALIZABLE
,因为它保证如果您同时运行多个事务,结果就好像它们按特定顺序按顺序运行。每种情况下的具体顺序都没有指定也没有报告,但保证存在一个产生相同最终结果的顺序。
问题的一个条件是数据库不可知(我假设高级答案),所以我不会提到不同的隔离级别如何在不同的数据库实现中工作或它们如何转换为锁。