mysql悲观锁总结和实践

MySQL的`FOR UPDATE`详解 通过本博客,我们详细了解了MySQL中的FOR UPDATE语句,它在事务中起到了锁定数据行的关键作用,确保了数据的一致性和可靠性。FOR UPDATE有所帮助。如果有任何问题或建议,请随时与我们分享。下一篇博客将继续介绍更多有关数据库的知识,敬请期待! 阅读详情

最近学习了一下数据库的悲观锁和乐观锁,根据自己的理解和网上参考资料总结如下:

 

悲观锁介绍(百科):

悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。

 

使用场景举例:以MySQL InnoDB为例

商品goods表中有一个字段status,status为1代表商品未被下单,status为2代表商品已经被下单,那么我们对某个商品下单时必须确保该商品status为1。假设商品的id为1。

 

1如果不采用锁,那么操作方法如下:

//1.查询出商品信息

select status from t_goods where id=1;

//2.根据商品信息生成订单

insert into t_orders (id,goods_id) values (null,1);

//3.修改商品status为2

update t_goods set status=2;

 

上面这种场景在高并发访问的情况下很可能会出现问题。

前面已经提到,只有当goods status为1时才能对该商品下单,上面第一步操作中,查询出来的商品status为1。但是当我们执行第三步Update操作的时候,有可能出现其他人先一步对商品下单把goods status修改为2了,但是我们并不知道数据已经被修改了,这样就可能造成同一个商品被下单2次,使得数据不一致。所以说这种方式是不安全的。

 

2使用悲观锁来实现:

在上面的场景中,商品信息从查询出来到修改,中间有一个处理订单的过程,使用悲观锁的原理就是,当我们在查询出goods信息后就把当前的数据锁定,直到我们修改完毕后再解锁。那么在这个过程中,因为goods被锁定了,就不会出现有第三者来对其进行修改了。

 

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

 

我们可以使用命令设置MySQL为非autocommit模式:

set autocommit=0;

 

设置完autocommit后,我们就可以执行我们的正常业务了。具体如下:

//0.开始事务

begin;/begin work;/start transaction; (三者选一就可以)

//1.查询出商品信息

select status from t_goods where id=1 for update;

//2.根据商品信息生成订单

insert into t_orders (id,goods_id) values (null,1);

//3.修改商品status为2

update t_goods set status=2;

//4.提交事务

commit;/commit work;

 

注:上面的begin/commit为事务的开始和结束,因为在前一步我们关闭了mysql的autocommit,所以需要手动控制事务的提交,在这里就不细表了。

 

上面的第一步我们执行了一次查询操作:select status from t_goods where id=1 for update;

与普通查询不一样的是,我们使用了select…for update的方式,这样就通过数据库实现了悲观锁。此时在t_goods表中,id为1的 那条数据就被我们锁定了,其它的事务必须等本次事务提交之后才能执行。这样我们可以保证当前的数据不会被其它事务修改。

 

注:需要注意的是,在事务中,只有SELECT ... FOR UPDATE 或LOCK IN SHARE MODE 同一笔数据时会等待其它事务结束后才执行,一般SELECT ... 则不受此影响。拿上面的实例来说,当我执行select status from t_goods where id=1 for update;后。我在另外的事务中如果再次执行select status from t_goods where id=1 for update;则第二个事务会一直等待第一个事务的提交,此时第二个查询处于阻塞的状态,但是如果我是在第二个事务中执行select status from t_goods where id=1;则能正常查询出数据,不会受第一个事务的影响。

 

补充:MySQL select…for update的Row Lock与Table Lock

上面我们提到,使用select…for update会把数据给锁住,不过我们需要注意一些锁的级别,MySQL InnoDB默认Row-Level Lock,所以只有「明确」地指定主键,MySQL 才会执行Row lock (只锁住被选取的数据) ,否则MySQL 将会执行Table Lock (将整个数据表单给锁住)。

 

举例说明:

数据库表t_goods,包括id,status,name三个字段,id为主键,数据库中记录如下;

