🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
> # 乐观锁和悲观锁 > ### 悲观锁 - `悲观锁(Pessimistic Lock)`,顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁、表锁、读锁、写锁等,都是在做操作之前先上锁。 - 假设最坏的情况, 每次读取数据的时候都认为别人会修改,所以每次读取数据都上锁 - MySQL的`FOR SHARE`和`FOR UPDATE`是两种不同的行级锁模式,它们用于控制并发访问数据时的锁定行为。 - `FOR SHARE`是一种共享锁模式,允许多个事务同时获得共享锁以读取数据, - `FOR UPDATE`是一种排他锁模式 - LOCK IN SHARE MODE` 和 `FOR SHARE` 是 MySQL 中两种用于行级锁的方式 --- - 读写(共享锁) : select * from key_table lock in share mode (多个查询间不阻塞, 插入、更新 阻塞) - 写锁(排它锁) : select * from key_table for update (查询、插入、更新 都阻塞) --- - SELECT *,SLEEP(2) FROM `data` lock in share mode; - 这时候去查询表不会阻塞 - SELECT *,SLEEP(2) FROM `data` for update; - 这时候去查询表会阻塞 > ### 乐观锁(**乐观锁适用于多读的应用类型,这样可以提高吞吐量**) - `乐观锁(Optimistic Lock)`,顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量。 - 假设最好的情况, 每次读取数据的时候都认为别人不会修改,不上锁, 只是在更新数据的时候检查有没有其他人也在这个时间段更新数据 - 实现方式1 - 往数据库表添加一个版本号字段, 每次修改前查询当前版本号, 修改时版本号加1 - 1.select id,key1, key2, key3, version from table - 2.update table set key1=5,version=version+1 where id={上查询结果的id} and version={上查询结果的version} - 实现方式2 : 自旋锁 - CAS算法 (缺点:1.存在ABA问题 2.循环时间长、开销很大 3.只能保证一个共享变量的原子操作, ) - MySQL服务运行中, 修改表结构, 那些需要加锁, 哪些不需要 - DML (数据操纵语言,Data Manipulation Language ):增删查改 - DDL(数据定义语言,Data Definition Language): 建库、修改表结构、设置约束等 - Mysql online DDL特性 : https://blog.csdn.net/finalkof1983/article/details/88355314 --- - 我们使用的`mutex`互斥锁类似悲观锁,总是假设会有并发的操作要修改被操作的值,所以使用锁将相关操作放入临界区中加以保护。而使用`CAS`操作的做法趋于乐观锁,总是假设被操作值未曾被改变(即与旧值相等),并一旦确认这个假设的真实性就立即进行值替换。在被操作值被频繁变更的情况下,`CAS`操作并不那么容易成功所以需要不断进行尝试,直到成功为止。 - 原子操作也有劣势。还是以`CAS`操作为例,使用`CAS`操作的做法趋于乐观,总是假设被操作值未曾被改变(即与旧值相等),并一旦确认这个假设的真实性就立即进行值替换,那么在被操作值被频繁变更的情况下,`CAS`操作并不那么容易成功。而使用互斥锁的做法则趋于悲观,我们总假设会有并发的操作要修改被操作的值,并使用锁将相关操作放入临界区中加以保护。 --- > ### 相关阅读 - [MySQL乐观锁电商库存并发问题应用](https://www.jianshu.com/p/efe85c5b4d62) - [ORM链式操作-悲观锁 & 乐观锁](https://goframe.org/pages/viewpage.action?pageId=1114324)