首页 > 数据库 >mysql select for update + 事务处理数据一致性

mysql select for update + 事务处理数据一致性

时间:2023-04-23 16:35:56浏览次数:49  
标签:UPDATE 事务处理 update test num mysql leyangjun 主键 SELECT


如果SELECT 后面若要UPDATE 同一个表数据的相关操作,最好使用SELECT ... FOR UPDATE。

一:举例说明

 假设商品表单test_leyangjun 内有一个存放商品库存的num字段,一个id主键 ,在生成订单前须先确定num>0 ,然后才把数量更新。代码如下(比如现在的库存:num=3对应的id=3,现在生成一个订单需要对库存做扣减少):

      SELECT num FROM test_leyangjun WHERE id=3; UPDATE test_leyangjun SET num = num-1 WHERE id=3;

  确实以上sql看上去没啥问题,逻辑也很明确就是做一个库存更新操作,但是在高并发请求的时候上面的sql就会暴露出对应问题,啥问题呢?就是在高并发请求的时候,如果我们需要在num>0 的情况下才能扣库存,假设程序在第一行SELECT 读到的num=3 ,但当MySQL 正准备要UPDATE 的时候,可能已经有人把库存扣成 “2|1|0 ”了,但是程序是不知道的咔嚓一下就执行UPDATE。因此必须透过的事务机制来确保读取及提交的数据都是正确的。

1: 每次操作开启事务

2:使用MySql -> SELECT ... FOR UPDATE机制

SELECT num FROM test_leyangjun WHERE id=3 FOR UPDATE; UPDATE test_leyangjun SET num = num-1 WHERE id=3;

 

二:注意

1:以上加上锁和for update其是在高并发的时候其实还是有低风险的数据不一致情况,在使用事务更新数据的时候加上历史数据值作为查询条件,改造后应该是这样,已避免风险存在

SELECT num FROM test_leyangjun WHERE id=3 FOR UPDATE; UPDATE test_leyangjun SET num = num-1 AND num = 3 WHERE id=3;//双保险

2:当然了,有些公司DBA是不允许是开发使用FOR UPDATE操作的怕操作不当把表搞挂掉,咋办? ----> 其实直接使用(事务+前提查询条件)也能有效避免,如果有人此时将库存改成其他了,当前这个操作update是执行不成功的回滚,进而保证了库存不超卖

SELECT num FROM test_leyangjun WHERE id=3; UPDATE test_leyangjun SET num = num-1 AND num = 3 WHERE id=3;

注意:select for update 主键索引和普通索引都能用,区别在于主键索引命中后是行锁,普通索引锁的范围更大甚至可能表锁,最终的效果是一样,最好在主键上使用。

 

二:FOR UPDATE锁机制介绍

mysql for update是分为Row Lock 与Table Lock  - - ->  MySQL SELECT ... FOR UPDATE 的Row Lock 与Table Lock,由于InnoDB 预设是Row-Level Lock,所以需指定主键MySQL 才会执行Row lock (锁定被读取的数据) ,否则MySQL 将会执行Table Lock (锁表)。

eg:假设有个表单test_leyangjun ,里面有主键id 跟num,name(普通索引)字段,id 是主键。
1: 明确指定主键,并且有此数据,产生行锁

----->  SELECT * FROM test_leyangjun WHERE id='3' FOR UPDATE;

 

2: 明确指定主键,若查无此数据,不产生锁

----->  SELECT * FROM test_leyangjun WHERE id='-1' FOR UPDATE;

 

3: 非主键含索引(name)进行查询,并且查询到数据,name字段产生行锁(没有查询到数据,不产生锁)         

----->          SELECT * FROM test_leyangjun WHERE name='乐杨俊'  FOR UPDATE;

 

4: 根据主键、非主键不含索引(name)进行查询,没有查询到数据,不产生锁  

----->          SELECT * FROM test_leyangjun WHERE id = 3 AND name='乐杨俊'  FOR UPDATE;

 

5:根据非主键含索引(name)进行查询,并且查询到数据,name字段产生行锁。

----->  SELECT * FROM test_leyangjun WHERE  name='乐杨俊'  FOR UPDATE;

 

6:根据非主键含索引(name)进行查询,没有查询到数据,不产生锁。

----->          SELECT * FROM test_leyangjun WHERE  name='乐杨俊'  FOR UPDATE;

 

7:根据非主键不含索引(name)进行查询,并且查询到数据,name字段产生表锁

----->          SELECT * FROM test_leyangjun WHERE  name='乐杨俊'  FOR UPDATE;

 

8:根据非主键不含索引(name)进行查询,没有查询到数据,name字段产生表锁。

