MySQL入门教程(9)MySQL事务特性与隔离级别

TangLu MySQL 2022-12-06 1791 0

一、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'

评论