mysql事务隔离级别

参考资料(视频)
参考资料(文章)
 
 
疑问点
比如一个人A有100元
然后开启一个事务,转账给B用户80元,(A已经转出,B还没收到,事务还没有提交),
同时再开启另一个事务,转账给C用户60元,(可以转出吗?前一个事务能成功吗?如果前一个事务没有提交,后面这个事务能成功吗?)
回答:
第一个事务转账给B还没有结束的时候,第二个事务转账给C不能进行数据操作,因为第一个事务有行锁,把数据锁起来了。
 

一,数据库中事物的作用
  • 什么是事务?
事务是一改改变,是一些操作的集合,是一个控制的执行单元。事务包含(原子性/一致性/隔离性/持久性)四个特征,我们需要通过技术的手段保证这四个事务的特征。
    • 原子性
      • 事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。
    • 一致性
      • 事务开始前和结束后,数据的完整性约束没有被破坏 。比如A向B转账,不可能A扣了钱,B却没收到。
    • 隔离性
      • 同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。
    • 持久性
      • 事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。
 
二,并发的情况下,事务会引发的一些问题
  • 脏读
    • 事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
  • 不可重复读
    • 事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。
  • 幻读
    • 系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
  • 小结
    • 不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
 
三,Mysql四种事务隔离级别
事务的四种隔离级别只是一个标准,但是各个数据库厂商并完全都是按照这个标准来做的。
 
四,事务隔离级别例子
  • 查询mysql默认的事务隔离级别
select @@tx_isolation;
  • 演示Demo
CREATE TABLE account (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
user_name VARCHAR(32) NOT NULL DEFAULT '' COMMENT '用户姓名',
balance DECIMAL(10,2) UNSIGNED NOT NULL DEFAULT 0 COMMENT '余额'
)ENGINE = INNODB DEFAULT CHARSET utf8;
 
INSERT INTO account(user_name, balance) VALUES
('aaa', 100.00),
('bbb', 100.00),
('ccc', 100.00);
  • 读未提交 - read-uncommitted
    • 1、打开客服端A,设置当前事务模式为read-uncommitted,查询表account的初始值
      • 2、打开客服端B,更新account表的数据
      • 3、这时,客服端B的数据还没有提交,但是客服端A已经可以查询到B更新的数据
    • 4、一旦客户端B的事务因为某种原因回滚,所有的操作都将会被撤销,那客户端A查询到的数据其实就是脏数据
      • 5、在客户端A执行数据修改操作,可以确认到上一次读取的数据属于“脏读”(要解决这个问题可以采用“读已提交”的隔离级别)
 
    • 不可重复读(读已提交) - read-committed
      • 1、打开客服端A,设置当前事务模式为read-committed,查询表account的初始值
      • 2、打开客服端B,更新account表的数据
      • 3、这时,客服端B的数据还没有提交,客户端A不能查询到B已经更新的数据,解决了“脏读”的问题
      • 4、客户端B提交了事务
      • 5、客服端A再执行查询,查询结果与上一次查询不一致,产生了不可重复读的问题
 
    • 可重复读 - repeatable-read
      • 1、打开一个客户端A,并设置当前事务模式为repeatable read,查询表account的所有记录
      • 2、打开客服端B,更新account表的数据,commit提交事务
      • 3、这时,客服端B的数据已经提交,客户端A不能查询到B已经更新的数据,解决了“不可重复读”的问题
      • 4、在客户端A,执行update account set balance = balance - 20 where id = 1;  aaa的balance没有变成100-20=80,值变成了50-20=30,数据的一致性是没有被破坏。
        • 可重复读的隔离级别下使用了MVCC机制,select操作不会更新版本号,是快照读(历史版本);insert、update和delete会更新版本号,是当前读(当前版本)
      • 5、打开客户端B,插入一条数据后提交,
      • 6、在客户端A查询表account的所有记录,没有查出新增数据,所以没有出现幻读
 
    • 串行化 - serializable
      • 1、 打开一个客户端A,并设置当前事务模式为serializable,查询表account的初始值:
      • 2、在客户端B,修改一条记录,表被锁住了无法修改成功。
        • mysql中事务隔离级别为serializable时会锁表,因此不会出现幻读的情况,这种隔离级别并发性极低,开发中很少会用到
 
