事务隔离级别
- 脏读
事务中可以读到未提交事务修改的数据。 - 不可重复读
事务中先后读取同一条记录,值不相同的现象。例如:A事务中读取一条数据,其值为1,B事务修改了其值为2,B事务提交后,A事务再次读取这条数据,其值变成了2。 - 幻读
事务中先后以某条件读取一张表,记录数不同的现象。
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
read uncommitted | √ | √ | √ |
read committed | × | √ | √ |
repeatable read | × | × | √ |
serialized | × | × | × |
1.读已提交(read committed)
PG中默认的隔离级别。 当一个事务运行使用这个隔离级别时, 一个查询(没有FOR UPDATE/SHARE子句)只能看到查询开始之前已经被提交的数据, 而无法看到未提交的数据或在查询执行期间其它事务提交的数据。
实际上,SELECT查询看到的是一个在查询开始运行的瞬间该数据库的一个快照。不过SELECT可以看见在它自身事务中之前执行的更新的效果,即使它们还没有被提交。
2.可重复读(repeatable read)
可重复读隔离级别只看到在事务开始之前被提交的数据,不过,查询能够看见在它的事务中之前执行的更新,即使它们还没有被提交。
这个级别与读已提交不同之处在于,一个可重复读事务中的查询看到 事务中第一个非事务控制语句开始时的一个快照, 而不是事务中当前语句开始时的快照。
当处于可重复读事务中时,如果要修改的记录,与事务开始时的数据快照不一致时,修改该记录会发生ERROR: could not serialize access due to concurrent update异常,导致回滚。
3.可序列化(serializable)
待补充
试验(基于Postgresql)
试验1
事务A隔离级别:read committed
事务B隔离级别:read committed
A:
begin transaction isolation level read committed;
update usr set name = 'admin' where id = 1;
//update语句在这条记录上增加了共享锁,其他事务可读不可写
B:
begin transaction isolation level read committed;
select * from usr where id = 1; //可以读
+----+-----------+
| id | name |
+----+-----------+
| 1 | admin1111 |
+----+-----------+
update usr set name = 'admin1111' where id = 1; //不可修改,发生了阻塞,等待上一事务结束
A:
commit;
B:
//阻塞停止,update生效
commit;
select * from usr where id = 1;
+----+-----------+
| id | name |
+----+-----------+
| 1 | admin1111 |
+----+-----------+
试验2
事务A隔离级别:repeatable read
事务B隔离级别:repeatable read
2.1 事务提交
A:
begin transaction isolation level repeatable read;
update usr set name = 'AAA' where id = 1;//加共享锁
B:
begin transaction isolation level repeatable read;
select * from usr where id =1;
+----+-----------+
| id | name |
+----+-----------+
| 1 | admin1111 |
+----+-----------+
update usr set name = 'BBB' where id = 1; //不可修改,发生了阻塞,等待上一事务结束
A:
commit;
B:
///阻塞停止,更新失败
ERROR: could not serialize access due to concurrent update
select * from usr where id =1;
+----+------+
| id | name |
+----+------+
| 1 | AAA |
+----+------+
2.2事务回滚
A:
begin transaction isolation level repeatable read;
update usr set name = 'AAA' where id = 1;//加共享锁
B:
begin transaction isolation level repeatable read;
select * from usr where id =1;
+----+-----------+
| id | name |
+----+-----------+
| 1 | admin1111 |
+----+-----------+
update usr set name = 'BBB' where id = 1; //不可修改,发生了阻塞,等待上一事务结束
A:
rollback;
B:
///阻塞停止,update生效
select * from usr where id =1;
+----+------+
| id | name |
+----+------+
| 1 | B |
+----+------+