Sql代码   收藏代码
  1. mysql> select * from t_goods;  
  2. +----+--------+------+  
  3. | id | status | name |  
  4. +----+--------+------+  
  5. |  1 |      1 | 道具 |  
  6. |  2 |      1 | 装备 |  
  7. +----+--------+------+  
  8. 2 rows in set  
  9.   
  10. mysql>  

注:为了测试数据库锁,我使用两个console来模拟不同的事务操作,分别用console1、console2来表示。 

 

例1: (明确指定主键,并且有此数据,row lock)

console1:查询出结果,但是把该条数据锁定了

Sql代码   收藏代码
  1. mysql> select * from t_goods where id=1 for update;  
  2. +----+--------+------+  
  3. | id | status | name |  
  4. +----+--------+------+  
  5. |  1 |      1 | 道具 |  
  6. +----+--------+------+  
  7. 1 row in set  
  8.   
  9. mysql>  

console2:查询被阻塞

Sql代码   收藏代码
  1. mysql> select * from t_goods where id=1 for update;  

console2:如果console1长时间未提交,则会报错

Sql代码   收藏代码
  1. mysql> select * from t_goods where id=1 for update;  
  2. ERROR 1205 : Lock wait timeout exceeded; try restarting transaction  

 

例2: (明确指定主键,若查无此数据,无lock)

console1:查询结果为空

Sql代码   收藏代码
  1. mysql> select * from t_goods where id=3 for update;  
  2. Empty set  

console2:查询结果为空,查询无阻塞,说明console1没有对数据执行锁定

Sql代码   收藏代码
  1. mysql> select * from t_goods where id=3 for update;  
  2. Empty set  

 

例3: (无主键,table lock)

console1:查询name=道具 的数据,查询正常

Sql代码   收藏代码
  1. mysql> select * from t_goods where name='道具' for update;  
  2. +----+--------+------+  
  3. | id | status | name |  
  4. +----+--------+------+  
  5. |  1 |      1 | 道具 |  
  6. +----+--------+------+  
  7. 1 row in set  
  8.   
  9. mysql>  

console2:查询name=装备 的数据,查询阻塞,说明console1把表给锁住了

Sql代码   收藏代码
  1. mysql> select * from t_goods where name='装备' for update;  

console2:若console1长时间未提交,则查询返回为空

Sql代码   收藏代码
  1. mysql> select * from t_goods where name='装备' for update;  
  2. Query OK, -1 rows affected  

 

例4: (主键不明确,table lock)

console1:查询正常

Sql代码   收藏代码
  1. mysql> begin;  
  2. Query OK, 0 rows affected  
  3.   
  4. mysql> select * from t_goods where id>0 for update;  
  5. +----+--------+------+  
  6. | id | status | name |  
  7. +----+--------+------+  
  8. |  1 |      1 | 道具 |  
  9. |  2 |      1 | 装备 |  
  10. +----+--------+------+  
  11. 2 rows in set  
  12.   
  13. mysql>  

console2:查询被阻塞,说明console1把表给锁住了

Sql代码   收藏代码
  1. mysql> select * from t_goods where id>1 for update;  

 

例5: (主键不明确,table lock)

console1:

Sql代码   收藏代码
  1. mysql> begin;  
  2. Query OK, 0 rows affected  
  3.   
  4. mysql> select * from t_goods where id<>1 for update;  
  5. +----+--------+------+  
  6. | id | status | name |  
  7. +----+--------+------+  
  8. |  2 |      1 | 装备 |  
  9. +----+--------+------+  
  10. 1 row in set  
  11.   
  12. mysql>  

console2:查询被阻塞,说明console1把表给锁住了

Sql代码   收藏代码
  1. mysql> select * from t_goods where id<>2 for update;  

console1:提交事务

Sql代码   收藏代码
  1. mysql> commit;  
  2. Query OK, 0 rows affected  

console2:console1事务提交后,console2查询结果正常

Sql代码   收藏代码
  1. mysql> select * from t_goods where id<>2 for update;  
  2. +----+--------+------+  
  3. | id | status | name |  
  4. +----+--------+------+  
  5. |  1 |      1 | 道具 |  
  6. +----+--------+------+  
  7. 1 row in set  
  8.   
  9. mysql>  

 

以上就是关于数据库主键对MySQL锁级别的影响实例,需要注意的是,除了主键外,使用索引也会影响数据库的锁定级别

 

