MysqL_SELECT FOR UPDATE详解
先来举一个在某些应用场景下会出现数据不一致的例子,当然存储引擎是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详解的更多相关文章
- MySql之on duplicate key update详解
在我们的日常开发中,你是否遇到过这种情景:查看某条记录是否存在,不存在的话创建一条新记录,存在的话更新某些字段.你的处理方式是不是就是按照下面这样? $result = mysql_query('se ...
- OAF_EO系列5 - Update详解和实现(案例)
2014-06-14 Created By BaoXinjian
- EntityFramework Core 1.1 Add、Attach、Update、Remove方法如何高效使用详解
前言 我比较喜欢安静,大概和我喜欢研究和琢磨技术原因相关吧,刚好到了元旦节,这几天可以好好学习下EF Core,同时在项目当中用到EF Core,借此机会给予比较深入的理解,这里我们只讲解和EF 6. ...
- Mysql加锁过程详解(4)-select for update/lock in share mode 对事务并发性影响
Mysql加锁过程详解(1)-基本知识 Mysql加锁过程详解(2)-关于mysql 幻读理解 Mysql加锁过程详解(3)-关于mysql 幻读理解 Mysql加锁过程详解(4)-select fo ...
- SQL Update 语句详解
SQL Update 语句详解 Update 语句 Update 语句用于修改表中的数据. 语法: UPDATE 表名称 SET 列名称 = 新值 WHERE 列名称 = 某值 Person: L ...
- Windows环境下执行hadoop命令出现Error: JAVA_HOME is incorrectly set Please update D:\SoftWare\hadoop-2.6.0\conf\hadoop-env.cmd错误的解决办法(图文详解)
不多说,直接上干货! 导读 win下安装hadoop 大家,别小看win下的安装大数据组件和使用 玩过dubbo和disconf的朋友们,都知道,在win下安装zookeeper是经常的事 ...
- Node.js npm 详解
一.npm简介 安装npm请阅读我之前的文章Hello Node中npm安装那一部分,不过只介绍了linux平台,如果是其它平台,有前辈写了更加详细的介绍. npm的全称:Node Package M ...
- linux yum命令详解
yum(全称为 Yellow dog Updater, Modified)是一个在Fedora和RedHat以及SUSE中的Shell前端软件包管理器.基於RPM包管理,能够从指定的服务器自动下载RP ...
- MyBatis魔法堂:Insert操作详解(返回主键、批量插入)
一.前言 数据库操作怎能少了INSERT操作呢?下面记录MyBatis关于INSERT操作的笔记,以便日后查阅. 二. insert元素 属性详解 其属性如下: parameterType ...
随机推荐
- python_斐波那契数列
什么是斐波那契数列? -- 一组第从第三个值开始,每个值都等于前两个值之和的一种有意思的数列 如[1, 1, 2, 3, 5, 8, 13, 21, 34, 55] 如何用程序进行实现? -- 逻辑整 ...
- 无废话XML--XML细节
今天开始研究xml,其实在实际的开发中,我们参与到真正的XML开发并不是很多,最多写一个配置,但是我还是觉得很有必要把XML的知识整理一遍.作为基本的2种的数据交互载体(还有一个是json),基本的X ...
- win7下JAVA环境变量配置方法
1.首先,根据自己的需要下载1.6或者1.7的JDK,安装JDK.(安装的时候记一下安装目录,后面会用到) 2.右键计算机→属性→高级系统设置→高级→环境变量,在系统变量部分新建名为"JAV ...
- Android内核三大核心功能之一AMS内部原理
上面类是AmS的全称,另外两大核心功能是WindowManagerService.java和View.java AmS提供的主要功能: 统一调度各应用程序 内存管理 进程管理 AmS中定义了几个重要的 ...
- Shell 批量复制文件名相近的文件到指定文件名中
问题: 目录结构如下: test/ 2001.01.01/ 2001.02.02/ 2001.03.02/ 2001.01.03/ 2001.02.04/ 2001.03.05/ 2 ...
- shell参数传递
应用实例: #!/bin/bash #运行:bash para_tran.bash text1.txt text2.txt #"set $1"设置存储传入的第一参数 #" ...
- px、pt、em、rem 的区别
px(pixel) 像素,是屏幕上显示数据的最基本的点,表示相对大小(不同分辨率上px显示不同) pt(point) 印刷行业常用的单位(磅),等于1/72英寸,表示绝对长度 em em是相对长度单位 ...
- 基于JAVA实现的排序算法总结
常用的排序方法有:冒泡排序.快速排序.选择排序.插入排序.归并排序,除此之外,还有基数排序.鸡尾酒排序.桶排序.鸽巢排序.希尔排序等,这里着重介绍下前半段列举的几种常见方法的实现. 1. 冒泡排序法: ...
- 浅谈ASP.NET配置文件加密
在刚刚完成的一个ASP.NET项目中,遇到了这么一个问题,项目部署到生产环境中时,领导要求项目中的配置文件(如web.config,app.config)中不能出现敏感字符,如:数据库连接,等等. 第 ...
- Springboot security cas整合方案-实践篇
承接前文Springboot security cas整合方案-原理篇,请在理解原理的情况下再查看实践篇 maven环境 <dependency> <groupId>org.s ...