粒度分
1.全局锁
- 读锁:阻止用户更新数据
- 写锁:阻止用户读取和更新数据
当我们在全库备份时,就需要加全局锁
FLUSH TABLES WITH READ LOCK;
2.表锁
- 意向共享锁(IS锁)
- 意向排他锁(IX锁)
Myism 引擎,不支持事务,所以,在读数据时,会自动加上表锁,写数据时,会自动加上写锁
适用于,写操作不频繁的场景
- mySQL哪些命令会发生表级锁
- ALTER TABLE:更改表结构,如添加列、删除列、改变列的类型等。
- DROP TABLE和TRUNCATE TABLE:删除整个表和删除表中的所有数据。
- LOCK TABLES:显式地为一个或多个表加上读锁或写锁。
LOCK TABLES t1 WRITE,t2 READ; #给表t1加上写锁,给表t2加上读锁
3.行锁
- 共享锁(S锁):阻止写
- 排它锁(X锁):组织读和写
mySQL哪些命令会发生行级锁:
- SELECT…FOR UPDATE:这种查询会对选定的行添加一个排他锁(X锁)
- SELECT…LOCK IN SHARE MODE:这种查询会对选定的行添加一个共享锁(S锁)
- NSERT,UPDATE,DELETE:会对新添加的行添加一个排他锁(X锁)。
锁问题:
- 死锁:当两个或更多的事务相互等待对方释放资源时,就会发生死锁。
例如,事务1锁定了行A并试图锁定行B,同时事务2锁定了行B并试图锁定行A,这就形成了死锁。
MySQL会检测到死锁并终止其中一个事务,但这仍可能导致性能问题和事务失败。 - 锁升级:如果一个事务试图锁定的行过多,InnoDB可能会将锁从行级升级为表级,这就可能导致更多的锁冲突。
- 锁等待:如果一个事务已经锁定了某行,其他试图访问这行的事务就必须等待,这可能导致性能下降。如果有大量的事务在等待锁,就可能导致系统出现性能瓶颈。
- 资源消耗:行级锁需要更多的内存来存储锁信息,而且需要更多的CPU时间来处理锁请求和释放锁。如果数据库中的行数非常多,或者并发事务的数量非常多,这可能会导致显著的资源消耗。
- 难以调试和排查:由于行级锁的粒度较小,如果出现性能问题或锁冲突,可能需要复杂的调试和排查工作来找出问题的原因。
模式分
4.乐观锁
- 是一种在数据库操作中用于处理并发问题的技术。
- 它的基本思想是假设在多个事务同时访问同一条数据时,冲突发生的概率较低,因此在操作数据时不会立即进行锁定
- 而是在提交数据更改时检查是否有其他事务修改了这条数据。如果没有,就提交更改,否则就回滚事务。
适用场景
1.读多写少的场景,因为不会频繁更改数据
2.短事务:避免不会频繁的回滚
mysql 实现
- 增加版本号
每次查询时查出版本号
每次修改时,带上版本号,并判断版本号是否和数据库一致
锁问题
耗时间:频繁回滚,就会造成时间消耗
5.悲观锁
一种并发控制的方法,基于一个假设:认为数据在并发处理过程中很可能会出现冲突。因此,为了保证数据的完整性和一致性,每次在读写数据时都会先加锁,这样可以避免其他事务进行并发的读写操作。
是否使用悲观锁需要根据应用的具体需求和场景来决定。在冲突较少,但需要保证数据完整性和一致性的情况下,可以考虑使用悲观锁。
适用场景
1.写多读少的场景
2.并发冲突高,避免重复的回滚
3.对数据的一致性要求较高,可以牺牲一定的性能来满足数据的一致性
mysql 实现
- SELECT…FOR UPDATE:这种查询会对选定的行添加一个排他锁(X锁)
- SELECT…LOCK IN SHARE MODE:这种查询会对选定的行添加一个共享锁(S锁)
锁问题
3. 性能差
4. 并发度降低
5. 锁超时
意向锁(表级锁)
意向锁是表锁,为了协调行锁和表锁的关系,支持多粒度(表锁与行锁)的锁并存。
作用:
当有事务A有行锁时,MySQL会自动为该表添加意向锁,事务B如果想申请整个表的写锁,那么不需要遍历每一行判断是否存在行锁,而直接判断是否存在意向锁,增强性能。
为什么意向锁是表级锁呢?
当我们需要加一个排他锁时,需要根据意枸锁去判断表中有没有数据行被锁定(行锁)
(1)如果意向锁是行锁,则需要遍历每一行数据去确认;
(2)如果意向锁是表锁,则只需要判断一次即可知道有没数据行被锁定,提升性能。
记录锁,间隙锁,临建锁(行级锁)
解决幻读的问题