今天我们分享 mysql数据库事务及隔离级别:
一、事务特性:
首先,事务应该具有 4 个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为 ACID 特性。
原子性(atomicity):undo log(MVCC)
一致性(consistency):最核心和最本质的要求
隔离性(isolation):锁,mvcc(多版本并发控制)
持久性(durability):redo log
二、隔离性(isolation)详解:
1、隔离级别:
一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。(对数据库的并行执行,应该像串行执行一样)
未提交读(READ UNCOMMITED)脏读
已提交读 (READ COMMITED)不可重复读
可重复读(REPEATABLE READ)
可串行化(SERIALIZABLE)
数据库的事务隔离级别有四种,分别是读未提交、读已提交、可重复读、序列化,不同的隔离级别下会产生脏读、幻读、不可重复读等相关问题,因此在选择隔离级别的时候要根据应用场景来决定,使用合适的隔离级别。各种隔离级别和数据库异常情况对应情况如下:
mysql 默认的事务隔离级别为: 可重复读(REPEATABLE READ)
show variables like '%tx_isolation%';
2、SQL 标准定义了四个隔离级别:
- READ-UNCOMMITTED(读取未提交): 事务的修改,即使没有提交,对其他事务也都是可见的。事务能够读取未提交的数据,这种情况称为脏读。
- READ-COMMITTED(读取已提交): 事务读取已提交的数据,大多数数据库的默认隔离级别。当一个事务在执行过程中,数据被另外一个事务修改,造成本次事务前后读取的信息不一 样,这种情况称为不可重复读。
- REPEATABLE-READ(可重复读): 这个级别是MySQL的默认隔离级别,它解决了脏读的问题,同时也保证了同一个事务多次读取同样的记录是一致的,但这个级别还是会出现幻读的 情况。幻读是指当一个事务A读取某一个范围的数据时,另一个事务B在这个范围插入行,A事务再次读取这个范围的数据时,会产生幻读。
- SERIALIZABLE(可串行化): 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重 复读以及幻读。
事务隔离机制的实现基于锁机制和并发调度。其中并发调度使用的是MVVC(多版本并发控制),通过保存修改的旧版本信息来支持并发一致性读和回滚等特性。因为隔离级别越低,事务请求的锁越少,所以大部分数据库系统的隔离级别都是READ-COMMITTED(读取提交内容):,但是你要知道的是InnoDB 存储引擎默认使用 **REPEATABLE-READ(可重读)**并不会有任何性能损失。
三、事务并发问题
脏读:事务 A 读取了事务 B 更新的数据,然后 B 回滚操作,那么 A 读取到的数据是脏数据。
不可重复读:事务 A 多次读取同一数据,事务 B 在事务 A 多次读取的过程中,对数据作了更新并提交,导致事务 A 多次读取同一数据时,结果 不一致。
幻读:系统管理员 A 将数据库中所有学生的成绩从具体分数改为 ABCDE 等级,但是系统管理员 B 就在这个时候插入了一条具体分数的记录,当系统管理员 A 改结束后发现
还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。(事务A按照一定条件进行数据读取,期间事务B插入了相同搜索条件的新数据,事务A再次按照原先条件进行修改数据,发现修改了事物B刚才提交的数据,而且再次读取时,发现了事务B新插入的数据称之为幻读。)
不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件就行,解决幻读需要锁表(当前读和快照读共同参与时才可能发生幻读)。
6)流程总结
show variables like '%tx_isolation%';
show variables like 'tx_isolation';
show variables like 'transaction_isolation';
SELECT @@tx_isolation;
SELECT @@transaction_isolation;
2)如果不是可重复读隔离级别,可以修改隔离级别:
set SESSION TRANSACTION ISOLATION LEVEL repeatable read;
3)A session 中,一个数据库窗口即一个数据库事务中
第一种情况:
start TRANSACTION;
update account set balance = balance -50 where id = 1;
另外一个B session 中查询 (数据并没改变)
select * from account where id = 1
回到第A session 中 提交事务
COMMIT
在B session 中
select * from account where id = 1
数据已经改变。
5)流程总结:
可串行化:
A 开启一个事务
B开启一个事务
B执行DML操作,阻塞
A执行DML操作,操作成功
A提交或者回滚
B进行DML操作,可以成功
总结,依次进行,谁先开启事务,谁先进行DML操作,然后提交后,其他事务才可以进行DML操作!