需要注意的是,表锁除了会限制别的线程的读写外,也会限制本线程接下来的读写操作 。
也就是说如果本线程对学生表加了「共享表锁」,那么本线程接下来如果要对学生表执行写操作的语句 , 是会被阻塞的,当然其他线程对学生表进行写操作时也会被阻塞,直到锁被释放 。
要释放表锁,可以使用下面这条命令,会释放当前会话的所有表锁:
unlock tables
另外,当会话退出后 , 也会释放所有表锁 。
不过尽量避免在使用 InnoDB 引擎的表使用表锁,因为表锁的颗粒度太大,会影响并发性能,InnoDB 牛逼的地方在于实现了颗粒度更细的行级锁 。
元数据锁再来说说元数据锁(MDL) 。
我们不需要显示的使用 MDL,因为当我们对数据库表进行操作时,会自动给这个表加上 MDL:
- 对一张表进行 CRUD 操作时,加的是 MDL 读锁;
- 对一张表做结构变更操作的时候 , 加的是 MDL 写锁;
当有线程在执行 select 语句( 加 MDL 读锁)的期间,如果有其他线程要更改该表的结构( 申请 MDL 写锁),那么将会被阻塞,直到执行完 select 语句( 释放 MDL 读锁) 。
反之,当有线程对表结构进行变更( 加 MDL 写锁)的期间,如果有其他线程执行了 CRUD 操作( 申请 MDL 读锁),那么就会被阻塞,直到表结构变更完成( 释放 MDL 写锁) 。
MDL 不需要显示调用 , 那它是在什么时候释放的?MDL 是在事务提交后才会释放,这意味着事务执行期间,MDL 是一直持有的 。
那如果数据库有一个长事务(所谓的长事务,就是开启了事务,但是一直还没提交),那在对表结构做变更操作的时候,可能会发生意想不到的事情,比如下面这个顺序的场景:
- 首先,线程 A 先启用了事务(但是一直不提交),然后执行一条 select 语句,此时就先对该表加上 MDL 读锁;
- 然后,线程 B 也执行了同样的 select 语句,此时并不会阻塞,因为「读读」并不冲突;
- 接着,线程 C 修改了表字段 , 此时由于线程 A 的事务并没有提交,也就是 MDL 读锁还在占用着,这时线程 C 就无法申请到 MDL 写锁,就会被阻塞 ,
为什么线程 C 因为申请不到 MDL 写锁 , 而导致后续的申请读锁的查询操作也会被阻塞?这是因为申请 MDL 锁的操作会形成一个队列,队列中写锁获取优先级高于读锁 , 一旦出现 MDL 写锁等待,会阻塞后续该表的所有 CRUD 操作 。
所以为了能安全的对表结构进行变更,在对表结构变更前 , 先要看看数据库中的长事务,是否有事务已经对表加上了 MDL 读锁,如果可以考虑 kill 掉这个长事务,然后再做表结构的变更 。
意向锁接着,说说意向锁 。
- 在使用 InnoDB 引擎的表里对某些记录加上「共享锁」之前 , 需要先在表级别加上一个「意向共享锁」;
- 在使用 InnoDB 引擎的表里对某些纪录加上「独占锁」之前,需要先在表级别加上一个「意向独占锁」;
而普通的 select 是不会加行级锁的,普通的 select 语句是利用 MVCC 实现一致性读,是无锁的 。
不过,select 也是可以对记录加共享锁和独占锁的,具体方式如下:
//先在表上加上意向共享锁 , 然后对读取的记录加共享锁select ... lock in share mode;//先表上加上意向独占锁 , 然后对读取的记录加独占锁select ... for update;
意向共享锁和意向独占锁是表级锁,不会和行级的共享锁和独占锁发生冲突,而且意向锁之间也不会发生冲突 , 只会和共享表锁(
推荐阅读
- SpringCloud整合分布式事务Seata 1.4.1 支持微服务全局异常拦截
- llinux下mysql建库、新建用户、用户授权、修改用户密码
- 别惹农夫小炎子皮肤怎么解锁
- RedHat7.6安装mysql8步骤
- 别惹农夫药尊者皮肤怎么解锁
- 保险柜怎么开锁(学保险柜开锁技术)
- 再有人说synchronized是重量级锁,就把这篇文章扔给他看
- 究极无敌细节版 Mysql索引
- 原神千柱的花园怎么解锁
- Mysql通过Canal同步Elasticsearch