数据库锁及事务分析记录

查看事务隔离级别(全局和会话):select @@global.tx_isolation,@@tx_isolation;
设置事务隔离级别:
set global transaction isolation level read committed; //全局的

set session transaction isolation level read committed; //当前会话

查看锁整体状态: show status like '%lock%';
查看引擎状态(可以查看到最后一次死锁信息):show engine innodb status\G;
查询是否锁表:show open tables where in_use>0;
查询正在使用的事务:select * from information_schema.innodb_trx\G;
查看正在锁的事务(只有单个事务,但没有竞争的时候查看不到事务):select * from information_schema.innodb_locks;
查看正在等待锁的事务:select * from information_schema.innodb_lock_waits;

一、锁详解

1、锁类型

1)按照锁机制分类

  • 排他锁 (X锁)

  • 共享锁 (S锁)
    2)按照锁数据粒度分类

    • 行级锁
    • 表级锁
    • 页级锁

    行级锁:开销大,加锁慢;会出现死锁;锁粒度最小,发生锁冲突的概率最低,并发度也最高。
    表级锁:开销小,加锁快;不会出现死锁;锁粒度大,发生锁冲突的概率最高,并发度低。
    页级锁:MySQL特有,开销和加锁时间在表锁和行锁之间;会出现死锁;锁粒度界表锁和行锁之间,并发度一般。

3)数据库事务机制

事务,保证一组操作要么全部执行,要么全部不执行,保证数据库一致性。简称ACID。
A 事务原子性(Atomicity)
事务中一组操作要么全部执行,要么全部不执行
C 事务一致性
事务的允许不改变数据的一致性
I 事务隔离性
两个事物执行时隔离的,不会交错执行
D 事务持久性
事务执行成功后,该事务对数据库所做的更改持久的保存在数据库中。

4)事务引发的并发调度问题

  • 脏读
    A事务读取B事务未提交的数据

  • 不可重复读
    事务中两次读取数据不一样(包括新增、更新、删除)

  • 幻读
    在同一事务里,多次查询的结果和事务开始第一次查询的状态一致。但是,如果另外一个事务同时提交了新数据,虽然本事务再次按照相同的条件查询得到相同的结果集,但是本事务指定更新时,就会发现这些新数据,这些数据就像“鬼影”一样出现。

5)事务隔离级别

  • Read uncommitted 读未提交
    所有事务都可以看到其他未提交事务的执行结果。存在脏读问题。

    image.png
  • Read committed 读提交
    一个事务只能看见已经提交事务的内容。解决了脏读,存在不可重复读问题。

    image.png

  • Repeatable read 可重复读
    同一个事务多次读取时,获取到的内容一致,可重复读针对的是数据库中同一条记录而言的。解决了不可重复读问题,存在幻读。

    image.png

    image.png

  • 可串行化
    强制事务排序,试之不能相互冲突,解决了幻读问题

  • MySQL中四中隔离级别,分别可能产生的问题:
    隔离级别    脏读  不可重复读   幻读
    读未提交    √   √   √
    读已提交    ×   √   √
    可重复读    ×   ×   √
    可串行化    ×   ×   ×
    

6)聚簇索引和非聚簇索引

聚簇索引:索引的叶子节点即为行数据
1)默认主键索引就是聚簇索引
2)若没有主键索引则用一个唯一且不为空的索引列成为聚族索引
3)若唯一且不为空的索引也不存在,Innodb会隐式定义一个主键作为聚簇索引。

非聚簇索引:索引的叶子节点是主键值
其他索引如普通索引、前缀索引等为非聚族索引。

聚簇索引和非聚簇索引数据结构如下:
CREATE TABLE person (
id INT(11) NOT NULL,
name VARCHAR(32) NULL DEFAULT NULL,
date TIMESTAMP NOT NULL,
PRIMARY KEY (id),
INDEX index_name (name)
);

聚族索引查找过程:直接根据聚族索引找到叶子节点上的数据
非聚族查找过程:根据非聚族索引先找到主键值(注意这里找到的是主键值,不是主键的地址),再根据主键值查找聚族索引找到数据

因为非聚族索引要扫描两次索引,所以效率会更低,这种查找也叫回表查询。

