关于MySql的事务隔离级别

谈到事务隔离级别,我们先回顾一下事务的基本要素。

一、事务的基本要素(ACID):
  1、原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体。
    2、一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破坏 。比如A向B转账200,A扣了200,B增加了200。
    3、隔离性(Isolation):同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。
    4、持久性(Durability):事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。

二、Mysql的事务隔离级别,如下表(Mysql默认是repeatable-read级别):

事务隔离级别

脏读

不可重复读

幻读

read-uncommitted(读未提交)

read-committed(不可重复读)

repeatable-read(可重复读)

serializable(串行化)

三、事务并发问题:

    1.脏读:A事务读取了B事务update的数据,随后B事务执行了rollback,那么A事务读取的是脏数据;

    2.不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据执行了update并未执行commit,导致事务A多次读取同一数据时,结果 不一致(不可重复读侧重于update操作,解决方案锁住当前行)。

    3.幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读(幻读侧重于insert、delete操作,解决方案锁住当前表)。

查看MySQL事务隔离级别:SELECT @@tx_isolation;

设置MySQL事务隔离级别(GLOBAL.全局  SESSION.当前会话):

    读未提交:set session transaction isolation level read uncommitted;
    不可重复读:set session transaction isolation level read committed;
    可重复读:set session transaction isolation level repeatable read;
    串行化:set session transaction isolation level serializable;

三、举例说明各个事务隔离级别的情况:

    有student表,详情如下:

    

    1.读未提交(read uncommitted):

          a.1 打开A会话,首先设置当前会话的事务隔离级别为读未提交:set SESSION transaction isolation LEVEL read committed;
          a.2 查看事务隔离级别:SELECT @@tx_isolation;
          a.3 关闭事务自动提交:SET @@autocommit=0;  查看事务自动提交状态:SHOW VARIABLES LIKE '%autocommit%';
          a.4 开启事务:START TRANSACTION; 执行更新:UPDATE student SET age=age-20 WHERE id=5;
          
          b.1 打开B会话,首先设置当前会话的事务隔离级别为读未提交:set SESSION transaction isolation LEVEL read committed;
          b.2 查看事务隔离级别:SELECT @@tx_isolation;
          b.3 关闭事务自动提交:SET @@autocommit=0;  查看事务自动提交状态:SHOW VARIABLES LIKE '%autocommit%';
          b.4 开启事务:START TRANSACTION; 执行查询:SELECT * FROM student;

         查询结果:

         

          这时我们会发现,B事务能够得到A事务update未commit的结果,当A事务进行rollback时,B事务读取到的是脏数据。

    2.不可重复读(read committed):设置当前会话的事务隔离级别为不可重复读,步骤同上;这时我们发现B事务读到id=5的数据age依然是120,解决了脏读的问题;当A事务执行commit,B事务前后查询的结果不一致,即产生了不可重复读的问题

    commit之前结果

    

    commit之后的结果:

    

    3.可重复读(repeatable read):设置当前会话的事务隔离级别为可重复读,步骤如下:

             A会话:
                 set SESSION transaction isolation LEVEL repeatable read;
                 SELECT @@tx_isolation;
                 SET @@autocommit=0;
                 SHOW VARIABLES LIKE '%autocommit%';
                 START TRANSACTION;
                 SELECT * FROM student;
             B会话:
                 set SESSION transaction isolation LEVEL repeatable read;
                 SELECT @@tx_isolation;
                 SET @@autocommit=0;
                 SHOW VARIABLES LIKE '%autocommit%';
                 START TRANSACTION;
                 UPDATE student SET age=age-20 WHERE id=5;
                 SELECT * FROM student;
                 commit;
             接着在A会话执行:SELECT * FROM student;查询结果age=80;在客户端继续执行UPDATE student SET age=age-20 WHERE id=5;这时age=60,数据一致性没有被破坏;可重复读的隔离级别下使用了MVCC机制,select操作不会更新版本号,是快照读(历史版本);insert、update和delete会更新版本号,是当前读(当前版本);

            重新在B会话,插入一条新数据后提交;在A会话查询表student的所有记录,没有 查出 新增数据,所以没有出现幻读(想要查询到B会话insert的数据,A事务要先commit当前事务)。

    4.串行化(serializable):mysql中事务隔离级别为serializable时只要有一个事务未提交,就会锁表,因此不会出现幻读的情况,这种隔离级别并发性极低,开发中很少会用到。

 

另外事务执行会产生相应的锁:

    1.事务隔离级别为读提交时,写数据时锁住相应的行;

    2.事务隔离级别为可重复读时,如果检索条件有索引(包括主键索引)的时候,默认加锁方式是next-key 锁;如果检索条件没有索引,更新数据时会锁住整张表。一个间隙被事务加了锁,其他事务是不能在这个间隙插入记录的,这样可以防止幻读;

    3.事务隔离级别为串行化时,读写数据都会锁住整张表;

    4.隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值