阿里云网站建设素材,dede怎么设置wap网站,林州二建集团建设有限公司网站,搜索软件MySQL 锁是 MySQL 数据库管理系统中为了实现并发控制和数据一致性的机制。在多用户并发访问数据库时#xff0c;锁可以确保多个事务在对同一数据进行操作时不会相互干扰#xff0c;以防止数据不一致的现象发生。
一、锁分类 MySQL支持多种类型的锁#xff0c;主要包括… MySQL 锁是 MySQL 数据库管理系统中为了实现并发控制和数据一致性的机制。在多用户并发访问数据库时锁可以确保多个事务在对同一数据进行操作时不会相互干扰以防止数据不一致的现象发生。
一、锁分类 MySQL支持多种类型的锁主要包括全局锁、表锁、行锁、元数据锁、自增长锁等。 1.1 全局锁 全局锁顾名思义是对整个数据库加锁MySQL提供了加全局锁的方法命令是Flush tables read lock(FTRL)整个库处于只读状态之后其他线程的以下语句都会被阻塞数据更新语句、数据定义语句和更新类事务提交语句。全局锁使用场景做全库备份不过让全库只读听上去很危险。 在 MySQL 中全局锁是对整个 MySQL 实例的锁定而非对单个数据库或表的锁定因此在高并发的生产环境中除非必要一般不建议长时间持有全局锁因为它会严重影响数据库的并发性能。在 InnoDB 存储引擎中全局锁主要用于 MyISAM 表而对于 InnoDB 表通常采用其他机制如行级锁和表级锁来管理并发控制。 1.2 表级锁 表级锁MySQL的表级锁有两种一种是表锁一种是元数据锁。 表锁使用unlock tables主动释放锁也可以在客户端断开时自动释放。 元数据锁(MDL)不需要显示的声明在访问一个表时会自动加上MDL 的作用是保证读写的正确性。你可以想象一下如果一个查询正在遍历一个表中的数据而执行期间另一个线程对这个表结构做变更删了一列那么查询线程拿到的结果跟表结构对不上肯定是不行的。 在 MySQL 5.5 版本中引入了 MDL当对一个表做增删改查操作的时候加 MDL 读锁当要对表做结构变更操作的时候加 MDL 写锁。 我们可以看到 session A 先启动这时候会对表 t 加一个 MDL 读锁。由于 session B 需要的也是 MDL 读锁因此可以正常执行。之后 session C 会被 blocked是因为 session A 的 MDL 读锁还没有释放而 session C 需要 MDL 写锁因此只能被阻塞。 如果只有 session C 自己被阻塞还没什么关系但是之后所有要在表 t 上新申请 MDL 读锁的请求也会被 session C 阻塞。前面我们说了所有对表的增删改查操作都需要先申请 MDL 读锁就都被锁住等于这个表现在完全不可读写了。 如果某个表上的查询语句频繁而且客户端有重试机制也就是说超时后会再起一个新 session 再请求的话这个库的线程很快就会爆满。你现在应该知道了事务中的 MDL 锁在语句执行开始时申请但是语句结束后并不会马上释放而会等到整个事务提交后再释放。 另外 MySQL 支持的 Online DDL 也是通过 MDL 锁来实现的。 Online DDL 执行流程
MDL 写锁获取在执行 Online DDL 之初MySQL会为待修改的表获取 MDL 写锁这会阻止其他会话对同一张表进行 DDL 操作同时在最开始阶段也会阻止 DML 操作确保在结构变更开始时数据的一致性。数据拷贝的 DML 降级根据 DDL 的具体类型MySQL 可能创建一个临时表或者在原地修改表结构。随后 MDL 写锁会被降级成 MDL 读锁或更低级别的锁使得在大部分 DDL 执行过程中对原表的读操作可以继续进行部分兼容写操作也可以在限定条件下并发执行。数据迁移或结构变更对于In-place DDL原地数据定义语言操作操作MySQL 会创建必要的辅助结构如临时表空间或Row Log用于记录DML操作并在原表数据的基础上进行结构变更。对于 Copy-based DDL(基于拷贝的DDL)操作MySQL 会创建一个新表结构并将旧表的数据逐步迁移到新表结构中同时维护一份 Row Log 记录在拷贝过程中发生的 DML 操作。并发控制与 Row log 应用在数据迁移过程中InnoDB 会使用行级锁和/或间隙锁来保证并发 DML 操作的正确性并将这些操作记录在 Row Log 中。在 DDL 操作即将完成时MySQL 会应用 Row Log 中的增量数据确保所有并发的 DML 操作都被正确地反映在最终的新结构上。切换与清理完成数据迁移后MySQL 会将旧表替换为新表如果是copy-based操作或完成原地结构变更如果是in-place操作并在所有 DML 操作均已完成的情况下解除MDL 锁。提交事务与释放锁最终整个 DDL 操作被视为一个事务当所有步骤完成后提交事务释放 MDL 锁使得其他会话可以正常执行 DDL 和 DML 操作。 1.3 行锁 行锁存储引擎层由各个引擎实现的并不是所有的引擎都支持的。行锁就是针对数据表中行记录的锁。在 InnoDB 事务中行锁是在需要时才加上的但并不是不需要了就立即释放而要等到事务结束了才释放。 知道了这个设定我们在日常工作中如果你的事务需要锁多个行要把最可能造成冲突、最可能影响并发度的锁尽量往后放。 InnoDB 存储引擎有两种标准的行级锁
共享锁S Lock允许事务读一行数据排它锁X Lock允许事务删除或更新一行数据 如果一个事务 T1 已经获得了行 r 的共享锁那么另外的事务 T2 可以立即获得行r的共享锁因为读取并没有改变行 r 的数据称这种情况为锁兼容。但若其他的事务 T3 想获取行r的排他锁则必须等待事务 T1、T2 释放行r的共享锁这种情况称为锁不兼容。 1.4 自增长锁 在 InnoDB 存储引擎的内存结构中对每个含有自增值的表都有一个自增长计数器。插入操作会依据这个自增长器加1赋值自增长列。这个实现方式称为 AUTO-INC Locking。这种锁其实采用一种特殊的表锁机制为了提高插入性能锁不是在一个事务完成后才释放而是在完成对自增长值插入的 sql 语句后立即释放。
二、锁升级问题 情况一不走索引 MySQL 行锁只能加在索引上如果操作不走索引就会升级为表锁。因为 InnoDB 的行锁是加在索引上的如果不走索引自然就没法使用行锁了原因是 InnoDB 是将 primary key index 和相关的行数据共同放在 B 树的叶节点。InnoDB 一定会有一个 primary keysecondary index 查找的时候也是通过找到对应的 primary再找对应的数据行。 情况二普通非唯一索引区分度太低 当非唯一索引上记录数超过一定数量时行锁也会升级为表锁。测试发现当非唯一索引相同的内容不少于整个表记录的二分之一时会升级为表锁。因为当非唯一索引相同的内容达到整个记录的二分之一时索引需要的性能比全文检索还要大查询语句优化时会选择不走索引造成索引失效行锁自然就会升级为表锁。
三、MVCC MySQL 的多版本并发控制MVCC, Multi-Version Concurrency Control是一种为了解决并发读写问题提高数据库并发性能的机制。在支持 MVCC 的存储引擎中最典型的是InnoDB。 3.1 一致性非锁定读 指 InnoDB 存储引擎通过多版本控制的方式读取当前执行时数据库中的行数据。如果读的时候正在执行delete或update操作这时读取操作不会因此去等待行上的锁释放。相反的InnoDB存储引擎会读取行的一个快照数据。 可以看到非锁定读机制极大的提高了数据库的并发性。在 InnoDB 存储引擎的默认设置下这是默认的读取方式即读取不会占用和等待表上的锁。 一个行记录可能不止一个快照数据一般称这种技术为行多版本技术。由此带来的并发控制称之为多版本并发控制Multi Version Concurrency Control, MVCC。 不仅 MySQL其他数据库都实现了MVCC只是实现的方式不同MVCC 没有统一的实现标准。MVCC 避免了加锁操作开销较低。 在事务隔离级别 READ COMMITTED 和 REPEATABLE READ 下InnoDB 存储引擎使用非锁定的一致性读。在 READ COMMITTED 隔离级别下对于快照非一致性读总是读取被锁定行的最新一份快照。而在 REPEATABLE READ 隔离级别下对于快照非一致性读总是读取事务开始时的行数据版本。 3.2 一致性锁定读 有些情况下需要显示的对数据库读取操作进行加锁以保证数据逻辑的一致性。InnoDB 存储引擎对于 select 语句支持两种一致性锁定读操作
select ... for update 对读取的行记录加上一个 x 锁其他事务不能对锁定的行加上任何锁select ... lock in share mode 对读取的行记录加上一个 s 锁其他事务可以向被锁定的行加 s 锁但是如果加 x 锁则会被阻塞。
四、锁的算法实现 InnoDB 存储引擎有3种行锁的算法
Record Lock单个行记录上的锁当事务对某一行数据进行修改时会锁定这一行。Gap Lock间隙锁锁定一个范围但不包含记录本身Next-Key Lock上边两种锁的结合锁定一个范围并且锁定记录本身。 4.1 幻读解决 在默认的隔离级别下InnoDB 存储引擎采用 Next-Key Locking 机制来避免幻读问题。幻读是指在同一事务下连续两次执行 同样的 sql 语句可能导致不同的结果第二次 sql 语句可能会返回之前不存在的行。 假如表t中有1、2、5这三个值的三行记录会话A执行2的查询第一次查询出一条记录这时会话B插入了一条4的数据会话A在查询时可能会查到4、5这两条数据造成了幻读。通过Next-Key Locking加锁后会对2∞这个范围加上x锁这个时候的插入是不被允许的从而避免了幻读。
五、死锁 死锁是指两个或两个以上的事务在执行过程中因争夺资源而造成的一种互相等待的现象。解决死锁问题最简单的方法时设置超时时间。 这时事务 A 在等待事务 B 释放 id2 的行锁事务 B 在等待事务 A 释放 id1 的行锁。事务A和事务 B 在互相等待对方释放资源就进入了死锁状态当出现死锁后有两种策略
直接进入等待直到超时发起死锁检测发现死锁后主动回滚死锁链条中某一个事务让其他事务得以正确运行。 死锁检测是有额外负担的可以想像一下这个过程每当一个事务被锁住的时候就要看看他所依赖的线程有没有被别人锁住如此循环最后判断是否出现了循环等待也就是死锁。 在实际应用中合理选择和使用锁机制是优化并发性能和保证数据一致性的关键环节。根据事务的隔离级别和操作需求MySQL会采取不同的锁策略。