MySQL入门教程(9)MySQL事务特性与隔离级别
一、MySQL事务介绍
1、MySQL的事务特性
MySQL事务有4大特性,分别是原子性(atomicity)、一致性(consistency)、隔离性(isolation)、持久性(durability),简称ACID。在这4个特性中,原子性是基础,隔离性是手段,一致性是约束条件,而持久性是最终目的
· 原子性(atomicity):原子是不可再切分的,所以事务的原子性是指事务开始后的所有操作要么全部执行,要么全部不执行,不应该有部分执行的情况存在。常见的场景就是银行转账,如果A要给B转账1000元,那么A账户减少1000与B账户增加1000这两个操作需要放在一个事务中完成。如果事务在执行过程中出错(包含会话断开、服务宕机)会由undo log(记录数据修改前的状态)回滚到事务开始前的状态
· 一致性(consistency):事务执行前后需要从一个状态变到另一个状态,但是这个状态需要符合业务的约束。比如A向B转账1000,不应存在A扣除1000后而B没有增加的情况;又比如A账户有1000,但是不能给B账户转账2000。由redo log(记录数据修改后的状态)来保持一致性。可以说原子性、隔离性、持久性都是为了保障一致性而存在的,一致性也是最终目的
· 隔离性(isolation):一个事务的执行不能被其他事务干扰,也就是说同一个时间内只允许一个事务对同一个数据进行处理
· 持久性(durability):事务完成后数据应该落盘,能够用久保存,并且不能再rollback回滚
2、MySQL事务控制语句
· 显式开启事务(如果显式开启了事务,一定要注意及时关闭,避免长事务问题)
# 使用begin语句开启事务,然后commit语句提交事务 begin; 加入事务中的语句; commit; # 使用start transaction开启事务,相比begin可以增加修饰符,默认为read write以及snapshot start transaction [read write]/[read write] with consistent snapshot;
· 事务的自动提交功能
当数据库设置autocommit=1时(默认为1),每一个DML都是一个事务,即便没有加begin语句开启事务,数据库也会自动开启事务并进行commit
· 隐式开启事务
对于DDL语句来说,它们都是单独的事务。如果DML中加有DDL会触发隐式提交,事务不支持嵌套,所以在一个事务中再开启事务也会导致前一个事务被提交
#rollback回滚事务 rollback #回滚所有未提交的事务 rollback to s1 #回滚到S1这个保存点(savepoint)
二、MySQL隔离级别
1、脏读、不可重复度与幻读
· 脏读:在事务1中查询到的数据是事务2已经修改过但未提交的,一旦事务2发生回滚,那事务1获取到的数据就是无效的
· 不可重复度:在一个事务中对数据进行多次查询,得到的结果因为数据被其它事务所修改而不一致
· 幻读:在一个事务中对数据进行多次查询,但是后续的查询读取到了之前没有的记录,也就是发生了新增数据(如果是删除了数据属于不可重复读的范围)。比如事务1对年龄<30的数据进行修改,事务2在事务1提交之前又新增了一个<30的数据,这个时候事务1提交之后会看到依然有一个<30的数据存在,带来修改失败的幻觉
2、MySQL的4种事务隔离级别
· 读未提交(read uncommitted):最低的隔离级别,在一个事务中可以读取到另一个事务已修改但尚未提交的结果。该隔离级别容易造成脏读、不可重复读、幻读,所以不建议使用。为了避免脏读、不可重复读、幻读导致主从数据不一致,当前隔离级别下binlog格式不能为statement
· 读已提交(read commited):只有事务提交后其更新结果才可以被其他事务查询。Oracle、SQL Server等大多数数据库系统的默认隔离级别(但MySQL并不是)。该隔离级别解决了RU级别的脏读问题,但存在不可重复读和幻读情况(同样的查询语句,在每一次进行查询的时候都会重新获取read view,所以产生不可重复读或者幻读)。为了避免脏读、不可重复读、幻读导致主从数据不一致,当前隔离级别下binlog格式不能为statement。该隔离级别下由于不存在GAP锁,所以性能会更好,也是最推荐使用的,如果在数据一致性高的场景,可以通过代码层进行会话级别的隔离级别设置
· 可重复读(repeatable read):Innodb引擎的默认隔离级别。在同一个事务中,如果对某行数据进行多次查询,其查询结果通过MVCC快照读的方式保证永远是相同的(快照读的样本是在SELECT那刻自动创建),即便事务2已经修改了数据并提交,但是在事务1中依然不会有变化。该隔离级别解决了脏读、不可重复读以及大部分幻读的发生。该隔离级别可以通过GAP锁解决幻读问题,但是对并发性能有一定影响,所以通常不太推荐使用该隔离级别,而是保持使用RC,至于幻读问题就需要忽略或者用其他手段解决
· 串行化(serializable):事务串行化处理,不会出现脏读、幻读、不可重复读的问题,隔离级别最高,但会导致大量的锁超时和锁竞争问题,因此性能最差,也不建议使用
PS:四个隔离级别逐个解决脏读、不可重复读、幻读的问题,但是随着隔离级别的上升,事务请求的锁和锁的时间就会越长。
隔离级别 | 脏读 | 不可重复读 | 幻读 |
Read Uncommitted | 是 | 是 | 是 |
Read Committed | 否 | 是 | 是 |
Repeatable Read | 否 | 否 | 是 |
Serializable | 否 | 否 | 否 |
3、MySQL事务隔离级别的设置
#查看事务隔离级别
show global variables like 'tx_isolation';
#在线设置事务隔离级别
set global tx_isolation='READ-COMMITTED'
#永久生效
vi /etc/my.cnf
tx_isolation=READ-COMMITTED'
评论