如何实现数据库的四种隔离级别(InnoDB)
  1. 锁机制
  2. MVCC机制
 
InnoDB锁机制
  • 表锁&行锁
InnoDB存储引擎支持行锁和表锁(另类的行锁),InnoDB的表锁是通过行锁把所有行都锁住实现的,他本身是不支持表锁的
表锁与行锁的区别:
    1. 锁定粒度:表锁 > 行锁
    2. 加锁效率:表锁 > 行锁
    3. 冲突概率:表锁 > 行锁
    4. 并发性能:表锁 < 行锁
 
  • InnoDB行锁到底锁了什么?
    1. InnoDB的行锁是通过给索引上的索引项加锁来实现的。
    2. 只有通过索引条件进行数据检索,InnoDB才使用行级锁,否则,InnoDB 将使用表锁(锁住索引的所有记录)
    3. 主键索引是条件时加1把锁,二级索引是条件时加2把锁,条件不加索引时,锁住整个表。
 
  • InnoDB锁类型
这八种锁中,后面三种锁只能算是行锁的算法
1, 共享锁(S)行锁:Shared Locks l
共享锁又称为读锁,简称S锁,顾名思义,共享锁就是多个事务对于同一数据可以共享一把锁, 都能访问到数据,但是只能读不能修改;
select * from users WHERE id=1 LOCK IN SHARE MODE;    //加锁方式
commit/rollback    //释锁
 
//例子:
//在客户端A打开共享锁
BEGIN;
SELECT * FROM account WHERE id=1 LOCK IN SHARE MODE;
 
//在客户端修改这行记录,行被锁住了无法修改成功
UPDATE account SET balance = balance - 20 WHERE id = 1;
2, 排它锁(X)行锁:Exclusive Locks l
排他锁又称为写锁,简称X锁,排他锁不能与其他锁并存,如一个事务获取了一个数据行的排他 锁,其他事务就不能再获取该行的锁(共享锁、排他锁),只有该获取了排他锁的事务是可以对 数据行进行读取和修改,(其他事务要读取数据可来自于快照)
//delete / update / insert 默认加上X锁
SELECT * FROM table_name WHERE … FOR UPDATE;    //加锁方式
commit/rollback    //释锁
3, 意向共享锁(IS)表锁:Intention Shared Locks l
表示事务准备给数据行加入共享锁,即一个数据行加共享锁前必须先取得该表的IS锁, 意向共享锁之间是可以相互兼容的
4, 意向排它锁(IX)表锁:Intention Exclusive Locks l
表示事务准备给数据行加入排他锁,即一个数据行加排他锁前必须先取得该表的IX锁, 意向排它锁之间是可以相互兼容的
关于意向锁
      1. 意向锁(IS、IX)是InnoDB数据操作之前自动加的,不需要用户干预
      2. 当事务想去进行锁表时,可以先判断意向锁是否存在,存在时则可快速返回该表不能 启用表锁
      3. 意向锁是表锁,一张表只有一个,就像是一个true,false标记。
5, 自增锁:AUTO-INC Locks
针对自增列自增长的一个特殊的表级别锁
show variables like ‘innodb_autoinc_lock_mode’;
默认取值1,代表连续,事务未提交ID永久丢失,表中的自增id就会不连续,建议不要改默认值。
行锁的算法
6, 记录锁 Record Locks l
7, 间隙锁 Gap Locks l
8, 临键锁 Next-key Locks
 
 
posted @ 2020-07-27 19:31  Duomen  阅读(207)  评论(0编辑  收藏  举报