一、事务简单介绍:
数据库的事务是指一组SQL语句组成的数据库逻辑处理单元,在这组的SQL操作中,要么全部执行成功,要么全部执行失败。
二、事务四大特性:
如果一个数据库支持事务的操作,那么该数据库必须要具备事务的四大特性(简称ACID),二事务的四大特性主要包含:原子性、一致性、隔离性、持久性。
⑴ 、原子性
原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,这和前面两篇博客介绍事务的功能是一样的概念,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
⑵ 、一致性
一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
⑶ 、隔离性
隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
⑷ 、持久性
持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
三、事务隔离级别
在关系型数据库中事务的隔离级别分为四大等级,读未提交(READ UNCOMMITTED)、读已提交(READ COMMITTED)、可重复读(REPEATABLE READ)、串行化(SERIALIZABLE)。DM数据库支持三种事务的隔离级别:读未提交、读提交和可串行化。DM数据库默认使用的事务隔离级别是读已提交,MySQL数据库默认使用的事务隔离级别是可重复读。
隔离级别\数据库 | 达梦 | Oracle | MySQL |
未提交读 | 支持 | 不支持 | 支持 |
已提交读 | 支持(默认) | 支持(默认) | 支持 |
可重复读 | 支持 | 支持 | 支持(默认) |
可串行化 | 支持 | 支持 | 支持 |
四、读数据的现象
数据库事务隔离级别的不同,在读取数据的时候会出现脏读、不可重复度、幻读等不同的现象,具体的情况如下介绍:
4.1 脏读
脏读就是对脏数据的读取,而脏数据所指的就是未提交的已修改数据。即一个事务正在对一条记录做修改,在这个事务完成并提交之前,这条数据是处于待定状态的(可能提交也可能回滚),这时第二个事务来读取这条没有提交的数据,并据此做进一步的处理,就会产生未提交的数据依赖关系,这种现象被称为脏读。如果一个事务在提交操作结果之前,另一个事务可以看到该结果,就会发生脏读。
第一个事务 | 第二个事务 |
create table student(id int,name varchar(13)); insert into student values(1,'AAA'); commit; set transaction isolation level read uncommitted; select * from student; | |
insert into student values(2,'BBB'); # 不提交 | |
select * from student; |
4.2 不可重复读
不可重复读指的是在同一事务内,不同的时刻读到的同一批数据可能是不一样,可能会受到其他事务的影响。如果一个事务在读取了一条记录后,另一个事务修改了这条记录并且提交了事务,再次读取记录时如果获取到的是修改后的数据,这就发生了不可重复读情况。不可重复读在数据库事务隔离级别为读未提交和读提交的情况下出现,通常指数据更新(UPDATE)操作。
第一个事务 | 第二个事务 |
create table student(id int,name varchar(13)); insert into student values(1,'AAA'); commit; set transaction isolation level read committed; select * from student; | |
update student set name='XXX' where id=1; select * from student; | |
select * from student; | |
commit; | |
select * from student; |
4.3 幻读
一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为幻读。幻读在数据库事务隔离级别为读未提交、读提交和可重复读的情况下会出现,而在DM中可重复读的数据库事务隔离级别升级为了更严格的串行化隔离级别,因此在DM中幻像读只会在数据库隔离级别为读未提交和读提交的情况下出现。
第一个事务 | 第二个事务 |
create table student(id int,name varchar(13)); insert into student values(1,'AAA'); commit; set transaction isolation level read committed; select * from student; | |
insert into student values (2,'BBB'); select * from student; | |
select * from student; | |
commit; | |
select * from student; |
五、隔离级别演示
事务隔离其实就是为了解决上面提到的脏读、不可重复读、幻读这几个问题,下面演示四种隔离级别对这三个问题的解决程度。
隔离级别/解决 | 脏读 | 不可重复读 | 幻读 |
未提交读 | 可能 | 可能 | 可能 |
已提交读 | 不可能 | 可能 | 可能 |
可重复读 | 不可能 | 不可能 | 可能 |
可串行化 | 不可能 | 不可能 | 不可能 |
5.1、读未提交隔离级
读未提交隔离级别是最不严格的隔离级别,在使用这个隔离级别时,有可能发生脏读、不可重复读和幻像读。第一个事务产生的未提交的事务的状态就会直接影响到第二事务,也就是出现了脏读的现象。
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; |
5.2读已提交隔离级
DM 数据库的读已提交隔离可以确保只访问到已提交事务修改的数据,保证数据处于一致性状态,能够满足大多数应用的要求,并最大限度的保证系统并发性能,但可能会出现不可重复读取和幻像读。第一个事务执行更新操作,但是没有进行提交,这时第二个事务再次进行查询,数据并没有改变,等第一个事务执行提交后,第二个事务再次进行查询就能查到改变后的数据,也就是不可重复读的现象。
SET TRANSACTION ISOLATION LEVEL READ COMMITTED; |
5.3、可重复读隔离级
在达梦数据库中可重复读隔离级别可以避免不可重复读和幻读问题,在并发环境下得到一个稳定结果,就可以设置可重复读事务隔离级别。可重复读相对于序列化在性能上能更灵活一些。
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; |
5.4、可串行化隔离级
在要求消除不可重复读取或幻像读的情况下,可以设置事务隔离级为串行化。跟读提交隔离级相比,串行化事务的查询本身不会增加任何代价,但修改数据可能引发“串行化事务被打断”错误。具体来说,当一个串行化事务试图更新或删除数据时,而这些数据在此事务开始后被其他事务修改并提交时,DM 数据库将报“串行化事务被打断”错误。如果系统中存在长时间运行的写事务,并且该长事务所操作的数据还会被其他短事务频繁更新的话,最好避免使用串行化事务。
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; |
六、实验注意事项
设置的事务隔离级别必须在事务开启前,事务开启后,再修改事务隔离级别将会报错:试图在事务运行中,改变其属性。