mysql锁机制与结构目录
一、锁的基础与行锁的特点
1. 概念
1. 在开发多用户、数据库驱动的应用时,相当大的一个难点就是解决并发性的问题,目前比较常用的解决方案就是锁机制。
2. 锁机制也是数据库系统区别于文件系统的一个关键特性。
3. InnoDB 存储引擎和 MyISAM 存储引擎使用的是完全不同的策略,我们必须分开来讲。
2. 锁特性
一旦事务锁住一页或者一行或者一张表的数据,被锁住就不能被操作了(写操作)
3. 锁类型
3.1 表级锁
表级锁:锁住一张表的数据
存储引擎:myisam
开销小,加锁的难度小,速度快,不会出现死锁的请情况,但是会发生锁冲突,并发最高
3.2 页级锁
页级锁:锁住某一页数据,大约16kb
存储引擎:BDB(支持事务,已经不用了)
开销中等,枷锁难度中等,速度中等,锁冲突中等
3.3 行级锁
行级锁:锁住某一行的数据
存储引擎:innodb
开销大,枷锁速度慢(检索量大),难度高,锁冲突最低,并发最低
3.3.1 行级锁类型
排它锁
排它锁
select * from user where id =1 fro update
特性:
对于普通的select查询不会有限制
排它锁不能与其他锁(排它锁,共享锁)一起使用(否则锁等待),不能读,不能写
因为mysql的事务会默认给你 update、insert、alter、delete,这样一些写的操作默认加上一把排它锁
使我们的业务强制进入串行化
应用场景:
支付
订单状态
秒杀(超卖)
共享锁
共享锁
select * from user where id =1 lock in share mode
特性:
能读不能写
可以和共享锁一起使用,不能与排它锁一起使用(否则锁等待)
使用场景:
mvcc
4. 总结
-
一旦事务锁住一页或者一行或者一张表的数据,被锁住就不能被操作了(写操作)
-
开启事务以后,写操作(alter、delete、insert、update)的sql语句,只要没提交就把不会生效。
-
当前查询:一般指的是加锁的select查询
-
快照查询:一般指的是没加锁的普通查询
-
普通查询不会受到加锁的影响,依然能够获取加锁后的数据
-
排它锁不能与其他锁(排它锁,共享锁)一起使用(否则锁等待),不能读,不能写
-
共享锁可以和共享锁一起使用,不能与排它锁一起使用(否则锁等待)
二、死锁的产生于处理
1. 死锁简介
属于一个现象
死锁的错误显示
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
- 还有一种可能不会直接报错,而是事务1在等待事务2 ,事务2在等待事务1
2. 死锁产生的原因
产生原因
因为两个以上的进程来争夺资源(查询数据),造成互相等待的现象(锁等待)。
事务1等待事务2提交或者回滚,事务2等待事务1提交或者回滚
最容易产生死锁:
模糊查询、范围查询
3. 解决办法
解决办法
1. 锁等待的时间 wait_timeout=120 --设置的是锁等待的时间
锁等待时间结束之后会有一个失败和一个成功mysql的选择与事务的大小有关 select 舍小保大
2. mysql自己去检测到
3. 不能彻底的解决,只能是尽量的避免
4. 避免死锁
避免死锁
1. 以固定的顺序去访问表 或者 行
2. 业务允许的情况下把大的事务拆分成小的事务
三、乐观锁与悲观锁
1. 乐观锁
乐观锁(Optimistic Lock)
顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,
但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。
乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。
1.1 MVCC-乐观锁的解释
MVCC: 多版本并发控制 (Multiversion concurrency control, MCC 或 MVCC),是数据库管理系统常用的一种并发控制,也用于程序设计语言实现事务内存。
主键 用户名 年龄 数据的版本号 数据第一次新增 version默认 1
id username age version
1 name 1 1
select * from user where id =1;
update user set username = '111',version = version+1 where id =1;
2. 悲观锁
悲观锁(Pessimistic Lock)
顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,
这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,
比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
四、间隙锁与行锁升级表锁
1. 间隙锁
1.1 概念
当我们使用范围查询而不是等式查询,并请求(写操作)或者加上排它锁的时候
间隙锁还是属于行级锁
1.2 危害
如果在查询中通过范围去查询摸,锁住的范围会是所有索引的键值,即使这个数据不存在
2. 行锁升级表锁
2.1 为什么行锁会升级表锁的原因
行锁升级为表锁(innodb)
行级锁加锁的where条件,在不加索引的字段(除主键、唯一索引(字段)之外)上进行加锁,会升级为表锁
加了索引之后,加锁会根据普通索引的基础上来进行加锁,而一旦索引失效(范围查询、模糊查询)还是会升级为表锁
2.2 如何避免
不只是排它锁,共享锁也是一样的
1. 尽可能是索引字段进行加锁
2. 尽可能使用等式而不是范围查询、模糊查询