MysqL_SELECT FOR UPDATE详解

时间:2021-08-25 00:09:19

先来举一个在某些应用场景下会出现数据不一致的例子,当然存储引擎是InnoDB(至于为什么,后面再告诉你)。

电商平台常见的下单场景:

一般商品表(goods)有基本的四个字段,id(主键),goods_name (商品名),goods_status是商品状态(下架还是在售),goods_stock(库存)。

用户在购买商品id为1的商品,虽然一般展示层会筛选出在售状态的商品,在严谨的流程中我们还需要判断一下是否在售,商品的库存数量等条件是否正常,来避免出现问题。但并发情况下,可能会出现用户在购买将要付费的时候,商品管理人员抢先把商品下架,就会出现不一致了。

select goods_status,goods_stock from goods where id=;  //查出商品状态和库存

inset into orders (goods_id,goods_count) values (,);      //如果库存和状态正常,把购买的商品和数量写入订单表

接下来还会有付费减库存等操作......

这里商品管理人员突然对商品的状态或者库存做了调整

update goods set goods_status =  where id =;  //修改状态为例//

在上面的场景中,商品信息从查询出来到修改,中间有一个处理订单的过程。那么可以使用悲观锁来解决此问题。

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

要注意的是,使用悲观锁,必须关闭Mysql的自动提交机制:http://www.cnblogs.com/wt645631686/p/7986696.html

//0.开始事务
begin;/begin work;/start transaction; (三者选一就可以)
//1.查询出商品信息
select goods_status from goods where id= for update;
//2.根据商品信息生成订单
insert into orders (goods_id,goods_count) values (3,5);
//3.修改商品status为2
update goods set status=;
//4.提交事务
commit;/commit work;

拿上面的实例来说,当我执行select status from goods where id=3 for update;后。我在另外的事务中如果再次执行select status from goods where id=3 for update;则第二个事务会一直等待第一个事务的提交,此时第二个查询处于阻塞的状态,但是如果我是在第二个事务中执行select status from goods where id=3;则能正常查询出数据,不会受第一个事务的影响。

举例说明
数据库表goods,包括id,status,name三个字段,id为主键,数据库中记录如下;

mysql> select * from goods;
+----+--------+------+
| id | status | name |
+----+--------+------+
| |    | 道具 |
| |    | 装备 |
+----+--------+------+

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

例1: (明确指定主键,并且有此数据,row lock)
console1:查询出结果,但是把该条数据锁定了

mysql> select * from goods where id= for update;
+----+--------+------+
| id | status | name |
+----+--------+------+
| |    | 道具 |
+----+--------+------+

console2:查询被阻塞

mysql> select * from goods where id= for update; 

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

mysql> select * from goods where id= for update;
ERROR : Lock wait timeout exceeded; try restarting transaction

例2: (明确指定主键,若查无此数据,无lock)
console1:查询结果为空

mysql> select * from goods where id= for update;
Empty set

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

mysql> select * from goods where id= for update;
Empty set

例3: (无主键,table lock)

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

mysql> select * from goods where name='道具' for update;
+----+--------+------+
| id | status | name |
+----+--------+------+
| |    | 道具 |
+----+--------+------+

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

mysql> select * from goods where name='装备' for update; 

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

mysql> select * from goods where name='装备' for update;
Query OK, - rows affected

例4: (主键不明确,table lock)
console1:查询正常

mysql> begin;
Query OK, rows affected
mysql> select * from goods where id> for update;
+----+--------+------+
| id | status | name |
+----+--------+------+
| |    | 道具 |
| |    | 装备 |
+----+--------+------+

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

mysql> select * from t_goods where id> for update; 

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

console1:

mysql> begin;
Query OK, rows affected mysql> select * from t_goods where id<> for update;
+----+--------+------+
| id | status | name |
+----+--------+------+
| | | 装备 |
+----+--------+------+

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

mysql> select * from t_goods where id<> for update; 

console1:提交事务

mysql> commit;
Query OK, rows affected

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

mysql> select * from t_goods where id<> for update;
+----+--------+------+
| id | status | name |
+----+--------+------+
| | | 道具 |
+----+--------+------+

以上就是关于数据库主键对MySQL锁级别的影响实例,需要注意的是,除了主键外,使用索引也会影响数据库的锁定级别
举例:
我们修改goods表,给status字段创建一个索引
修改id为2的数据的status为2,此时表中数据为:

mysql> select * from goods;
+----+--------+------+
| id | status | name |
+----+--------+------+
| | | 道具 |
| | | 装备 |
+----+--------+------+

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

console1:

mysql> select * from goods where status= for update;
+----+--------+------+
| id | status | name |
+----+--------+------+
| | | 道具 |
+----+--------+------+

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

mysql> select * from goods where status= for update;
Query OK, - rows affected

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

mysql> select * from goods where status= for update;
+----+--------+------+
| id | status | name |
+----+--------+------+
| | | 装备 |
+----+--------+------+

例7: (明确指定索引,若查无此数据,无lock)
console1:查询status=3的数据,返回空数据

mysql> select * from t_goods where status= for update;
Empty set

console2:查询status=3的数据,返回空数据
Sql代码 收藏代码

mysql> select * from t_goods where status= for update;
Empty set

完毕。。。

