MySQL事务(transaction)的四大特性ACID、隔离性问题及隔离级别

1.事务的四大特性(ACID)

原子性(atomicity):一个事务是不可分割的工作单位,事务中的操作要么一起发生,要么一起不发生

一致性(consistency):事务前后的数据必须保持一致

隔离性(isolation):多个事务之间数据要相互隔离

持久性(durability):事务一旦被提交,改变是永久性的

2.隔离性问题

2.1隔离性分析

  • 隔离性问题本质上就是多线程的并发安全问题
  • 如果两个线程并发修改,必然会产生多线程安全问题,必须隔离
  • 如果两个线程并发查询,必然没有问题,不需要隔离
  • 如果一个线程修改,一个线程查询,在不同的应用场景下可能有问题,也可能没问题

2.2隔离性可能造成的问题

脏读(dirty reads):一个事务读取到另一个事务未提交的数据

实现脏读过程:

1.打开两个窗口,因为SESSION表示的是当前窗口有效,所以窗口1和窗口2都要先执行下面语句,将隔离级别设置为最低

set session transaction isolation level read uncommitted;

2. 执行窗口1中圈住的语句

3.执行完窗口1中的语句后回到窗口2中开启事务并执行查询,此时窗口2中的数据查询a用户已经被扣款100,b用户账户已经被增加100(因为窗口1还未完成提交,但是允许查询,故出现了脏读)

 

4.执行窗口1的回滚操作

5.回到窗口2中继续查询数据,此时展示的值就是窗口一回滚后的值

2.不可重复度(non-repeatable reads) :一个事务多次读取同一条数据,多次查询结果不同

测试方法类似于脏读(此处不再赘述)

窗口1:

start transaction;

select * from user where name='a';

窗口2:

start transaction;

update user set money=money-100 where name='a';

commit;

窗口1:

/#两次查询结果不同

select * from user where name='a';

commit;

3.虚读/幻读(phantom reads ):出现概率很低,一个事务多次查询整表数据,查询到的结果不同

测试方法类似于脏读(此处不再赘述)

窗口1:

start transaction;

select sum(money) from user;

窗口2:

start transaction;

insert into user values(3,'c',5000);

commit;

窗口1:
#两次查询结果不同

select sum(money) from user; 

commit;

3.隔离级别

数据库针对不同场景需求设计了不同的隔离级别

  • read uncommitted:不做任何隔离,可能造成脏读、不可重复读、虚读(幻读)问题
  • read committed:可以防止脏读,但是不能防止不可重复读、虚读(幻读)问题
  • repeatable read:可以防止脏读、不可重复读,但是不能防止虚读(幻读)问题
  • serializable:可以防止所有隔离性问题,但是数据库被设计为串行化的数据库,性能很低

安全性:serializable>repeatable read>read committed>read uncommitted

效率:read uncommitted>read committed>repeatable read>serializable

MySQL默认隔离级别:repeatable read

Oracle默认隔离级别:read committed

操作隔离级别

查询数据库的隔离级别

select @@tx_isolation;

修改隔离级别

set [session/global] transaction isolation level xxx;

不写默认为session,表示只修改当前客户端的隔离级别,不影响其他客户端

如果设置为global,表示修改数据库默认的隔离级别,但是当前窗口无效

例如:set session transaction isolation level serializable;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章