关注我

    我的微信
在线咨询 x
在线咨询
有什么可以帮到你
点击咨询

MySQL 事务管理(ACID)

简介MySQL事务具有4个特征,分别是原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability),简称事务的ACID特性。

一、事务管理(ACID)


谈到事务一般都是以下四点


原子性Atomicity

原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。(比如:银行转帐过程中,必须同时从一个帐户减去转帐金额,并加到另一个帐户中,只改变一个帐户是不合理的。)

一致性Consistency

事务前后数据的完整性必须保持一致。(比如:银行转帐过程中,要么转帐金额从一个帐户转入另一个帐户,要么两个帐户都不变,没有其他的情况。)

隔离性Isolation

事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。(比如说,银行转帐过程中,在转帐事务没有提交之前,另一个转帐事务只能处于等待状态。)

持久性Durability

持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。(比如:银行转帐过程中,转帐后帐户的状态要能被保存下来。)


举个简单的例子理解以上四点


1、原子性


针对同一个事务


原子性.png


这个过程包含两个步骤

A: 800 - 200 = 600

B:    200 + 200 = 400

原子性表示,这两个步骤一起成功,或者一起失败,不能只发生其中一个动作


2、一致性(Consistency)


针对一个事务操作前与操作后的状态一致


一致性.png



操作前  A:800,B:200

操作后  A:600,B:400


一致性表示事务完成后,符合逻辑运算


3、持久性(Durability)


表示事务结束后的数据不随着外界原因导致数据丢失


操作前  A:800,B:200

操作后  A:600,B:400

如果在操作前(事务还没有提交)服务器宕机或者断电,那么重启数据库以后,数据状态应该为

A:800,B:200

如果在操作后(事务已经提交)服务器宕机或者断电,那么重启数据库以后,数据状态应该为

A:600,B:400


4、隔离性(Isolation)


针对多个用户同时操作,主要是排除其他事务对本次事务的影响


隔离性.png


两个事务同时进行,其中一个事务读取到另外一个事务还没有提交的数据,B


隔离性.png


二、不可重复读


在一个事务内读取表中的某一行数据,多次读取结果不同。(这个不一定是错误,只是某些场合不对)


页面统计查询值


不可重复读.png



点击生成报表的时候,B有人转账进来300(事务已经提交)


不可重复读.png



三、虚读(幻读)


是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。

(一般是行影响,多了一行)


虚读(幻读).png



四、四种隔离级别设置


设置 描述
Serializable 可避免脏读、不可重复读、虚读情况的发生。(串行化)
Repeatable Read 可避免脏读、不可重复读情况的发生。(可重复读)
Read Committed 可避免脏读情况发生(读已提交)
Read Uncommitted 最低级别,以上情况均无法保证



五、MySQL模拟事务隔离性测试


SELECT @@session.tx_isolation;   
SELECT @@tx_isolation;  
  
SET SESSION TRANSACTION ISOLATION LEVEL read uncommitted;  
SET SESSION TRANSACTION ISOLATION LEVEL read committed;  
SET SESSION TRANSACTION ISOLATION LEVEL repeatable read;  
SET SESSION TRANSACTION ISOLATION LEVEL serializable;  

start transaction;

--建表
drop table amount;
CREATE TABLE `amount` (
`id`  varchar(10) NULL,
`money`  numeric NULL
)
;
--插入数据
insert into amount(id,money) values('A', 800);
insert into amount(id,money) values('B', 200);
insert into amount(id,money) values('C', 1000);
--测试可重复读,插入数据
insert into amount(id,money) values('D', 1000);

--设置事务
SET SESSION TRANSACTION ISOLATION LEVEL read uncommitted;  
SELECT @@tx_isolation;  
--开启事务
start transaction;


-- 脏读演示 -- 
-- 脏读演示 -- 
-- 脏读演示 -- 
--脏读演示,读到其他事务未提交的数据
--案列1,事务一:A向B转200,事务二:查看B金额变化,事务一回滚事务
update amount set money = money - 200 where id = 'A';
update amount set money = money + 200 where id = 'B';

--不可重复读演示,读到了其他事务提交的数据
--案列2,事务一:B向A转200,事务二:B向C转200转100
SET SESSION TRANSACTION ISOLATION LEVEL read committed;  

--开启事务
start transaction;
--两个事务都查一下数据(转账之前需要,查一下金额是否够满足转账)
select * from amount;
--事务一:B向A转200
update amount set money = money - 200 where id = 'B';
update amount set money = money + 200 where id = 'A';

commit;
--事务二:B向C转200转100
update amount set money = money - 100 where id = 'B';
update amount set money = money + 100 where id = 'C';
commit;
--从事务二的角度来看,读到了事务一提交事务的数据,导致金额出现负数


-- 幻读演示 --
-- 幻读演示 --
-- 幻读演示 --
--案列3,事务一:B向A转200,事务二:B向C转200转100
SET SESSION TRANSACTION ISOLATION LEVEL repeatable read;  

--开启事务
start transaction;
--两个事务都查一下数据(转账之前需要,查一下金额是否够满足转账)
select * from amount;
--事务一:B向A转200
update amount set money = money - 200 where id = 'B';
update amount set money = money + 200 where id = 'A';

commit;
--事务二:B向C转200转100
update amount set money = money - 100 where id = 'B';
update amount set money = money + 100 where id = 'C';
commit;
--从事务二的角度来看,读到了事务一提交事务的数据,导致金额出现负数