image.png
mysql的锁大概分为悲观锁跟乐观锁两类

乐观锁

基本上是代码逻辑控制的,在数据表中加一个时间戳的版本号,每次修改更新这个时间,每次修改前先拿到上次的时间,再以时间跟条件修改数据,判断是否成功就可以

  1. update `type` set name='改变值',editTime=unix_timestamp(now()) where id=1 and editTime=1639452257;

悲观锁

悲观锁分类比较负责,大致分为表锁,行锁,读锁跟写锁

表锁

Mylsam引擎就是表锁,
表锁不是存储引擎控制的,是有其上一层,MySQL server,负责的
如果需要给innodb的引擎通过lock来加表锁,需要配置项(当autocommit=0、InnoDB_table_locks=1(默认设置)时,InnoDB层才能知道MySQL加的表锁)这样innodb引擎才可以自动识别涉及表的死锁,另外在事务中使用释放表锁的命令会隐含的提交事务,而提交回滚事务不能释放表锁,所以,回滚,提交前后释放锁
共享读锁(表锁)
读锁加上后,当前进程只允许访问加锁的表,其他进程依然可以自由访问,也可以加读锁,但是已加锁的表,不能修改,直到表锁被释放,而且多个表加读锁,只有最后的会成功,只会加一个

-- 加锁
lock table `表名` read;
select * from `name`;
-- 查看表锁情况
show OPEN TABLES where In_use > 0;
-- 删除表锁
unlock table;

共享写锁(表锁)
写锁加上后,本进程只允许修改,不允许查看其他表数据,其他进程不可以查看,修改已加锁数据

-- 加锁
lock table `表名` write;
UPDATE `表名` set `name`='hauahuaua' where id=57;
-- 查看表锁情况
show OPEN TABLES where In_use > 0;
-- 删除表锁
unlock table;

删除表锁
执行命令 SHOW PROCESSLIST;
查看当State列内容中有lock状态,那么通过Info列就可以得出哪张表被锁了,查到进程id
解锁:kill 进程id
元数据锁(自动加锁,不用控制)
保护表的元数据信息一致性,解决或者保证DDL,操作与DML操作之间的一致性,保证在修改数据的时候不会有进程修改表结构,反之亦然
对一个表做增删改查操作的时候,加MDL读锁,当对表做结构变更操作的时候,加DML写锁

 --开启事务
 begin; 
 --加MDL读锁
 select * from 表名;
 --提交事务 或者 rollback 释放读锁
 commit; 
 --在此期间 其他事务 修改表结构阻塞
 alter table 表名 add f int;

查看表锁状态
show OPEN TABLES where In_use > 0;
字段解释:
Database:包含表的数据库。
Table:表名。
In_use:表的表锁或锁请求数。例如,如果一个客户端使用获取锁定为一个表LOCK TABLE t1 WRITE,In_use将是1,如果其他客户端的问题LOCK TABLE t1 WRITE,而表保持锁定时,客户端将阻塞等待锁,但是锁定请求的原因In_use是2.如果计数零,表处于打开状态,但当前未使用
Name_locked:表名是否被锁定。名称锁定用于诸如删除或重命名表的操作。

行锁

需要跟事务配合使用,提交或者回滚,就是的解锁
InnoDB引擎是行锁,不过行锁都是基于索引实现的行锁,如果加锁sql中没有使用索引则会变成表锁
按照范围分三种
记录锁: 锁定索引中的一条记录
间隙锁:锁定记录前,记录中,记录后的行,例如查询1-7范围内的,1 7会被加上做,中间范围内数据也会加上锁,但是中间不存在的比如id3,就成为间隙,如果有insert插入id为3的,需要等解锁,(当加锁数据为范围时,自动加上间隙锁,也就不会出现幻读的情况了)
Next-Key锁:记录锁加间隙锁
读锁(行锁)
加行读锁后,本事务可以任意操作,修改,添加,加锁,其他事务可以对加锁数据加行读锁,但是不可以加写锁,也不可以修改数据

--开启事务
begin;
--加行读锁
select * from `name` where id=57 lock in share mode; 
 --提交事务 或者 rollback 释放读锁
commit;

写锁(行锁)
加行写锁后,本事务可以任意操作,修改,添加,加锁,其他事务不可以对加锁数据加锁,修改数据,但是可以查询数据

--开启事务
begin;
--加行写锁
select * from `name` where id=57 for update; 
 --提交事务 或者 rollback 释放读锁
commit;

查看行锁状态
show STATUS like ‘innodb_row_lock%’;
参数:
Innodb_row_lock_current_waits:当前正在等待锁定的数量;
Innodb_row_lock_time:从系统启动到现在锁定总时间长度;
Innodb_row_lock_time_avg:每次等待所花平均时间;
Innodb_row_lock_time_max:从系统启动到现在等待最常的一次所花的时间;
Innodbrowlockwaits:系统启动后到现在总共等待的次;

死锁

innnoDB事务管理跟锁机制中,有专门检测死锁的机制,会在系统产生死锁之后很短时间检测到,会通过响应的判断,来选产生死锁的两个事务中较小的事务来回滚,让另外一个比较大的完成,
防止死锁,加锁顺序有次序