OR博客
MySQL的锁
OrdinaryRoad
创建于:2021-10-03 16:49:20
0
15
83
0
锁是数据库系统区别于文件系统的一个关键特性,用于管理对共享资源的并发访问。
# MySQL的锁 ## 1. 什么是锁 锁是数据库系统区别于文件系统的一个关键特性,用于管理对共享资源的并发访问 ### 分类 - 粒度 - 表锁 - 整个表 - 行锁 - 某一行或多行 - Record Lock:记录锁 - 一行 - Gap Lock:间隙锁 - 左开右闭 - 查到的:1,4;实际锁住的:2,3,4 - Next-Key Lock:临键锁 - 左闭右闭,记录锁+间隙锁 - 查到的:1,4;实际锁住的:1,2,3,4 - 页级锁 - 介于行锁和表锁之间 - ...... - 不同角度的说法 - 属性 - 共享锁 - 排他锁 - 状态 - 意向共享锁 - 意向排他锁 - 意向锁:加锁时设置一个标志位,其他事务只需要判断这个标志位,而不需要扫描每个节点判断是否加锁 - 逻辑层面 - 乐观锁 - 版本控制 - 悲观锁 ### 作用 - 利用锁解决幻读问题 ## 2. Lock和Latch ## 3. InnoDB中的锁 ### 3.1 锁的类型 - 共享锁(S Lock) - 允许事务读一行数据 - 排他锁(X Lock) - 允许事务更新或删除一行数据 ### 3.2 一致性非锁定读 - 读取的记录正在执行UPDATE或DELETE操作,则会读取事务的快照数据undo段 ### 3.3 一致性锁定读 - SELECT ... FOR UPDATE - 事务对读取的记录加X锁,其他事务不能再加任何锁 - RR隔离级别下,总是读取事务开始时的结果 - RC隔离级别下,总是读取最新的快照数据,破坏了隔离性 - SELECT ... LOCK IN SHARE MODE - 事务对读取的记录加S锁,其他事务可以加S锁,但X锁会被阻塞 ## 4. 锁的算法 ## 5. 锁问题 ### 5.0 说明 - 存在快照读和当前读,快照读是记录版本,不加锁,当前读是最新版本,加锁 - 快照读 - 普通select - 当前读 - select ... lock in share mode; (共享锁) - select ... for update; - insert; - update; - delete; ### 5.1 赃读 - 数据可能同时存在内存和磁盘中,看读取的是哪一份 - 一个事务内读取到了另一个事务未提交的修改,破坏了隔离性 ### 5.2 不可重复读 - 一个事务内读取到了另一个事务提交的数据,导致先后两次读取结果不一样,破坏了一致性 - 5.3 丢失更新(第二类) - 事务1和事务2先后修改同一条数据,分别先后提交,先提交的会被后提交的覆盖掉 - 数据库理论上不会出现这种问题,因为事务会等待前面的事务提交完成,更多的是逻辑上的丢失更新 - 自己就遇到过类似的问题:邮件有一个是否读取字段,用户1给用户2发送了一个信函,用户1对邮件进行修改并更新数据库,但是用户2并没有获取数据库最新的版本,本地还是更新前的,此时读取邮件,调用更新接口,将是否读取字段设置为true,同时信函内容又变回修改前的了 - 可以加悲观锁或乐观锁 - 悲观锁:select ... for update - 乐观锁:由程序自己实现,判断版本号,比如更新时间,更新前先查询,拿到旧的更新时间,更新的时候再查询,更新时间一样的话就更新,否则通知用户刷新数据。 ### 幻读 - 没有锁间隙 - 破坏了一致性 ### 第一类丢失更新,(不会发生) - 两个事务修改同一条记录,某一事务完成,另一个事务回滚,造成第一个事务更新丢失 - 现代的关系型数据库已经不会发生,排他锁 ## 6. 阻塞 ## 7. 死锁 ### 7.1 什么是死锁 - 并行下,多个事务因竞争资源而产生的相互等待现象,若没有外力干涉将无法继续执行 - 解决方法 - 超时回滚 - 等待图 - 记录事务等待链表和锁链表 - 事务等待链表 - t1 t2 t3 t4 - 锁的信息列表 - row1 t2:x t1:s - row2 t1:s t4:s t2:x t3:x - 调用关系 - t1->row1.t1:s t2->row2:t2:x t3->row2:t3:x - 等待图 - ``` t1<--->t2 ↖ ^ × | ↙ | t4<--- t3 ``` - 存在回路t1,t2 - 回滚undo量最小的事务 - 判断是否存在回路 - 深度优先 ### 7.2 死锁概率很小 ### 7.3 死锁示例 - AB-BA死锁 - MySQL自动为外键添加索引,删除索引会报错,need a foreign key constraint ## 8. 锁升级 ### 降低锁的粒度 - 一个表的1000行的行锁升级为页锁,页锁升级为表锁 - 目的:如果将锁看为一种稀有资源,降低锁的粒度是为了保护系统资源,一定程度上提高效率 - InnoDB不存在锁升级问题,因为不是根据每条记录产生行锁的,而是根据事务访问的每页对锁进行管理,采用的是位图方式。不管锁住的是一页中的一条记录还是多条记录,开销通常都是一致的。
评论
楼主暂时不想被别人评论哦~