| 页锁就是在页的粒度上进行锁定,锁定的数据资源比行锁要多,因为一个页中可以有多个行记录。当我们使用页锁的时候,会出现数据浪费的现象,但这样的浪费最多也就是一个页上的数据行。 |
| 页锁的开销介于表锁和行锁之间,会出现死锁。锁定粒度介于表锁和行锁之间,并发度一般。 |
| |
| 每个层级的锁数量是有限制的,因为锁会占用内存空间,锁空间的大小是有限的。当某个层级的锁数量超过了这个层级的阈值时,就会进行锁升级。锁升级就是用更大粒度的锁替代多个更小粒度的锁, |
| 比如InnoDB中行锁升级为表锁,这样做的好处是占用的锁空间降低了,但同时数据的并发度也下降了。 |
| 悲观锁是一种思想,顾名思义,就是很悲观,对数据被其他事务的修改持保守态度,会通过数据库自身的锁机制来实现,从而保证数据操作的排它性。 |
| 悲观锁总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会 阻塞 直到它拿到锁(共享资源每次只给一个线程使用, |
| 其它线程阻塞,用完后再把资源转让给其它线程)。比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁,当其他线程想要访问数据时,都需要阻塞挂起。Java中 synchronized 和 ReentrantLock 等独占锁就是悲观锁思想的实现 |
| |
| # 例如在商品秒杀的情景中,避免出现超卖的情况 |
| # 商品信息从查询、生成订单、修改的这个过程,查询到数据后,获取锁,知道修改数据后才释放锁 |
| # 需要将执行的业务放到1个事务中 |
| # 1.查询数据 |
| select quantity from items where id = 1001 for update; |
| # 2. 生成订单 |
| insert into orders(item_id) values(1001); |
| # 3. 修改库存 |
| update items set quantity = quantity-num where id = 1001; |
| |
| # 在使用悲观锁时,必须对要查询的对象使用索引 |
| # 悲观锁对于比较多的业务,开销较大 |
| 乐观锁认为对同一数据的并发操作不会总发生,属于小概率事件,不用每次都对数据上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,也就是不采用数据库自身的锁机制, |
| 而是通过程序来实现。在程序上,我们可以采用 版本号机制 或者 CAS机制 实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量。在Java中 java.util.concurrent.atomic 包下的 |
| 原子变量类就是使用了乐观锁的一种实现方式:CAS实现的 |
| |
| # 实现方式1:版本号机制 |
| # 在表中添加1个字段version,第1个事务第1次读的时候,会拿到这个版本号,最后修改库存的时候,判断版本号是否一致,一致才能修改成功 |
| # 1.查询数据 |
| select quantity from items where id = 1001 for update; |
| # 2. 生成订单 |
| insert into orders(item_id) values(1001); |
| # 3. 修改库存 |
| update items set quantity = quantity-num where id = 1001 and version = 1; |
| |
| # 实现方式2:时间戳机制 |
| # 第1个事务第1次读的时候,会拿到这个时间戳,最后修改库存的时候,判断时间戳是否一致,一致才能修改成功 |
| # 1.查询数据 |
| select quantity from items where id = 1001 for update; |
| # 2. 生成订单 |
| insert into orders(item_id) values(1001); |
| # 3. 修改库存 |
| update items set quantity = quantity-num where id = 1001 and updated = 123456; |
| |
| # 如果数据库是读写分离的表,当主表写入的数据,没有及时同步到从表时,需强制去主表中读数据 |
| |
| # 在使用版本号机制的时候,多个事务第1次读的时候,版本号都是1,当其中1个事务修改后,其他事务则都会修改失败 |
| # 由于每次只有1个事务能够成功,会导致业务感知上有大量的失败操作 |
| # 为了避免以上的现象,可以在最后修改库存时,判断库存不为0则能成功 |
| # 1.查询数据 |
| select quantity from items where id = 1001 for update; |
| # 2. 生成订单 |
| insert into orders(item_id) values(1001); |
| # 3. 修改库存 |
| update items set quantity = quantity-num where id = 1001 and quantity-num > 0; |
| 乐观锁适合读操作比较多的场景 |
| 悲观锁适合写操作比较多的场景 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
· 提示词工程——AI应用必不可少的技术