----->          SELECT * FROM test_leyangjun WHERE  name='乐杨俊'  FOR UPDATE;

 

9: 主键不明确,产生表锁

 ----->          SELECT * FROM test_leyangjun WHERE id<>'3' FOR UPDATE;

 

10: 主键不明确,产生表锁

----->          SELECT * FROM test_leyangjun WHERE id LIKE '3' FOR UPDATE;

 

 

标签:UPDATE,事务处理,update,test,num,mysql,leyangjun,主键,SELECT
From: https://blog.51cto.com/u_16085147/6218174

相关文章

  • 基于Canal实现MySQL 8.0 数据库数据同步
    前言服务器说明主机名称操作系统说明192.168.11.82Ubuntu22.04主库所在服务器192.168.11.28OracleLinuxServer8.7从库所在服务器版本说明MySQL版本:MySQL_8.0.32Canal版本:Canal_1.1.7//我的canal安装部署在192.168.11.82上,当然你也可以部......
  • mysql 主从,django操作读写分离
    目录mysql主从搭建步骤1.准备两台机器2.创建文件夹,文件(目录映射)3编写mysql配置文件(主,从)重要启动mysql容器,并做端口和目录映射连接主库修改新建用户连接从库修改配置django操作多数据库方法1.配置文件2.手动读写分离3.自动读写分离4.配置文件添加新点mysql主从目的: 主要做读......
  • sqlserver视图 to mysql表
    sqlserver视图tomysql表有两台服务器,是同一个内网。sqlserver这台只能内网访问mysql这台可内可外现在需要将sqlserver的一个视图数据,每天凌晨同步到另外一台服务器的mysql数据库里共参考:安装sqlserverhttps://www.linuxprobe.com/centos7-instal-mssql-2019.html创......
  • 一篇文章教会你进行Mysql数据库和数据表的基本操作
    前言NaicatforMysql使用通常情况下,我们都是通过mysql.exe(客户端),连接mysql服务的。但是有个问题。第一个问题就是太丑了。第二个问题是因为这不会自动提示啊...,早都习惯了各种自动提示工具,在用这么Low的安装下一步下一步就可以了!!!管理员运行PatchNavicat打开之后,游览到安装N......
  • 1 python操作哨兵 、2 python操作集群、3 缓存优化、4 mysql 主从 、5 django使用多数
    目录1python操作哨兵2python操作集群3缓存优化3.1redis缓存更新策略3.2缓存击穿,雪崩,穿透4mysql主从5django使用多数据库做读写分离1python操作哨兵#高可用架构后---》不能直接连某一个主库了---》主库可能会挂掉,后来它就不是主库了#之前学的连接redis的操作,就用不......
  • Mysql查询语句进阶知识集锦
    前言上次咱们简单的学习了一下select的用法,一篇文章教会你进行Mysql数据库和数据表的基本操作,对数据库大概有了一些基本的了解。咱们接着上次继续来看叭!查询数据如下or查询我们在上学时,会听到这样的话,某某某,你把谁谁谁或者谁谁谁叫过来。这样子的话,我们我们要查询的,就是一个或......
  • mysql主从-day1——mysql主从搭建、django中使用多数据库做读写分离
    目录一、mysql主从5django使用多数据库做读写分离一、mysql主从#之前做过redis的主从,很简单#mysql稍微复杂一些,搭建mysql主从的目的是? -读写分离-单个实例并发量低,提高并发量-只在主库写,读数据都去从库#mysql主从原理步骤一:主库db的更新事件......
  • Django配置mysql数据库
    今天跟大家分享Django配置python的mysql数据库链接工具pymysql。系统环境:windows11x64,pycharm专业2022.3版本,python11,Django4.0。第一步:pip安装pymysql库,在当前django的python环境中用pip install pymysql进行安装。如下图: 我已经安装好,所以不用重新安装,这里需要注意的是有......
  • ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run
      今天执行mysql操作的时候出现了错误:ERROR2002(HY000):Can'tconnecttolocalMySQLserverthroughsocket'/var/run/mysqld/mysqld.sock'问题1:首先检查是否安装了mysql-server了 sudoapt-getinstallmysql-servertoinstallmysqlonubuntu  sudoapt-getin......
  • mysql数据库表的自增id被删后的乱序重排问题
    在对数据库进行操作的时候遇到了这样一个问题,数据库的表里的id是自增的,当数据被删除或者添加时,ID便会一直增上去,id就会变得很乱,不会按照顺序,今天查找了各个网站,终于找到了解决办法altertabletablenamedropcolumnid;altertabletablenameaddidmediumint(8)notnullprim......