MysqL_SELECT FOR UPDATE详解的更多相关文章

  1. MySql之on duplicate key update详解

    在我们的日常开发中,你是否遇到过这种情景:查看某条记录是否存在,不存在的话创建一条新记录,存在的话更新某些字段.你的处理方式是不是就是按照下面这样? $result = mysql_query('se ...

  2. OAF&lowbar;EO系列5 - Update详解和实现(案例)

    2014-06-14 Created By BaoXinjian

  3. EntityFramework Core 1&period;1 Add、Attach、Update、Remove方法如何高效使用详解

    前言 我比较喜欢安静,大概和我喜欢研究和琢磨技术原因相关吧,刚好到了元旦节,这几天可以好好学习下EF Core,同时在项目当中用到EF Core,借此机会给予比较深入的理解,这里我们只讲解和EF 6. ...

  4. Mysql加锁过程详解(4)-select for update&sol;lock in share mode 对事务并发性影响

    Mysql加锁过程详解(1)-基本知识 Mysql加锁过程详解(2)-关于mysql 幻读理解 Mysql加锁过程详解(3)-关于mysql 幻读理解 Mysql加锁过程详解(4)-select fo ...

  5. SQL Update 语句详解

    SQL Update 语句详解   Update 语句 Update 语句用于修改表中的数据. 语法: UPDATE 表名称 SET 列名称 = 新值 WHERE 列名称 = 某值 Person: L ...

  6. Windows环境下执行hadoop命令出现Error&colon; JAVA&lowbar;HOME is incorrectly set Please update D&colon;&bsol;SoftWare&bsol;hadoop-2&period;6&period;0&bsol;conf&bsol;hadoop-env&period;cmd错误的解决办法(图文详解)

    不多说,直接上干货! 导读   win下安装hadoop 大家,别小看win下的安装大数据组件和使用  玩过dubbo和disconf的朋友们,都知道,在win下安装zookeeper是经常的事   ...

  7. Node&period;js npm 详解

    一.npm简介 安装npm请阅读我之前的文章Hello Node中npm安装那一部分,不过只介绍了linux平台,如果是其它平台,有前辈写了更加详细的介绍. npm的全称:Node Package M ...

  8. linux yum命令详解

    yum(全称为 Yellow dog Updater, Modified)是一个在Fedora和RedHat以及SUSE中的Shell前端软件包管理器.基於RPM包管理,能够从指定的服务器自动下载RP ...

  9. MyBatis魔法堂:Insert操作详解(返回主键、批量插入)

    一.前言    数据库操作怎能少了INSERT操作呢?下面记录MyBatis关于INSERT操作的笔记,以便日后查阅. 二. insert元素 属性详解   其属性如下: parameterType  ...

随机推荐

  1. js和jquery获取图片真实的宽度和高度

    1.什么时候需要获取图片真实的宽度和高度 在做pc网页的时候,有时候会考虑按照插入的图片的尺寸来判断图片是横图还是竖图.然后判断过后给予不同的展示方式! 另外一种就是在手机页面上,在新闻页插入的图片往 ...

  2. 向架构师进军---&gt&semi;系统架构设计基础知识

    如果你对项目管理.系统架构有兴趣,请加微信订阅号"softjg",加入这个PM.架构师的大家庭 在讲解系统架构设计之前,有必要补充一下架构相关的概念,因此本博文主要讲述架构.架构师 ...

  3. PDO连接mysql和pgsql数据库

    PDO连接mysql数据库 <?php $dsn="mysql:host=localhsot;dbname=lamp87"; $user="root"; ...

  4. wikioi1012 最大公约数和最小公倍数问题(2001年NOIP全国联赛普及组)

    题目描述 Description 输入二个正整数x0,y0(2<=x0<100000,2<=y0<=1000000),求出满足下列条件的P,Q的个数 条件:  1.P,Q是正整 ...

  5. inputstream与其他格式的转换

    1.InputStream 转换成InputSource . InputStream inputStream = request.getInputStream(); InputSource input ...

  6. RSA 公私钥 互换问题

    关于 RSA,我的理解是: 按定义的话,公私钥是可以互换的 问题是常见的实现里面,保存“私钥”的那个数据结构或者文件,里面除了私钥所必需的那一对数之外,还有额外的信息(足以算出公钥来),所以绝对不能把 ...

  7. 如何使用LightningChart拖放功能进行数据转移 &quest;

    本文主要介绍如何使用LightningChart扩展拖放功能为所有图表组件创建图表,如:系列,标题,轴线等等.支持用鼠标放置自定义对象到另一个图表中,如:可以添加或修改JSON/CSV或其他格式的数据 ...

  8. 解决Jenkins中执行jmeter脚本后不能发报告(原报告被覆盖、新报告无法保存)的问题

    我没有找到根本原因,但是我用了个取巧的办法: 先将原来的报告移到别的文件夹,执行完jmeter脚本后,再把那些旧报告移回来(也可以不移回来,我这里是为了能从jenkins页面上看).

  9. POJ 2443 Set Operation

    Set Operation Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 3558   Accepted: 1479 Des ...

  10. ITxlab倡议启动&OpenCurlyDoubleQuote;互联网X大脑”计划

    导语:"互联网X大脑"计划由ITxlab(互联网X实验室)联合科学院相关机构.基于7年以来取得的研究成果,倡议建立的互联网与脑科学前沿研究平台,吸引不同领域专家进行科学研究和成果交 ...