注册
达梦事务隔离
专栏/培训园地/ 文章详情 /

达梦事务隔离

Light 2023/11/07 1294 0 0
摘要

1数据读的概念

1.1脏读(DirtyRead)

所谓脏读就是对脏数据的读取,而脏数据所指的就是未提交的已修改数据。也就是说,一个事务正在对一条记录做修改,在这个事务完成并提交之前,这条数据是处于待定状态的 (可能提交也可能回滚),这时,第二个事务来读取这条没有提交的数据,并据此做进一步的处理,就会产生未提交的数据依赖关系,这种现象被称为脏读。

1.2不可重复读(Non-RepeatableRead)

一个事务先后读取同一条记录,但两次读取的数据不同,我们称之为不可重复读。如果一个事务在读取了一条记录后,另一个事务修改了这条记录并且提交了事务,再次读取记录时如果获取到的是修改后的数据,这就发生了不可重复读情况。

1.3幻像读(PhantomRead)

一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为幻像读。

2SQL-92标准中的四种隔离级别

读未提交:容许脏读,容许不可重复读,容许幻想读。
读提交:不容许脏读,容许不可重复读,容许幻像读。
可重复读:不容许脏读,不容许不可重复读,容许幻像读。
串行化:不容许脏读,不容许不可重复读,不容许幻像读。

3达梦的隔离级别

DM数据库支持三种事务隔离级别:读未提交、读提交和串行化。其中,读提交是 DM 数据库默认使用的事务隔离级别。可重复读升级为更严格的串行化隔离级。
启动会话ISO_LEVEL :隔离级。
0:读未提交;1:读提交;2:可重复读;3:串行化。

3.1读未提交隔离级别

读未提交隔离级别是最不严格的隔离级别。实际上,在使用这个隔离级别时,有可能发生脏读、不可重复读和幻像。一般来说,读未提交隔离级别通常只用于访问只读表和只读视图,以消除可见性判断带来的系统开销,提升查询性能。

会话1创建表,插入一条数据:
SQL> create table test(id int,name varchar(50));
操作已执行
已用时间: 13.660(毫秒). 执行号:602.
SQL> insert into test values(1,'shi');
影响行数 1
已用时间: 1.994(毫秒). 执行号:603.
SQL> commit ;
操作已执行
已用时间: 1.521(毫秒). 执行号:604.

会话1,2均更改事务隔离为读未提交:
SQL> SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
操作已执行
已用时间: 0.600(毫秒). 执行号:629.
查询两个会话的隔离级别:
SQL> select sess_id,isolation from v$trx;
行号 SESS_ID ISOLATION


1 140712859476344 0
2 140714671417672 0

会话1更新数据不提交:
SQL> select * from test;
行号 ID NAME


1 1 shi
已用时间: 0.673(毫秒). 执行号:631.
SQL> update test set name = 'rang' where id=1;
影响行数 1
已用时间: 2.355(毫秒). 执行号:632.
SQL> select * from test;
行号 ID NAME


1 1 rang
已用时间: 0.674(毫秒). 执行号:633.
SQL> select sessid;
行号 SESSID


1 140712859476344
已用时间: 0.711(毫秒). 执行号:634.
会话1更改后,未提交,但当前会话查看数据,已更改。

会话2查询该表,此时查到的数据为会话1未提交的数据:
SQL> select * from test;
行号 ID NAME


1 1 rang
已用时间: 0.841(毫秒). 执行号:711.
SQL> select sessid;
行号 SESSID


1 140714671417672
已用时间: 0.756(毫秒). 执行号:712.

3.2读已提交隔离级别

DM 数据库的读提交隔离可以确保只访问到已提交事务修改的数据,保证数据处于一致性状态,能够满足大多数应用的要求,并最大限度的保证系统并发性能,但可能会出现不可重复读取和幻像读。

会话1,2均更改事务隔离级别为读已提交:
SQL> SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
操作已执行
已用时间: 0.344(毫秒). 执行号:607.
查询两个会话的隔离级别(达梦默认也是读已提交):
SQL> select sess_id,isolation from v$trx;
行号 SESS_ID ISOLATION


