- Q1 : MySQL有哪些锁,功能是什么,如何项目中使用?
- Q2 : 行锁是如何实现的?什么情况下会使用行锁?
- Q3 : 四种事务隔离形式的行锁有什么不一样?
- 读未提交
- 读提交
- 可重复读
- 串行
- Q4 : MySQL 的读写都是怎样加锁的?
- Q5 : 需要注意什么?
Q1 : MySQL有哪些锁,功能是什么,如何项目中使用?
- 全局 - 锁定全局(库)的数据,所有写全部阻塞,只能写.
- 只有做全库逻辑备份才会用
- 表锁 - 锁定一个表的数据,避免数据更新时的并发问题
- 行锁 - 锁定某一行/一个区间(间隙)的数据,避免数据更新时的并发问题
- 行锁是通过索引实现的,如果没有索引,那么将会使用表锁.
Q2 : 行锁是如何实现的?什么情况下会使用行锁?
- MySQL 如何加表锁:
- 直接在整个表上加锁,限制全表的读写访问(锁全表)
那么行锁是如何工作的呢?
行锁是通过索引实现的,主要分为两个阶段
-
二级索引(间隙/临建)加锁并命中数据(主键 id)
- 加锁方式: 先根据边界条件或者等值条件命中情况决定加锁的范围
- 没命中: 索引无法命中不存在的 key,但是要避免数据在(事务)执行期间新数据的加入导致数据混乱问题,就会在未命中前后 key 区间加间隙锁,保证执行期间没有数据插入
- 其他: 如果锁范围查询就会对查询范围进行加锁,在结合刚刚的未命中区间,就是二级索引加锁的区间
- 作用: 限制区间的数据插入,避免区间内数据的插入导致结果错误问题
- 加锁方式: 先根据边界条件或者等值条件命中情况决定加锁的范围
-
主键索引加锁
- 根据上面二级索引命中的主键 id,对每个 id 的数据行进行加锁
- 作用: 避免事务执行期间数据被修改
Q3 : 四种事务隔离形式的行锁有什么不一样?
读未提交
有的人说读提交不会显示加锁,我觉得不加锁不科学,不加锁百分百会出现读写并发冲突问题,一定会报错;
但是 MySQL 不会做一个有问题的东西给大家用,那为什么读未提交不会阻塞其他事务,我想只有一个解释锁的生命周期(持有时间)
- 锁持有时间是任务结束(并不是事务结束),不会加间隙锁
- 优点: 锁持有时间短,对其他事务影响小
- 缺点: 脏读问题
读提交
- 锁的生命周期锁整个事务,不会加间隙锁
- 优点: 没有间隙锁,对其他事务(在间隙的数据插入)性能影响小
- 缺点: 数据幻读问题
(思考: 有锁的话读提交还有不可重复读的问题吗?)
可重复读
- 锁的生命周期锁整个事务,会加间隙锁
- 优点: 避免数据幻读
- 缺点: 略微降低数据写入的性能
串行
- 最严格的隔离级别,它通过加 范围锁 或 表锁 来确保事务之间没有冲突,所有读取的数据都必须是其他事务已提交的数据。
- 由于避免了幻读,它会在 查询范围 上加 间隙锁 或 表锁,防止其他事务在查询范围内插入或修改数据。
(我觉得串行不需要锁,单线程的执行事务就没有并发问题了呀,为什么需要锁?搞不懂)
Q4 : MySQL 的读写都是怎样加锁的?
-
MySQL 的普通查询是不会加锁的,而是通过 mvcc 去进行多版本并发控制
-
MySQL 写是通过锁控制的,具体锁的程度根据索引情况与隔离程度而定
Q5 : 需要注意什么?
- 没有索引锁全表
行锁只有索引的条件下才会生效,没有索引会锁全表,造成其他线程阻塞,连接大量堆积,严重影响性能.
没有索引的查询与更新数据在并发情况下表现更差.
索引不仅会减少磁盘 io 的次数加快数据的查询,还可以提高并发情况下的读写性能表现.
参考:
https://www.xiaolincoding.com/mysql/lock/how_to_lock.html#%E5%94%AF%E4%B8%80%E7%B4%A2%E5%BC%95%E8%8C%83%E5%9B%B4%E6%9F%A5%E8%AF%A2
https://juejin.cn/post/6931752749545553933
https://blog.csdn.net/weixin_43994761/article/details/132250415
https://blog.unclezs.com/pages/180d74/#%E7%AE%80%E4%BB%8B