我们知道数据库事务具有原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)四个特性,简称 ACID。那什么是隔离性呢?
在一个事务中可以读到其他未提交的事务产生或变更的数据。
-- 脏读测试
SQL> create table test_uncommitted(id int, info varchar);
操作已执行
SQL> insert into test_uncommitted values (1, 'test');
影响行数 1
SQL> commit;
操作已执行
SQL> SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
操作已执行
SQL> select * from test_uncommitted;
行号 ID INFO
---------- ----------- ----
1 1 test
-- 其他会话更新这份数据, 但不提交.
SQL> update test_uncommitted set info='new' where id=1;
影响行数 1
-- 脏读出现
SQL> select * from test_uncommitted;
行号 ID INFO
---------- ----------- ----
1 1 new
不可重复读指的是在同一事务内,不同的时刻读到的同一批数据可能是不一样的,可能会受到其他事务的影响,比如其他事务改了这批数据并提交了。通常指数据更新(UPDATE)操作。
-- 不可重复读测试
SQL> create table test_unrepeatable(id int, info varchar);
操作已执行
SQL> insert into test_unrepeatable values (1, 'test');
影响行数 1
SQL> commit;
操作已执行
SQL> SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
操作已执行
SQL> select * from test_unrepeatable where id=1;
行号 ID INFO
---------- ----------- ----
1 1 test
-- 其他会话更新这份数据, 并提交.
SQL> update test_unrepeatable set info='new' where id=1;
影响行数 1
SQL> commit;
操作已执行
-- 不可重复读出现.
SQL> select * from test_unrepeatable where id=1;
行号 ID INFO
---------- ----------- ----
1 1 new
在一个事务中, 再次执行同样的SQL, 得到的结果可能不一致。通常指数据插入(INSERT)操作。
-- 幻读测试
SQL> create table test_phantom(id int, info varchar);
操作已执行
SQL> insert into test_phantom values (1, 'test');
影响行数 1
SQL> commit;
操作已执行
SQL> SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
操作已执行
SQL> select * from test_phantom;
行号 ID INFO
---------- ----------- ----
1 1 test
-- 其他会话新增数据
SQL> insert into test_phantom values (2, 'new');
影响行数 1
SQL> commit;
操作已执行
-- 幻读出现
SQL> select * from test_phantom;
行号 ID INFO
---------- ----------- ----
1 1 test
2 2 new
事务隔离其实就是为了解决上面提到的脏读、不可重复读、幻读这几个问题,下面展示了 4 种隔离级别对这三个问题的解决程度。
隔离级别 \ 解决 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
未提交读 | 可能 | 可能 | 可能 |
已提交读 | 不可能 | 可能 | 可能 |
可重复读 | 不可能 | 不可能 | 可能 |
可串行化 | 不可能 | 不可能 | 不可能 |
注:对于可重复读能否解决幻读问题,只有Mysql的可重复读隔离级别在不加间隙锁(Next-Key锁)的情况下,才可能出现幻读。 |
隔离级别 \ 数据库 | 达梦 | Oracle | Postgresql | Mysql(InnoDB) |
---|---|---|---|---|
未提交读 | 支持 | 不支持 | 不支持 | 支持 |
已提交读 | 支持(默认) | 支持(默认) | 支持(默认) | 支持 |
可重复读 | 支持 | 支持 | 支持 | 支持(默认) |
可串行化 | 支持 | 支持 | 支持 | 支持 |
未提交读隔离级别是最不严格的隔离级别,在使用这个隔离级别时,会发生脏读、不可重复读和幻读。一般来说,未提交读隔离级别通常只用于访问只读表和只读视图,以消除可见性判断带来的系统开销,提升查询性能,该级别下事务为只读模式。
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
数据库的已提交读隔离级别可以确保只访问到已提交事务修改的数据,保证数据处于一致性状态。
默认就是已提交读隔离级别
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
在达梦数据库中可重复读隔离级别可以避免不可重复读和幻读问题,为了在并发环境下得到一个稳定结果,比如,财务对账中,我们可以设置可重复读事务隔离级别。可重复读相对于序列化在性能上能更灵活一些。
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
在要求消除不可重复读或幻读的情况下,我们可以设置事务隔离级为可串行化。跟已提交读隔离级别相比,可串行化事务的查询本身不会增加任何代价,但修改数据可能引发“串行化事务被打断”的错误。
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
设置事务隔离级别必须在事务开启之前,事务开启后,再修改事务隔离级别将会报错:试图在事务运行中,改变其属性。
文章
阅读量
获赞