什么是全局锁
MySQL的锁定主要分为全局锁、表锁和行锁
全局锁是针对整个数据库的锁,全局锁又分为读锁和写锁。
1.读锁(共享锁)
该锁会阻止其他用户更新数据库,只允许读数据库。使用该锁在一段时间内可以保持数据一致性。
2.写锁(排他锁)
该锁会阻止其他用户读数据和写数据。如果在修改数据的时候不想被其他用户干扰,可以使用该锁。
使用场景:一些确保整个数据库一致性的操作,比如全库备份,全库导出。
在MySQL中可以用使用FLUSH TABLES WITH READ LOCK(FTWRL)
添加全局读锁,这将阻止其他线程进行的更新操作。使用UNLOCK TABLES
释放锁定。注意:全局锁的开销很大,因为它会阻止其他线程的修改操作,并且在高并发场景下会导致大量的线程等待锁定,应尽量避免在生产环境使用全局锁或减少全局锁持有的时间。
表级锁开销小加锁快,不会出现死锁,锁定颗粒度大,出现锁冲突概率高并发度低。
在MySQL中对MyISAM读操作会自动加上读锁,对MyISAM的写操作会自动加上写锁,因为MyISAM不支持事务在高并发场景下没办法保持数据的一致性。
InnoDB在必要情况会加表锁,但主要使用行锁来实现多版本并发控制,它能够提供更好的并发性能和更少的锁冲突。
表锁读操作多,写操作少的场景。当并发高或者写操作多表锁会成为瓶颈。
哪些命令会发生锁表
ALTER TABLE
修改表结构,MySQL需要锁定整张表防止在更改过程中有新的数据写入。
DROP TABLE
和TRUNCATE TABLE
MySQL需要锁定整张表防止在更改过程中有新的数据写入。
LOCK TABLES
显式地为一个或多个表加上读锁或写锁。例如,LOCK
TABLES t1 WRITE t2 READ
;命令会给表t1加上写锁,给表t2加上读锁。
全表扫描或大范围扫描`对于MyISAM存储引擎,全表扫描或大范围扫描会触发表锁。
FLUSH TABLES WITH READ LOCK(FTWRL)
这个命令可以给所有表加上全局读锁,其他会话在此期间不能对数据进行修改。
MySQL表锁风险点
对数据库表中单独一行进行锁定。开销大加锁慢会出现死锁,锁定颗粒小出现锁冲突概率低,并发度高。
行锁只能在事务中使用,也就是说只有一个事务开始后并在事务提交或回滚之前,才能对数据进行锁定。如果在非事务环境中执行sql,那么InnoDB会在语句执行结束后立即释放所有的锁。
使用场景
高并发读写操作
:在高并发读写操作场景中,行级锁可以提高性能和并发性,因为它允许多个事务并发操作不同的行。
单行操作
:对单行数据进行增删改操作。
短期锁
:短时间锁定某行数据,行级锁可以防止长时间阻塞其他事务。
实现并发控制
:确保数据的一致性和隔离性的事务中。
复杂事务处理
:对多行数据进行复杂事务处理中,可以使用行级锁来锁定这些行,防止在事务处理过程中数据被其他事务修改。
发生行锁的命令
for update
:这种查询会对选定的行添加一个排他锁(X),那么其他事务就不能对这行数据执行写操作,也不能添加共享锁。[video(video-1NuL7PQd-1702997559118)(type-bilibili)(url-https://player.bilibili.com/player.html?aid=452384717)(image-https://img-blog.csdnimg.cn/img_convert/f3924b83fb438bca02423313f8090285.jpeg)(开启事务时为一行数据加排他锁,其他线程就不能修改该条数据,只有事务提交后其他线程才可以对该条数据执行写操作)]
lock in share dome
: 添加一个共享锁(S),那么其他事务就不能对这行数据执行写操作,但能添加共享锁。insert
会自动添加排他锁(X)update
会自动添加排他锁(X)delete
会自动添加排他锁(X)行锁的风险
是一种在数据库操作中用于处理并发请求的技术。事务操作该条数据前不会立即加锁,而是在数据更改时检查其他事务是否修改了该条数据。如果没有则提交事务,否则回滚。
使用场景
实现方式
通过数据库字段,版本号字段或者时间戳字段。每次修改前把版本号或者时间戳查出来,where 条件带上版本号或者时间戳查,是否是刚才查出来的结果
认为数据在并发处理中一定会被其他事务修改,每次在读数据时都会先加锁,这样可以避免其他事务在并发处理中的读写操作。
使用场景
悲观锁具有先加锁的特点适合一下场景
实现方式
select field from table where id = 1 for update
:意思是给id为1的数据加上排他锁,这样其他事务就不能修改该条数据也不能为该行数据重新设置排他锁或者共享锁。
select field from table where id = 1 lock in share mode
:意思是给id为1的数据加上共享锁,其他事务可以读该条数据但是不能写,也不能为其重新设置排他锁。
意向锁是表锁,为了协调表锁和行锁的关系,支持多粒度(表锁与行锁)的锁并存。
作用
当事务A有行锁时,MySQL会自动为该表添加意向锁,事务B如果想申请整张表的写锁,那么不需要遍历每一行判断是否存在行锁,而是直接判断是否存在意向锁,增强性能。
为什么意向锁是表锁
当我们需要加一个排他锁时,需要根据意向锁去判断表中有没有数据行被锁定。
如果意向锁时行锁,则需要遍历每一行数据去确认。
如果意向锁是表锁,则只需判断一次就可以知道有没有数据行被锁定,提高性能。‘
意向锁怎么支持表锁和行锁并存
并存的概念是数据库同时支持表锁和行锁,而不是在一个表中有一个事务A持有行锁,一个事务B只有表锁。因为一个表一旦持有表锁,就不能再加上一个行锁。
如果事务A对某一行数据上锁,其他事务就不能修改改行数据。所以在没有意向锁的时候让表锁和行锁共存会带来很多问题。数据库不需要检查每一行数据是否有锁,而是直接判断是否存在意向锁。
临键锁可以解决幻读问题。每个数据行上的非唯一索引列都会存在一个临键锁,当某个事务持有该数据行的临键锁时,会锁住一段左开右闭的数据。InnoDB中的行级锁时基于索引实现的,临键锁只与非唯一索引列有关,在唯一索引列(包括主键)不存在临键锁。
该表中存在的临键锁有
(-∞,10]
(10,24]
(24,32]
(32,45]
(45,+∞]
实现方式
主要用于锁定和控制对单个行记录的访问。记录锁是在索引记录上设置的,对于没有主键或唯一索引的表,InnoDB会生成一个隐藏的聚簇索引,并在这个隐藏索引上加锁。
该锁锁定的不是具体的行记录,而是两个索引之间的间隙(区间)。这样可以防止新的记录插入到该间隙,确保数据的一致性和事物的隔离性。
间隙锁主要是为了解决幻读问题。
实现方式