聊一聊MySQL里的锁和MVCC

在一个高并发的数据库系统里,可能会遇到多个事务同一时刻修改某条数据的情况,这样就产生了资源冲突,解决冲突就需要用到锁。

一、锁

一说到锁,就可能会联想到乐观锁、悲观锁、共享锁(读锁)、排他锁(互斥锁/写锁)、行级锁、表级锁 等一堆名词,那它们之间到底有什么区别和联系呢?其实很简单,乐观锁和悲观锁是一种加锁的思想;行级锁和表级锁是锁的粒度,表示加锁的范围;而共享锁和排他锁才是真正的锁,用来锁住数据。下面我们分别讨论一下它们。

1.1 乐观锁和排他锁
锁名机制实现原理优点缺点适用场景
乐观锁整个数据处理过程都不加锁,直到处理完准备提交时,才通过版本号检查数据是否过期大多是基于数据版本( Version )记录机制实现,即为每条数据增加一个记录版本号的字段,读取数据时,将版本号一同读出,更新时对此版本号加一,此时若提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为数据已经被其它事务修改过,需要回滚和重试避免了加锁的开销和死锁的出现,提高了系统的并发性能来自外部系统的更新操作不受控制适用于写操作比较少,数据冲突较少的场景
悲观锁数据处理开始时就对数据加锁,直到处理完成才释放锁需要利用数据库本身提供的锁机制来实现,例如共享锁、排他锁外部系统的更新操作也受控制,最大限度的为数据处理的安全性提供了保证加锁开销大,增加产生死锁的可能性,大大降低系统的并发性能适用于写操作比较多,数据冲突严重的场景
1.2 表级锁和行级锁

表级锁和行级锁是一种锁的粒度。一般来说,锁粒度越小,锁冲突就越少,系统的并发性能就更高,但同时数据库在管理锁方面的开销也越大,当管理锁的开销比数据存取的开销还要大时,反而可能会影响到系统的性能。
在MySQL中,每个存储引擎都可以有自己的锁策略,例如MyISAM引擎仅支持表级锁,而InnoDB引擎除了支持表级锁外,也支持行级锁(默认)。行级锁可以最大程度地支持并发处理。

1.3 共享锁和排他锁
锁名机制
共享锁1.当事务A对某资源加了共享锁后,其它事务也只能对该资源加共享锁
2.若想加排他锁,需等待所有事务释放共享锁
3.持有共享锁的事务,都可以读取该资源,但不能修改
排他锁1.当事务A对某资源加了排他锁后,事务A可以读取和修改该资源
2.其它事务不能对该资源加任何锁,直到事务A释放排他锁

共享锁和排他锁是悲观锁不同的实现,它俩都属于悲观锁的范畴。在MySQL InnoDB中,UPDATE/INSERT/DELETE操作都会自动加排他锁,普通的SELECT语句不会加任何锁,如果想加锁,可以使用下面方式:

SELECT * FROM table_name WHERE id = 1 LOCK IN SHARE MODE; -- 显式加共享锁
SELECT * FROM table_name WHERE id = 1 FOR UPDATE; -- 显式加排他锁
二、多版本并发控制(MVCC)

不同的数据库实现MVCC的方式是不一样的,因为MVCC没有一个统一的实现标准,这里我们只谈论MySQL InnoDB中的MVCC。

2.1 为什么需要MVCC

InnoDB采用的是两阶段锁定协议,事务执行过程中,根据需要不断的加锁,最后COMMIT或ROLLBACK的时候一次性释放所有锁,实质上是一种悲观并发控制(悲观锁),而悲观锁会降低系统的并发性能。为了提高并发性能,InnoDB同时还实现了多版本并发控制(MVCC)。

2.2 MVCC的实现原理

简单来说,MVCC就是同一条数据可以同时存在多个版本:更新数据时,先插入一条新记录,然后把旧记录标记为删除;删除数据时将记录标记为删除;查询时只查询事务开始前就已存在的记录。详细的实现就不展开讲了,网上有很多相关资料,详情可以参考这个网站,或者参阅《高性能MySQL第三版》1.4章节。

2.3 MVCC解决的问题

通过了解实现原理,可以看出MVCC解决了这些问题:

  • 在一致性读(快照读)的场景下,保证了事务周期内数据的一致性。事务A开启后,即使事务B对数据做了修改/新增/删除,不管事务B有没有提交,这些变更对于事务A的SELECT语句都是不可见的,因为这些变更是其它事务发起的,并且是在事务A开启后发生的。也就是说,它解决了不可重复读和一致性读场景下的幻读问题。
  • 提高了数据库的并发性能,试想,如果一个数据只有一个版本,那么多个事务对这个数据进行读写是不是需要读写锁来保护? 加锁的话就会造成阻塞,阻塞就会降低并发性能。而在MVCC里,每一个事务都有对应的数据版本,事务A开启后,即使数据被事务B修改,也不影响事务A那个版本的数据,事务A依然可以无阻塞的读取该数据,当然,只是读取不阻塞,写入还是阻塞的,如果事务A也想修改该数据,则必须要等事务B提交释放所有锁后,事务A才可以修改。所以MVCC解决的只是读-写的阻塞问题,写-写依然还是阻塞的。
Mysql机制是用来处理并发访问数据库时的问题,特别是在使用InnoDB引擎支持事务的情况下。机制可以按照的粒度分为表级行级。表级是对整张表进行加,实现简单,消耗的资源较少,加快速,不容易出现死。而行级则是对当前操作的行进行加定粒度更小,可以提高并发性,但加的代价较高。 MySQL的InnoDB存储引擎默认的事务隔离级别是RR(可重复读),这是通过行级多版本并发控制(MVCC起实现的。在正常读取数据时,不会加,而在写入数据时才会进行加操作。 MVCC是通过些技术实现的,包括隐藏字段、Read ViewUndo log。隐藏字段用于存储数据版本信息,Read View用于控制事务的隔离级别,而Undo log则用于记录事务对数据的修改操作,以便在需要回滚时进行恢复。 总结起来,Mysql机制包括表级行级,用于处理并发访问数据库时的问题。而MVCC则是InnoDB存储引擎实现事务隔离级别的种机制,通过隐藏字段、Read ViewUndo log来实现数据的致性并发控制。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Mysql机制+MVCC](https://blog.youkuaiyun.com/qq_45901741/article/details/120245265)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [MySQL事务](https://download.youkuaiyun.com/download/weixin_38739919/13683140)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [mysql机制mvcc](https://blog.youkuaiyun.com/u014618114/article/details/115534734)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值