Mysql数据库锁--全局锁、表锁、行锁

Mysql数据库锁--全局锁、表锁、行锁Mysql 数据库按照加锁范围划分 根据加锁的范围 MySQL 里面的锁大致可以分成全局锁 表级锁和行锁三类 全局锁 全局锁就是对整个数据库实例加锁 MySQL 提供了一个加全局读锁的方法 命令是 Flush tables with read lock FTWRL 当你需要让整个库处于只读状态的时候 可以使用这个命令

大家好,我是讯享网,很高兴认识大家。

Mysql数据库按照加锁范围划分

根据加锁的范围,MySQL 里面的锁大致可以分成全局锁、表级锁和行锁三类

全局锁

全局锁就是对整个数据库实例加锁。MySQL 提供了一个加全局读锁的方法,命令是 Flush tables with read lock (FTWRL)。当你需要让整个库处于只读状态的时候,可以使用这个命令,之后其他线程的以下语句会被阻塞:数据更新语句(数据的增删改)、数据定义语句(包括建表、修改表结构等)和更新类事务的提交语句。
全局锁的典型使用场景是,做全库逻辑备份,备份为什么要加锁呢?
不加锁的话,如果此时正在执行一个转账减库存的操作,在转账完成后,还没有减库存,那么最后的数据时不正确的。正在备份系统备份的得到的库不是一个逻辑时间点,这个视图是逻辑不一致的。
那么怎么拿到一个一致性的视图呢?
官方自带的逻辑备份工具是 mysqldump。当 mysqldump 使用参数–single-transaction 的时候,导数据之前就会启动一个事务,来确保拿到一致性视图。而由于 MVCC 的支持,这个过程中数据是可以正常更新的。

表锁

LOCK TABLES table_name [AS alias_name] {READ | WRITE} 

讯享网
  • table_name: 要锁定的表名。
  • AS alias_name: 可选项,允许你为表指定一个别名。
  • READ 或 WRITE: 表示要对表执行的锁定类型。READ锁允许其他会话读取表中的数据,但不允许对表进行写操作,而WRITE锁则允许对表进行写操作,同时也禁止其他会话对表进行读或写操作。
    2、另一类表级的锁是 MDL(metadata lock)
    MDL 不需要显式使用,在访问一个表的时候会被自动加上。
    当对一个表做增删改查操作的时候,加 MDL 读锁;当要对表做结构变更操作的时候,加 MDL 写锁。
  • 读锁之间不互斥,因此你可以有多个线程同时对一张表增删改查。
  • 读写锁之间、写锁之间是互斥的,用来保证变更表结构操作的安全性。因此,如果有两个线程要同时给一个表加字段,其中一个要等另一个执行完才能开始执行。

在 MySQL 的 information_schema 库的 innodb_trx 表中,你可以查到当前执行中的事务。如果你要做 DDL 变更的表刚好有长事务在执行,要考虑先暂停 DDL,或者 kill 掉这个长事务。

行锁


讯享网

在这里插入图片描述

上述两个事务中查看表锁的情况

讯享网 SHOW OPEN TABLES WHERE In_use > 0; +----------+----------+--------+-------------+ | Database | Table | In_use | Name_locked | +----------+----------+--------+-------------+ | niuke | salaries | 1 | 0 | +----------+----------+--------+-------------+ 1 row in set (0.01 sec) 

死锁和死锁检测:当并发系统中不同线程出现循环资源依赖,涉及的线程都在等待别的线程释放资源时,就会导致这几个线程都进入无限等待的状态,称为死锁。这里我用数据库中的行锁举个例子。

当出现死锁以后,有两种策略:

  • 一种策略是,直接进入等待,直到超时。这个超时时间可以通过参数 innodb_lock_wait_timeout 来设置。,innodb_lock_wait_timeout 的默认值是 50s。
  • 另一种策略是,发起死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。将参数 innodb_deadlock_detect 设置为 on,表示开启这个逻辑。

死锁情况自动检测实例

ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction 
  • 一种头痛医头的方法,就是如果你能确保这个业务一定不会出现死锁,可以临时把死锁检测关掉。但是这种操作本身带有一定的风险,因为业务设计的时候一般不会把死锁当做一个严重错误,毕竟出现死锁了,就回滚,然后通过业务重试一般就没问题了,这是业务无损的。而关掉死锁检测意味着可能会出现大量的超时,这是业务有损的。
  • 另一个思路是控制并发度。根据上面的分析,你会发现如果并发能够控制住,比如同一行同时最多只有 10 个线程在更新,那么死锁检测的成本很低,就不会出现这个问题。一个直接的想法就是,在客户端做并发控制。但是,你会很快发现这个方法不太可行,因为客户端很多。我见过一个应用,有 600 个客户端,这样即使每个客户端控制到只有 5 个并发线程,汇总到数据库服务端以后,峰值并发数也可能要达到 3000。
  • 因此,这个并发控制要做在数据库服务端。如果你有中间件,可以考虑在中间件实现;如果你的团队有能修改 MySQL 源码的人,也可以做在 MySQL 里面。基本思路就是,对于相同行的更新,在进入引擎之前排队。这样在 InnoDB 内部就不会有大量的死锁检测工作了。
小讯
上一篇 2025-01-25 10:33
下一篇 2025-01-11 22:30

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/129801.html