欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

大白话聊聊mysql的悲观锁

程序员文章站 2024-03-24 08:24:22
...
           目录

         1、什么是悲观锁

         2、mysql的悲观锁实现

         3.  聊聊数据库悲观锁的用途

         4.  聊聊数据库悲观锁的缺点

大家好,我是四九城最豪横的小耳朵。

大白话聊聊mysql的悲观锁

今天咱们来用大白话聊聊mysql的悲观锁。

1、什么是悲观锁

比如线程A对某个变量进行修改,在这个修改期间,它持悲观心理,认为其他线程在这个期间,也有可能去修改这个变量,所以它就给变量加个锁,保证在它修改期间,别的线程没法去访问这个变量。这个锁就是悲观锁。

大白话聊聊mysql的悲观锁

2、mysql的悲观锁实现
假设有这么一个场景。你现在负责一个订单模块,要写一个下单的方法。有一张商品表,商品的状态是 “0 未下单 1 已下单”。 正常的逻辑如图:

大白话聊聊mysql的悲观锁

但是,如果遇到高并发场景,假设2个用户同时对该商品下单,在线程B执行完步骤1的时候,线程A刚好提交了事务,这个时候其实商品的状态已经是“ 1 已下单” 了 ,但是线程B 不知道,继续执行步骤 2 、步骤 3,就会在订单表中出现对该商品的2次下单记录,造成重复下单的问题了。

这种场景,可以考虑用mysql的悲观锁来处理。
怎么使用mysql的悲观锁呢?

  第一步,关闭数据库的自动提交属性。

要使用悲观锁,我们必须关闭mysql数据库的自动提交属性,因为MySQL默认使用autocommit模式,也就是说,当你执行一个更新操作后,MySQL会立刻将结果进行提交。
我们可以使用命令设置MySQL为非autocommit模式:

   set autocommit=0;

   第二步,代码中手动开启事务,提交事务;

    第三步,在select * 语句 最后加上 for update。

我们来看改造后的代码逻辑,如图

大白话聊聊mysql的悲观锁

这样改成之后,假设还是上面的高并发场景,2个用户同时对该商品下单的问题。当线程A先执行完步骤二中的sql"select * fron shop where id = xx and status = 0 for update"后,mysql一看,哦哥们,你这条查询sql末尾有for update啊,它就会对这条数据加上一个锁,除非你的线程A执行完步骤5,把事务提交了,否则线程B执行完步骤1就会卡在那里,一直阻塞着,直到线程A提交了事务,它才能执行步骤2~5。

  1. 聊聊数据库悲观锁的用途

用途其实就是类似上面的场景了。比如你负责的项目,就是一些简单的单体系统,用户量也不大,真的遇到类似的业务场景,你可以考虑用数据库悲观锁来优化你的代码。虽然redis也能实现这种锁的功能,但是你想想,redis也需要维护的,万一挂了怎么办?而且也不是每个公司都有钱随便给你申请服务器的。

  1. 聊聊数据库悲观锁的缺点
    虽然数据库悲观锁可以保证强一致性,但是缺点也很多。如果你的项目是分布式的,并且用户量很大,或者用户增长预计很快,那你就不能贸然使用数据库悲观锁。尤其是如果发生死锁问题那你就麻烦了。

简单罗列一些数据库悲观锁的缺点:

  1. 高并发情况下,大量请求进来,会导致大部分请求进行排队,影响数据库稳定性,也会耗费服务的CPU等资源。当获得锁的客户端等待时间过长时,会提示:

[40001][1205] Lock wait timeout exceeded; try restarting transaction。高并发情况下,也会造成占用过多的应用线程,导致业务无法正常响应。

  1. 如果优先获得锁的线程因为某些原因,一直没有释放掉锁,可能会导致死锁的发生。

  2. 锁的长时间不释放,会一直占用数据库连接,可能会将数据库连接池撑爆,影响其他服务。

End

作者简介:豪横的小耳朵,一个豪横的程序员。想和大家一起在技术的世界里豪横,用技术的眼光去看待世界。欢迎扫描下方二维码,持续关注,一大波原创系列文章正在路上

大白话聊聊mysql的悲观锁

相关标签: