03-MySQL的锁

MySQL的锁

说的大家肯定并不陌生.锁嘛,是为了并发操作时,数据的安全.

Java里也有锁,synchronizedLock

操作系统也有锁.只要是多线程相关的就肯定离不开锁.

MySQL也是一样.但处理的问题不同,锁的种类有些不同.主要是粒度相关.
(本文基于InnoDB引擎)

MySQL 锁分类

MySQL的锁,分为三类

  • 全局
  • 表级
  • 行级

粒度由粗到细.

全局锁

全局锁,顾名思义就是把数据库给锁上了.这种情况下,数据库都无法操作,只能等待操作完成.

这个操作一般用于全库逻辑备份.会让整个库只读.这个操作想一想就很可怕啊.
那整个业务不得要全部停摆吗?

为啥一定得要加锁呢?

加锁,是为了在备份库的时候,数据能够不受影响.

可以想象一下,在银行转账业务中.如果备份不加锁,突然出现了异常.账户余额没有扣除,
那不全完了!

表级锁

表锁

表锁,因为有了行锁,现在很少使用了.作用于对整个表的修改.

会把整个表锁住,其它操作无法执行.代价较大.

举个例子, 如果在线程 A 中执行 lock tables t1 read, t2 write; 这个语句,
则线程A只能读t1,读写t2. 而其它线程只能 写t1,读t2.

元数据(metadata)锁

元数据锁,锁住的是表的结构.读写锁.
读写锁,可以同时读,但不能同时写.读写互斥.

在更改表的结构时,肯定是要得到写锁的.不然你这改一下,他那里改一下的.那不全乱套了吗!

另外,其实在查询的时候,会默认得到元数据锁.得到读锁

你想想,如果在查询数据的时候,查完了.发现和现有的字段对不上了.那怎么能行呢!

在这里插入图片描述

session1 , session2,都是读取数据.它们可以获得读锁,进行查询.
但是当session3 要去添加字段的时候,它要获得写锁,它被阻塞了.

那么session4 来的时候,得不到读锁.它就会一直等待.可能会导致数据库崩了.

行级锁

行锁

行锁,就是一个非常常见的锁了.行级锁在进行数据的更改操作时,
肯定会先得到这一行的锁,然后再进行数据的更新.

当两个更新操作同时更改同一行数据时,就必须等一方commit后,另一方才能继续进行操作.
在InnoDB中行锁是在需要的时候才加上的,在commit之后才归还的.

两阶段锁

那么会涉及到一个两阶段锁的问题.

在这里插入图片描述

在事务A执行时,它update了id为1的行,那么事务B,就必须等待事务A提交才能进行下去.

锁是肯定会影响数据的并发的.那么,我们可以调整sql语句的顺序.尽量把更新操作向后推.
减少事务间的锁等待.提高并发!

有一个问题:如果删除 10000 行数据,下面三种情况哪种更合适

  • 在一个连接中一次删除 10000行
  • 在一个连接中循环10次删除 10000行
  • 在10 个连接中共删除 10000行

聪明的你,一定知道是第二种最好了吧!
因为这样可以减少其它线程等待的时间.

死锁

如果上面的图片中事务A和事务B分别有对方想要更新的行,那么就会造成死锁.

在这里插入图片描述

在图中,当事务A更新了id为1的行后,事务B更新了id为2的行.
但是,这两个事务都没有commit.这就意味它们都留着锁呢!

接下来,当事务A想要更新id为2的锁,但是呢,id为2的锁在事务B那里呢.
它得不到,那么它就只能等待.

事务B也类似.它得不到id为1的锁.这样两个事务就会互相等待.彼此都不释放锁!

那好了.这就一直等下去吧.就形成了 死锁

当然了,数据库也会尽量帮我们解决死锁.

  • 超时检测,默认超过50s就认为是死锁;
  • 死锁检测,主动检测是否存在依赖.存在,主动回滚事务.
发布了92 篇原创文章 · 获赞 18 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/qq_34120430/article/details/99706928