1 140459724841400 1
2 140461805285640 1
已用时间: 0.533(毫秒). 执行号:608.

会话1查询数据:
SQL> select sessid;
行号 SESSID


1 140459724841400
已用时间: 1.813(毫秒). 执行号:611.
SQL> select * from test;
行号 ID NAME


1 1 shi
已用时间: 3.282(毫秒). 执行号:609.

会话1更新一条数据,不提交:
SQL> update test set name='rang' where id=1;
影响行数 1
已用时间: 10.619(毫秒). 执行号:610.
SQL>

会话1查询数据:
SQL> select * from test;
行号 ID NAME


1 1 rang
已用时间: 0.798(毫秒). 执行号:612.

会话2查询数据:
SQL> select sessid;
行号 SESSID


1 140461805285640
已用时间: 0.767(毫秒). 执行号:701.
SQL> select * from test;
行号 ID NAME


1 1 shi
已用时间: 0.627(毫秒). 执行号:702.
会话1提交后,会话2查询数据:
SQL> select * from test;
行号 ID NAME


1 1 rang
已用时间: 0.727(毫秒). 执行号:703.
SQL> select sessid;
行号 SESSID


1 140461805285640
已用时间: 0.550(毫秒). 执行号:704

3.3串行化隔离级别

在要求消除不可重复读取或幻像读的情况下,我们可以设置事务隔离级为串行化。跟读 提交隔离级相比,串行化事务的查询本身不会增加任何代价,但修改数据可能引发“串行化 事务被打断”错误。 具体来说,当一个串行化事务试图更新或删除数据时,而这些数据在此事务开始后被其他事务修改并提交时,DM 数据库将报“串行化事务被打断”错误。应用开发者应该充分考虑 串行化事务带来的回滚及重做事务的开销,从应用逻辑上避免对相同数据行的激烈竞争导致产生大量事务回滚。并结合应用逻辑,捕获“串行化事务被打断”错误,进行事务重做等相应处理。如果系统中存在长时间运行的写事务,并且该长事务所操作的数据还会被其他短事务频繁更新的话,最好避免使用串行化事务。

会话1,2均更改事务隔离级别为串行化:
SQL> SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
操作已执行
已用时间: 0.599(毫秒). 执行号:648.

查询两个会话的隔离级别:
SQL> select sess_id,isolation from v$trx;
行号 SESS_ID ISOLATION


1 148060680 3
2 160894536 3
已用时间: 2.114(毫秒). 执行号:59407.

会话1查询事务ID及内容:
SQL> select TRXID,id,name from test where id=1;
行号 TRXID ID NAME


1 3677 1 rang

会话1更新一条数据,不提交查询:
QL> update test set name='xian' where id = 1;
影响行数 1
已用时间: 1.178(毫秒). 执行号:59409.
SQL> select TRXID,id,name from test where id=1;
行号 TRXID ID NAME


1 3681 1 xian

会话2查询:
SQL> select TRXID,id,name from test where id=1;
行号 TRXID ID NAME


1 3677 1 rang

会话1提交,查询:
SQL> commit;
操作已执行
已用时间: 2.928(毫秒). 执行号:59412.
SQL> select TRXID,id,name from test where id=1;
行号 TRXID ID NAME


1 3681 1 xian
已用时间: 0.387(毫秒). 执行号:59413.

会话2查询:
SQL> select TRXID,id,name from test where id=1;
行号 TRXID ID NAME


1 3677 1 rang
已用时间: 0.837(毫秒). 执行号:59503.
停90秒后再查询(UNDO_RETENTION值为90):
SQL> /
select TRXID,id,name from test where id=1;
[-7120]:回滚记录版本太旧,无法获取用户记录.
已用时间: 0.528(毫秒). 执行号:0.
查询到的记录和之前一致,并没有因为会话1提交了记录发生改变;停90秒后再查询也可看出查的是历史数据。

4总结

达梦支持3种隔离级别(可重复读升级为更严格的串行化隔离级);日常生活中几乎所有环境均为读提交隔离级别,这也是达梦的默认隔离级别。

评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服