举例:

我们修改t_goods表,给status字段创建一个索引

修改id为2的数据的status为2,此时表中数据为:

Sql代码   收藏代码
  1. mysql> select * from t_goods;  
  2. +----+--------+------+  
  3. | id | status | name |  
  4. +----+--------+------+  
  5. |  1 |      1 | 道具 |  
  6. |  2 |      2 | 装备 |  
  7. +----+--------+------+  
  8. 2 rows in set  
  9.   
  10. mysql>  

 

例6: (明确指定索引,并且有此数据,row lock)

console1:

Sql代码   收藏代码
  1. mysql> select * from t_goods where status=1 for update;  
  2. +----+--------+------+  
  3. | id | status | name |  
  4. +----+--------+------+  
  5. |  1 |      1 | 道具 |  
  6. +----+--------+------+  
  7. 1 row in set  
  8.   
  9. mysql>  

console2:查询status=1的数据时阻塞,超时后返回为空,说明数据被console1锁定了

Sql代码   收藏代码
  1. mysql> select * from t_goods where status=1 for update;  
  2. Query OK, -1 rows affected  

console2:查询status=2的数据,能正常查询,说明console1只锁住了行,未锁表

Sql代码   收藏代码
  1. mysql> select * from t_goods where status=2 for update;  
  2. +----+--------+------+  
  3. | id | status | name |  
  4. +----+--------+------+  
  5. |  2 |      2 | 装备 |  
  6. +----+--------+------+  
  7. 1 row in set  
  8.   
  9. mysql>  

 

例7: (明确指定索引,若查无此数据,无lock)

console1:查询status=3的数据,返回空数据

Sql代码   收藏代码
  1. mysql> select * from t_goods where status=3 for update;  
  2. Empty set  

console2:查询status=3的数据,返回空数据

Sql代码   收藏代码
  1. mysql> select * from t_goods where status=3 for update;  
  2. Empty set  

 

 

以上就是关于我对数据库悲观锁的理解和总结,有不对的地方欢迎拍砖,下一次会带来数据库乐观锁的总结和实践

 

参考资料:

MySQL事务与锁定命令:http://www.docin.com/p-16805970.html

悲观锁:http://www.cnblogs.com/chenwenbiao/archive/2012/06/06/2537508.html 

Quantum Espresso实战进阶:HSE混合泛函在能带计算中的精准应用 本文深入探讨了在Quantum Espresso中应用HSE混合泛函进行高精度能带计算的实战方法。针对传统DFT方法低估半导体带隙的问题,HSE通过混合精确交换能,显著提升计算精度。文章详细讲解了从输入文件配置、参数设置(如nqx网格、exxdiv_treatment)、到自洽与非自洽计算流程,以及结果可视化与对比的全过程,并提供了关键的调优与避坑指南,助力实现从PBE到HSE的精准进阶。 阅读详情

相关推荐

报错:subprocess.CalledProcessError: Command ‘[‘where‘, ‘cl‘]‘ returned non-zero exit status 1.

右键此电脑--属性--高级系统设置--环境变量--系统变量--找到Path。Enterprise是企业版,如果你是社区版就找Community。2.安装的时候,c++桌面那个需要勾选。

2301_77554343的博客 1507

一文理解MySQL的For Update行级锁

For update是MySQL中用于实现行锁的一种语法,其主要作用是在SELECT查询语句中加上FOR UPDATE子句,以保证查询结果集中的每一行都被锁定,避免其他事务对这些行进行修改。在执行For update语句时,MySQL会首先获取表级共享锁,然后再根据WHERE条件锁定符合条件的行。锁定的范围包括了WHERE条件筛选出来的所有行,即使有些行并不满足WHERE条件。

Lion_Long的博客 1万+

STM8库函数开发手册(3) //UART1、内部EEPROM、FLASH操作库、IIC(硬、软)

STM8S 微控制器家族的通用同步异步收发器(UART1,UART2 或者UART3)提供了一种灵活的方法与使用工业标准NRZ 异步串行数据格式的外部设备之间进行全双工数据交换。STM8 的UART 提供范围的波特率选择,并且支持多处理器通讯。UART 也支持LIN(局部互联网)协议版本1.3,2.0,和2.1 以及在主模式下的J2602。 UART1 和UAR...

