先来举一个在某些应用场景下会出现数据不一致的例子,当然存储引擎是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. java并发编程 | 锁详解:AQS,Lock,ReentrantLock,ReentrantReadWriteLock

    原文:java并发编程 | 锁详解:AQS,Lock,ReentrantLock,ReentrantReadWriteLock 锁 锁是用来控制多个线程访问共享资源的方式,java中可以使用synch ...

  2. 为什么说JAVA中要慎重使用继承 C# 语言历史版本特性(C# 1.0到C# 8.0汇总) SQL Server事务 事务日志 SQL Server 锁详解 软件架构之 23种设计模式 Oracle与Sqlserver:Order by NULL值介绍 asp.net MVC漏油配置总结

    为什么说JAVA中要慎重使用继承   这篇文章的主题并非鼓励不使用继承,而是仅从使用继承带来的问题出发,讨论继承机制不太好的地方,从而在使用时慎重选择,避开可能遇到的坑. JAVA中使用到继承就会有两 ...

  3. SQL Update 语句详解

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

  4. “全栈2019”Java多线程第二十九章:可重入锁与不可重入锁详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  5. “全栈2019”Java多线程第二十八章:公平锁与非公平锁详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  6. “全栈2019”Java多线程第十七章:同步锁详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  7. 进程、线程与GIL全局解释器锁详解

    进程与线程的关系: . 线程是最小的调度单位 . 进程是最小的管理单元 . 一个进程必须至少一个线程 . 没有线程,进程也就不复存在 线程特点: 线程的并发是利用cpu上下文的切换(是并发,不是并行) ...

  8. synchronized锁详解

    synchronized的意义 解决了Java共享内存模型带来的线程安全问题: 如:两个线程对初始值为 0 的静态变量一个做自增,一个做自减,各做 5000 次,结果是 0 吗?(针对这个问题进行分析 ...

  9. for update排他锁详解

    使用场景: 高并发并且对于数据的准确性很有要求. 落实到mysql就是在事务中使用,只有使用InnoDB时才用,在begin于commit之间使用(只有此引擎支持事务). 本质: 给表或行上个锁以便接 ...

随机推荐

  1. nginx 重定向 说明

    一.nginx 两个操作系统的安装见以前的随笔(已安装请跳过) linux上搭建nginx windows上搭建nginx 二.Nginx重定向——直接到项目,而非nginx欢迎页 默认ngin修改n ...

  2. zabbix 自定义 nginx 监控模板

    打开zabbix首页→配置→模板→创建模板模板名称:Template App NGINXagent 需添加自定义监控项:UserParameter=nginx.status[*],/bin/bash ...

  3. 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 ...

  4. Java 枚举 的学习

    在JDK5.0之后,引进了一种与C语言相通的枚举类型. 所谓枚举类型就是指含有一组具有固定值, 并且容量有限的数据集合. 例如,定义一个星期的枚举类型, 从周一到周日是具有固定大小和固定值的集合 pu ...

  5. 【BZOJ3157/3516】国王奇遇记(数论)

    [BZOJ3157/3516]国王奇遇记(数论) 题面 BZOJ3157 BZOJ3516 题解 先考虑怎么做\(m\le 100\)的情况. 令\(f(n,k)=\displaystyle \sum ...

  6. Arukas.io云主机安装CentOS

    创建应用   1 jdeathe/centos-ssh:centos-6 启动应用 电机启动应用,应用会自动部署,等显示Running 就说明成功了.估计需要几分钟. 查看用户以及密码 自己保存下用户 ...

  7. centos7/rhel7下安装redis4.0集群

    相关介绍:Redis从3.0版本开始支持集群! 集群一般由多个节点组成,节点数量至少6个才能保证组成完整高可用的集群. 每个节点需要开启配置文件中的cluster-enabled yes,让Redis ...

  8. Servlet -- 中文乱码解决

    请求:对于get和post都有效果 request.setCharacterEncoding("UTF-8"); 相应: 设置服务器输出的编码为UTF-8 response.set ...

  9. js jquery 数组的合并 对象的合并

    转载自:http://www.cnblogs.com/xingxiangyi/p/6416468.html 1 数组合并 1.1 concat 方法 1 2 3 4 var a=[1,2,3],b=[ ...

  10. MVC Razor

    1.@....    相当于<%=...%> 2.@{}  相当于<%%>,遇到无法自动转换的,需要在前面加@: 3.@()  将某一段代码当做C#代码 4.表单提交name值 ...