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锁详解的更多相关文章
- java并发编程 | 锁详解:AQS,Lock,ReentrantLock,ReentrantReadWriteLock
原文:java并发编程 | 锁详解:AQS,Lock,ReentrantLock,ReentrantReadWriteLock 锁 锁是用来控制多个线程访问共享资源的方式,java中可以使用synch ...
- 为什么说JAVA中要慎重使用继承 C# 语言历史版本特性(C# 1.0到C# 8.0汇总) SQL Server事务 事务日志 SQL Server 锁详解 软件架构之 23种设计模式 Oracle与Sqlserver:Order by NULL值介绍 asp.net MVC漏油配置总结
为什么说JAVA中要慎重使用继承 这篇文章的主题并非鼓励不使用继承,而是仅从使用继承带来的问题出发,讨论继承机制不太好的地方,从而在使用时慎重选择,避开可能遇到的坑. JAVA中使用到继承就会有两 ...
- SQL Update 语句详解
SQL Update 语句详解 Update 语句 Update 语句用于修改表中的数据. 语法: UPDATE 表名称 SET 列名称 = 新值 WHERE 列名称 = 某值 Person: L ...
- “全栈2019”Java多线程第二十九章:可重入锁与不可重入锁详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- “全栈2019”Java多线程第二十八章:公平锁与非公平锁详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- “全栈2019”Java多线程第十七章:同步锁详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- 进程、线程与GIL全局解释器锁详解
进程与线程的关系: . 线程是最小的调度单位 . 进程是最小的管理单元 . 一个进程必须至少一个线程 . 没有线程,进程也就不复存在 线程特点: 线程的并发是利用cpu上下文的切换(是并发,不是并行) ...
- synchronized锁详解
synchronized的意义 解决了Java共享内存模型带来的线程安全问题: 如:两个线程对初始值为 0 的静态变量一个做自增,一个做自减,各做 5000 次,结果是 0 吗?(针对这个问题进行分析 ...
- for update排他锁详解
使用场景: 高并发并且对于数据的准确性很有要求. 落实到mysql就是在事务中使用,只有使用InnoDB时才用,在begin于commit之间使用(只有此引擎支持事务). 本质: 给表或行上个锁以便接 ...
随机推荐
- nginx 重定向 说明
一.nginx 两个操作系统的安装见以前的随笔(已安装请跳过) linux上搭建nginx windows上搭建nginx 二.Nginx重定向——直接到项目,而非nginx欢迎页 默认ngin修改n ...
- zabbix 自定义 nginx 监控模板
打开zabbix首页→配置→模板→创建模板模板名称:Template App NGINXagent 需添加自定义监控项:UserParameter=nginx.status[*],/bin/bash ...
- Hdoj 1086.You can Solve a Geometry Problem too 题解
Problem Description Many geometry(几何)problems were designed in the ACM/ICPC. And now, I also prepare ...
- Java 枚举 的学习
在JDK5.0之后,引进了一种与C语言相通的枚举类型. 所谓枚举类型就是指含有一组具有固定值, 并且容量有限的数据集合. 例如,定义一个星期的枚举类型, 从周一到周日是具有固定大小和固定值的集合 pu ...
- 【BZOJ3157/3516】国王奇遇记(数论)
[BZOJ3157/3516]国王奇遇记(数论) 题面 BZOJ3157 BZOJ3516 题解 先考虑怎么做\(m\le 100\)的情况. 令\(f(n,k)=\displaystyle \sum ...
- Arukas.io云主机安装CentOS
创建应用 1 jdeathe/centos-ssh:centos-6 启动应用 电机启动应用,应用会自动部署,等显示Running 就说明成功了.估计需要几分钟. 查看用户以及密码 自己保存下用户 ...
- centos7/rhel7下安装redis4.0集群
相关介绍:Redis从3.0版本开始支持集群! 集群一般由多个节点组成,节点数量至少6个才能保证组成完整高可用的集群. 每个节点需要开启配置文件中的cluster-enabled yes,让Redis ...
- Servlet -- 中文乱码解决
请求:对于get和post都有效果 request.setCharacterEncoding("UTF-8"); 相应: 设置服务器输出的编码为UTF-8 response.set ...
- js jquery 数组的合并 对象的合并
转载自:http://www.cnblogs.com/xingxiangyi/p/6416468.html 1 数组合并 1.1 concat 方法 1 2 3 4 var a=[1,2,3],b=[ ...
- MVC Razor
1.@.... 相当于<%=...%> 2.@{} 相当于<%%>,遇到无法自动转换的,需要在前面加@: 3.@() 将某一段代码当做C#代码 4.表单提交name值 ...