mysql锁的划分
对数据操作类型划分:读锁 /共享锁/S锁,写锁 /排他锁/X锁 (在InnoDB引擎中读锁和写锁可以加在表上和行上)
锁粒度划分:行级锁(记录锁,间隙锁,临键锁,插入意向锁)
表级锁(S锁,X锁,意向锁,自增锁,元数据锁)
页级锁
对待锁的态度:乐观锁,悲观锁
读锁定
当我们进行读操作的时候可添加两种锁如果只允许一个事务来读加X锁,别的事务也可以读加S锁,获得读锁的事务不仅可以进行读操作,也可以进行写操作
S锁
在select语句末尾添加 lock in share mode
X锁
在select语句末尾添加 for update
在同一个表或同一个记录中S锁与X锁的兼容性
一个行记录添加了X锁如果这个锁没有释放(获得锁的事务没提交)那么就无法添加S锁
写锁定
写锁定主要针对delete,update,insert操作,对于delete,update操作只能添加X锁,但是insert操作一般情况下不添加锁,为了保证insert操作提交前不被其他事务访问sql会添加隐式锁
表锁
MyISAM和InnoDB均支持表锁在InnoDB引擎中为了提高并发度我们一般添加行级锁
S锁,X锁
s锁:lock table 表名 read
x锁:lock table 表名 write
表级锁在不开启事务的情况下需要我们手动释放锁
释放锁:unlock tables
在MyISAM引擎中,无论我们是否主动添加锁,在增删改之前MyISAM引擎都会添加X锁,在查询之前都会添加S锁
意向锁
意向锁是InnoDB独有的一种锁,属于表级锁,用来调节表级锁和行级锁的关系,意向锁由存储引擎自己维护,我们无法手动添加,存储引擎会在数据行添加S锁和X锁之前对表添加意向锁
意向锁的主要作用:当我们添加对表添加表锁的时候,首先会去遍历表中的行是否添加了行锁(表锁与行锁不兼容),这是一个非常耗时的操作,意向锁的会在表中添加行锁对应的表级锁(如果行中出现了X锁那么表上会添加IX锁)
意向锁之间互相兼容,即一个表上可以有多个IS和IX锁
对已经含有意向锁的表(并且这个锁是IS锁)我们只能对这个表添加S锁
自增锁
当字段被auto_increment修饰的时候,会自动的添加表级别的自增锁 (了解即可)
元数据锁(MDL锁)
元数据锁由引擎自己管理,主要目的是保证读写的正确性,我们在对表进行读操作的时候会在表上添加MDL读锁,进行增删改操作的时候会添加MDL写锁
行锁
记录锁
在进行增删改操作的时候对相应的行记录添加S锁和X锁
间隙锁
mysql的默认隔离为REPEATABLE READ只解决了脏读和可重复读但没有解决幻读但我们又无法添加记录锁这时,间隙锁的出现解决了幻读的问题
如果我们在id 3,8之间添加间隙锁(3,8本身不添加任何锁),需要进行如下操作 select * from student where id=5 lock in share mode 此时别的事务就无法在id 3和8间进行插入操作
间隙锁会造成死锁问题 如果在两个事务中我们分别在id 3和8之间添加了间隙锁(添加到不同的id上),那么这个两个事务回造成死锁
解决死锁有两种策略
策略一:设置超时时间 innodb_lock_wait_timeout的值(mysql8的新特性)
策略二:开启死锁检测(将innodb_deadlock_detect设置为on),发生死锁后回主动回滚其中的一个事务(持有最小行级排他锁的事务)
临键锁
临键锁兼具记录锁和间隙锁的功能,我们可以在一个闭区间上加上锁
select * from student where id>=3 and id<=8 for update
上述语句在3,8区间添加了间隙锁并且在3,8的记录行上添加了X锁
插入意向锁
插入意向锁是由存储引擎维护的一种行级锁,如果一个事务创建了间隙锁,另一个事务进行插入操作,那么这个事务会在插入的行上产生一个插入意向锁
悲观锁
添加悲观锁会造成别的事务的阻塞,X锁就属于悲观锁,我们在添加悲观锁的时候一定要创建索引
不然会将语句执行过程中的所扫描到的所有行都添加悲观锁
乐观锁
乐观锁通过代码层面实现的有两种实现方式
1,版本号机制
我们会在表中设置一个字段用于记录版本号,在进行操作前会读取版本号,在进行更新删除操作时先进行版本号判断然后将版本号加一
2,时间戳机制
时间戳机制与版本号机制类似,只是将版本号变成了时间戳