finedayforu的博客 2520

详解mysql的for update

详解mysql的for update 背景 for update是在数据库中上锁用的,可以为数据库中的行上一个排它锁。当一个事务的操作未完成时候,其他事务可以读取但是不能写入或更新。 for update的使用场景 如果遇到存在高并发并且对于数据的准确性很有要求的场景,是需要了解和使用for update的。 比如...

stay hungry ! stay foolish! 4万+

基于单片机的自动喷淋系统设计【毕业设计】

随着人民生活质量提高与生活节奏的加快,城市居民对于花草绿植的家庭培养与装饰需求增加,随之因浇灌植物的需要,智能浇花系统的市场逐渐扩大。现有自动浇花系统大部分只能通过设置固定浇水时间而难以实现适时、适量浇水,或在植物环境土壤含水量低时进行报警而并不能实际补水。为克服局限性而设计以单片机为控制中心的自动浇花系统。通过湿度传感器检测目标植物环境土壤湿度数据,再经ADCO832将其放大转换为数字量,由单片机读取输出向LCD1602 显示屏显示并通过比对键盘向单片机所设置的湿度范围而利用中断服务程序进行补水需求判断。

qq_48771816的博客 1711

最短线性递推式求解与有理函数重建

这一算法来自于我们对“线性递推式拟合”的视角转换,其后得到的算法是自然的。 引理 1. 如果两个有理分式 p1/q1,p2/q2p_1/q_1, p_2/q_2p1​/q1​,p2​/q2​ 均有 deg⁡p<n,deg⁡q≤n\deg p<n, \deg q\leq ndegp<n,degq≤n 且展开式 p1/q1≡p2/q2(modx2n)p_1/q_1 \equiv p_2/q_2 \pmod {x^{2n}}p1​/q1​≡p2​/q2​(modx2n),那么 p1/q1=p2/

Entropy Increaser 的博客 2591

数据库-MySQL中for update的作用和用法

一、for update定义 for update是一种行级锁,又叫排它锁。 一旦用户对某个行施加了行级加锁,则该用户可以查询也可以更新被加锁的数据行,其它用户只能查询但不能更新被加锁的数据行。 如果其它用户想更新该表中的数据行,则也必须对该表施加行级锁.即使多个用户对一个表均使用了共享更新,但也不允许两个事务同时对一个表进行更新,真正对表进行更新时,是以独占方式锁表,一直到提交或复原该事务为止。 行锁永远是独占方式锁。 只有当出现如下之一的条件,才会释放共享更新锁: 执行提交(COMMIT)语

daobuxinzi的博客 6504

开源大模型推理GPU资源评估以及优化

随着大模型的火热很多项目中都使用到了开源大模型,这时候准确评估大模型的GPU资源非常重要,主要有下面几个方面:GPU是昂贵的资源。高估内存需求可能导致在硬件上的不必要支出,而低估则可能导致系统故障或性能下降。:适当的内存管理确保模型高效运行,能够更快地响应用户并处理更多并发请求。:随着需求的增长,理解内存需求对于在不牺牲性能或产生高昂成本的情况下扩展服务至关重要。尽管其重要性显而易见,但计算用于服务大型语言模型(LLM)的GPU内存并不简单。

优快云DN的博客 3116

mysql数据库,悲观锁。for update 的用法。

一、for update定义 for update是一种行级锁,又叫排它锁,一旦用户对某个行施加了行级加锁,则该用户可以查询也可以更新被加锁的数据行,其它用户只能查询但不能更新被加锁的数据行.如果其它用户想更新该表中的数据行,则也必须对该表施加行级锁.即使多个用户对一个表均使用了共享更新,但也不允许两个事务同时对一个表进行更新,真正对表进行更新时,是以独占方式锁表,一直到提交或复原该事务为止。行...

alin1215的博客 2414

华为CNA VRM搭建(使用vmware worfstartion搭建)

华为CNA和VRM在 vmware workstation安装使用

weixin_70595351的博客 1810