索引覆盖:只需要在一棵索引树上就能获取所有列数据,无需回表,称为索引覆盖。

索引覆盖方法:针对被查询的字段,建立索引或者联合索引。提高查询效率。

哪些场景可以利用索引覆盖来优化sql:
1)指定查询某个或者某几个列
只查询所需要的列(列上已建索引),不要使用select 来查询出所有的列数据。
2)全表count查询
使用select count(col name),不要使用select count(
)来统计全表。

二、索引加锁分析

1、MVCC 多版本并发控制协议(与之相对的是基于锁的并发控制Lock-Based Concurrency Control)

在MVCC并发控制中,读操作分成:快照读(Snapshot read)与当前读(Current read)。快照读,读取的是记录的可见版本(有可能是历史版本),不用加锁。当前读,读取的是记录的最新版本,并且当前读返回的记录,都会加锁,保证其他事物不会并发地修改这条记录。

InnoDb行锁是通过给索引上的索引项加锁来实现的。这也意味着只有通过索引条件检索的数据,Innodb才使用行级锁,否则,InnoDb将使用表锁。

以MySQL InnoDb为例,哪些操作是快照读?哪些是当前读?
1)快照读:简单的select操作,属于快照读,不加锁。(除一些特殊场景)
Select * from table where ?;
2)当前读:特殊的读操作,插入、更新、删除操作,属于当前读,需要加锁
Select * from table lock in share mode; (S锁)
Select * from table for udpate; (X锁)
Insert into table xxx; (X锁)
Update table set xxx where ?; (X锁)
Delete from table where ?; (X锁)

如下图,数据更新操作执行流程:

2、SQL加锁分析

SQL1:select * from t1 where id = 10;
SQL2:delete from t1 where id = 10;

上述sql加什么锁?需要根据具体场景来分析。

前提条件:
1)id列是不是主键
2)当前系统隔离级别
3)id如果不是主键,那么id是否有索引
4)id列上有二级索引,那么是唯一索引吗
5)两个SQL的执行计划是什么?索引扫描?全表扫描?

针对各种场景,具体分析:
1)在RC、RR隔离级别下,SQL1均不加锁,采用的是快照读
2)id主键 + RC

结论:id是主键时,只需要在id=10这条记录上加X锁

3)id唯一索引+RC

id是唯一索引,name是主键列。
结论:SQL需要加两个X锁,一个对应ID unique索引上的id=10的记录,另一把锁对应于聚簇索引上的name='d'的记录。

4)id为非唯一索引+RC

结论:id列上有非唯一索引,name对应的所有满足SQL查询条件的记录,都会加锁。同时这些记录的主键索引上的记录,也会被加锁。

5)id无索引+RC

结论:如果id列上没有索引,SQL会走聚簇索引的全扫描进行过滤,由于过滤是由MySQL Server层面进行的。因为每条记录,无论是否满足条件,都会被加上X锁。但是为了效率考量,MySQL做了优化,对于不满足条件的记录,会在判断后放锁,最终持有的,是满足条件的记录上的锁,但是不满足条件的记录加锁/放锁动作不会省略。同时优化也违背了2PL的约束。

6)id主键+RR
加锁与id主键+RC是一致的

7)id唯一索引+RR
加锁与id唯一索引+RC是一致的

8)id非唯一索引+RR
Repeatable Read隔离级别下,id列上有一个非唯一索引,对应SQL:delete from t1 where id = 10; 首先,通过id索引定位到第一条满足查询条件的记录,加记录上的X锁,加GAP上的GAP锁,然后加主键聚簇索引上的记录X锁,然后返回;然后读取下一条,重复进行。直至进行到第一条不满足条件的记录[11,f],此时,不需要加记录X锁,但是仍旧需要加GAP锁,最后返回结束。????
存疑

9)id为索引+RR

//www.greatytc.com/p/13f5777966dd

10)serializable
delete语句在serializable下和RR隔离级别是一致的。而select语句也会加读锁。

关于死锁:死锁的发生与否,并不在于事务中有多少条SQL语句,死锁的关键在于:两个(或以上)的Session加锁的顺序不一致。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,123评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,031评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,723评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,357评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,412评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,760评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,904评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,672评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,118评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,456评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,599评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,264评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,857评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,731评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,956评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,286评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,465评论 2 348