mysql中InnoDB的事务理解
1.什么是事务
简单来说,数据库事务即指一组sql语句操作中 ,要么全部执行成功,要么全部执行失败
eg:A向B转1000元,即A减少1000,B增加1000,这两件事要么都成功,要么都失败
2.ACID即事务的四大特性
- 原子性(Atomicity) 指事务的原子性操作,对数据的修改要么全部执行成功 ,要么全部失败。
- 一致性(Consistent) 指执行事务前后的状态要一致。
- 隔离性(Isalotion) 指事务之间相互隔离,不受影响,这个与事务设置的隔离级别有关系
- 持久性(Durable) 指将数据持久化到数据库长久保存。
3.事务隔离级别
- 读未提交(READ UNCOMMITTED)
- 读已提交(READ COMMITTED)
- 可重复读(REPEATABLE READ)
- 串行化(SERIALIZABLE)
4.如果没有事务隔离,会有哪些影响
- 脏读(Dirty read) 当事务A对数据正在修改,还没有提交,这时事务B也访问这个数据 ,并使用这个数据,因A还没有提交,这个时候B事务读到的数据就是“脏数据 ”
- 丢失修改(Lost to modify) 当事务A读取表中的数据金额amount=100,事务B也读取表中的数据金额amount=100,事务A修改amount-10,事务B也执行amount-10,最终正确结果数据库中金额amount应该等于80,但没有事务隔离,事务B的会覆盖事务A,造成金额amount=100
- 不可重复读 (Unrepeatableread) 指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读取数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为不可重复读
- 幻读(Phantom read) 幻读与不可重复读类似。它发生在一个事务T1读取了几行数据 ,接着另一个并发事务(T2)插入了一些数据。在随后的查询中,第一个事务T1就会 发现多了一些原本不存在的记录。
4.1 不可重复读与幻读的区别
不可重复读重点是update修改操作,幻读的重点在于insert插入操作
4.2 事务隔离级别即为了解决脏读、不可重复读、幻读
5.事物隔离级别分析
5.1事物隔离级别查看及修改
查看事务隔离级别
InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ
select @@tx_isolation
show variables like 'tx_isolation'
show variables like 'transaction_isolation';
SELECT @@transaction_isolation
#以上四种均可以查看事务隔离级别,说是mysql版本不同用不同的语句,我5.7.32的mysql都能查
设置事务隔离级别
#设置事务隔离级别 SET 作用域 TRANSACTION ISOLATION LEVEL 隔离级别
#作用域:SESSION:当前会话 GLOBAL:全局
#隔离级别: READ UNCOMMITTED:读未提交 READ COMMITTED:读已提交 REPEATABLE READ:可重复读 SERIALIZABLE:串行化
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
#eg:设置全局隔离级别为读未提交 SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
注意:
- 设置完隔离级别,对当前session无效,即需要你重新打开一个CMD命令界面,或重新连接shell,亦或Navicat关闭数据库再重新连接,否则无效。
- mysql命令行的默认配置中事务都是自动提交的,所以需要进行显示打开事务与提交
START TARNSACTION | BEGIN 显示开启一个事务
COMMIT 提交事务
ROLLBACK 回滚会结束用户的事务,并撤销正在进行的所有未提交的修改
5.2事物隔离级别演示
前期准备:创建一张表,并插入几条数据
CREATE TABLE user (
id INT(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20),
age INT DEFAULT 18
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into USER (name, age) VALUES ('zhangsan', 18), ('lisi', 19), ('wangwu', 20)
5.2.1读未提交导致的脏读
- 将事务隔离级别设置为读未提交,并重新连接,查看隔离级别
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
3. 启动两个事务分别为事务A与事务B
事务A:更新张三的年龄为20,先不提交,此时事务B查询张三的年龄,事务B发现张三的年龄为20,在事务B查完之后,事务A不想改张三的年龄了进行了回滚,但B已经查完了,为时已晚,这就是脏读
5.2.2读已提交导致不可重复读
- 将事务隔离级别设置为读已提交,这样可以避免脏读
set global transaction isolation level read committed;
- 启动两个事务分别为事务A与事务B
事务A更新张三的年龄,改为20,但先不提交。此时事务B查询张三的年龄为18,避免了脏读
事务A提交更新,这时事务B查询张三的年龄为20,造成在事务B在一个事务的不同时间段,查询到的数据不同。即不可重复读
5.2.3可重复读
MySQL 在可重复读级别解决了幻读问题,是通过行锁和间隙锁的组合 Next-Key 锁实现的
说下幻读是一种什么情况:
- 将事务隔离级别设置为可重复读
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ
- 启动两个事务分别为事务A与事务B
事务A更新id为1的数据,id由1改为4,名字由zhangsan改为叫zhaoliu,年龄由18改为25,但先不提交。此时事务B像user表中插入一条id为1,名字为zhangsan,年龄为18的数据并提交。
事务A再次查询数据时,发现数据库中张三的数据仍然存在,但是更改后的数据也存在,这就是幻读
5.2.4串行化
串行化是4种事务隔离级别中隔离效果最好的,解决了脏读、可重复读、幻读的问题,但是效果最差,它将事务的执行变为顺序执行,与其他三个隔离级别相比,它就相当于单线程,后一个事务的执行必须等待前一个事务结束。
6.其他知识点
- mysql中InnoDB引擎才支持事务。
- 隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。
7.特别鸣谢
本篇文章隔离分析摘录于https://zhuanlan.zhihu.com/p/117476959,文章写的特别好,还讲了mysql可重复读怎么解决的幻读问题!