MySQL事务隔离级别-案例驱动
SQL92将事务隔离级别分为了4种,读未提交,读已提交,可重复读,可串行化。不同的隔离级别,对于数据的可见性不同,就会导致不同的正确性。事务的核心在于控制多个客户端在读写共享数据时候的并发问题。这篇文章通过实例研究隔离级别,我们将从读未提交开始,一步一步分析。
step1 创建表和基础数据
CREATE TABLE `traning`.`account` ( `id` INT NOT NULL AUTO_INCREMENT COMMENT '主键id', `uid` INT NOT NULL COMMENT '用户uid', `amount` INT NOT NULL COMMENT '金额', PRIMARY KEY (`id`)); INSERT INTO `traning`.`account` (`uid`, `amount`) VALUES ('1', '1000'); INSERT INTO `traning`.`account` (`uid`, `amount`) VALUES ('2', '2000');
step2 修改隔离级别
场景1 读未提交导致脏读
Client1:SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
Client2:SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
关闭会话重新进入MySQL客户端。
Client2:show variables like 'transaction_isolation';
Client1: start TRANSACTION;
Client2: start TRANSACTION;
Client2: select amount from account where uid=1; (1000)
update account set amount=amount-500 where uid=1;
Client1: select amount from account where uid=1; (读到别人没提交事务:500)
-- update account set amount=(amount+100) where uid=1;(数据被锁,不能更新)
Client2: rollback;(Client1再次读到的是1000,但是没有读)
-- Client1: select amount from account where uid=1; (500)
Client1: update account set amount=(500+100) where uid=1; (读到旧数据去进行更新操作,导致账户丢失500)
场景2 读已提交解决脏读问题
Client1:SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
Client2:SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
关闭会话重启。
Client1:start TRANSACTION;
Client2:start TRANSACTION;
Client2: select amount from account where uid=1; (1000)
update account set amount=amount-500 where uid=1; (500)
Client1:select amount from account where uid=1 (读取不到别人没提交的事务:1000);
update account set amount=1000-500 where uid=1;(数据被锁不能更新)
Client2: rollback;
Client1: update account set amount=(1000+100) where uid=1;
Client1: commit;
场景3 读已提交导致不可重复读问题
Client1:SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
Client2:SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
关闭会话重启。
Client1:start TRANSACTION;
Client2:start TRANSACTION;
Client1:select amount from account where uid=1; (1000);
Client2:update account set amount=amount-100 where uid=1;
Client2: commit;
Client1: select amount from account where uid=1(amount=900,发现自己钱少了100);
场景4 可重复读解决不可重复读问题
Client1:SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
Client2:SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
Client1:start TRANSACTION;
Client2:start TRANSACTION;
Client2: select amount from account where uid=1;(1000)
Client1:select amount from account where uid=1; (1000);
Client2:commit;
Client1:select amount from account where uid=1;(amount=1000);
场景5 可重复读导致幻读问题
Client1:SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
Client2:SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
Client1:start TRANSACTION;
Client2:start TRANSACTION;
Client2: select amount from account ; (2行数据)
Client1:select amount from account ; (2行数据);
Client2:INSERT INTO
traning.
account(
uid,
amount) VALUES ('3', '3000');
Client2:commit;
Client1:select amount from account ;(3条数据);
Clinet1 :update account set amount=1 where id=3(Client读不到但是可以更新);
Clinet1 :select amount from account ;(4条数据-phantom read here!!!!影响了client1的判断和数据);
Clinet1 :commit;
场景6 可序列化解决幻读问题
Client1:SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;
Client2:SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;
Client1:start TRANSACTION;
Client2:start TRANSACTION;
Client2: select amount from account ; (2行数据)
Client1:select amount from account ; (2行数据);
Client2:INSERT INTO
traning.
account(
uid,
amount) VALUES ('3', '3000'); (插入不进去,数据被锁)
Lock wait timeout exceeded; try restarting transaction
以下是整理的图:
当然还有第一类丢失更新(脏写)和第二类丢失更新,第一类丢失更新永远不会发生,第二类丢失更新会在RU和RC情况下发生。
这是完整的图
包含了更多的隔离级别和可能发生数据异常情况:
- 事件驱动(案例)
- EntityFramework之领域驱动设计实践【后续篇】:基于EF 4.3.1 Code First的领域驱动设计实践案例
- 领域驱动设计案例:Tiny Library:领域模型
- 步步高告诉你如何获客增长:4种数字化驱动案例
- SQL优化经典案例----让in/exists子查询作为驱动表
- 王家林亲授的上海7月6-7日云计算分布式大数据Hadoop深入浅出案例驱动实战报名信息
- 【SpringMVC整合MyBatis】案例驱动-包装类型pojo参数绑定
- DDD专题案例三《领域驱动设计架构基于SpringCloud搭建微服务》
- Struts2框架之application、Request、Response、paramaters、Session实现及理解(案例驱动)
- Redhat升级至2.6.0!Vmware成功案例——说明如何配置VMware中的SCSI驱动
- 嵌入式Linux驱动开发案例流程--LED驱动
- 【学习】一本案例驱动的jQuery Mobile入门书
- Oracle创建用户、表空间和创建表【案例驱动】
- 干货 : 10个案例告诉你,数据如何驱动产品设计。
- 【SpringMVC整合MyBatis】案例驱动-集合类型参数绑定
- 墙裂推荐一本案例驱动的PhoneGap入门书,早看早收货
- MySql事务隔离级别锁机制实际案例深入分析
- OOA&D实践之路——真实案例解析OO理论与实践(六、迭代式开发与用例驱动)
- 【STM32小案例 06 】STM32使用按键驱动L298N电机模块控制电机正反转
- 【学习】一本案例驱动的jQuery Mobile入门书