【Ubuntu】RK3576 Linux 6.10 Ubuntu 22.04 系统中 HUSB311 Type-C 转 DP 显示输出与 Device/OTG 模式切换配置详解

本文详细介绍了在Rockchip RK3576开发板(Linux Kernel 6.10+Ubuntu 22.04)上配置HUSB311 Type-C控制器的设备树实现方案。主要内容包括:1)硬件连接与模块组成;2)设备树完整配置,涵盖Type-C供电、USB OTG/Host模式、DP显示输出等关键功能;3)软件配置步骤与常见问题排查方法。该方案实现了Type-C接口的DisplayPort AltMode显示输出、USB Device/Host模式自动切换等功能,为嵌入式系统Type-C接口开发提供参考

qq_34478161的博客 808

mysql的悲观锁_mysql悲观锁总结和实践 (转)

最近学习了一下数据库的悲观锁和乐观锁,根据自己的理解和网上参考资料总结如下:悲观锁介绍(百科):悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外...

weixin_36444661的博客 174

innovus:NRDB-2276 special net route layer与NanoRouteMode route layer冲突问题解决方法

NanoRouteMode中设置绕线层次2-6,但是被动到的special net有8-11的preferred route layer,这个层次可能是create_route_type+set_ccopt_property -net_type 定义的。二者绕线层次范围有冲突,导致在调整过这条net后再绕线就会提示失败。然后再下route_design 等route命令去绕别的net。我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧?

m0_61544122的博客 1099

mysql的悲观锁_mysql悲观锁总结和实践(转)

最近学习了一下数据库的悲观锁和乐观锁,根据自己的理解和网上参考资料总结如下:悲观锁介绍(百科):悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外...

weixin_39613433的博客 124

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

mysql 开启悲观锁_mysql悲观锁总结和实践

使用场景举例:以MySQL InnoDB为例商品t_goods表中有一个字段status,status为1代表商品未被下单,status为2代表商品已经被下单,那么我们对某个商品下单时必须确保该商品status为1。假设商品的id为1。一、如果不采用锁,那么操作方法如下://1.查询出商品信息select status from t_goods where id=1;//2.根据商品信息生成订单i...

weixin_32821811的博客 258

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

mysql实现悲观锁语句_mysql悲观锁总结和实践

使用场景举例:以MySQL InnoDB为例商品t_goods表中有一个字段status,status为1代表商品未被下单,status为2代表商品已经被下单,那么我们对某个商品下单时必须确保该商品status为1。假设商品的id为1。一、如果不采用锁,那么操作方法如下://1.查询出商品信息select status from t_goods where id=1;//2.根据商品信息生成订单i...

weixin_42613501的博客 672

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

mysql 悲观锁 性能_mysql悲观锁总结和实践

悲观锁介绍(百科):悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。使用场景举例:以MySQL InnoDB为例商品goo...

weixin_39895995的博客 164

java 使用mysql悲观锁_mysql悲观锁总结和实践

最近学习了一下数据库的悲观锁和乐观锁,根据自己的理解和网上参考资料总结如下:悲观锁介绍(百科):悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外...

weixin_33622085的博客 799

mysql proxy 悲观锁_mysql悲观锁总结和实践

最近学习了一下数据库的悲观锁和乐观锁,根据自己的理解和网上参考资料总结如下:悲观锁介绍(百科):悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外...

weixin_31318441的博客 81

mysql悲观锁关键字_mysql悲观锁总结和实践

最近学习了一下数据库的悲观锁和乐观锁,根据自己的理解和网上参考资料总结如下:悲观锁介绍(百科):悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外...

weixin_34237700的博客 178

mysql对查询上悲观锁无效_mysql悲观锁总结和实践详解

使用场景举例:以MySQL InnoDB为例商品t_goods表中有一个字段status,status为1代表商品未被下单,status为2代表商品已经被下单,那么我们对某个商品下单时必须确保该商品status为1。假设商品的id为1。一、如果不采用锁,那么操作方法如下://1.查询出商品信息select status from t_goods where id=1;//2.根据商品信息生成订单i...

weixin_35161750的博客 692
上一篇: 深入理解乐观锁与悲观锁
下一篇: mysql乐观锁总结和实践
csdn265
博客等级 码龄11年 109粉丝 10原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值