先来举一个在某些应用场景下会出现数据不一致的例子,当然存储引擎是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. Python35安装

    wnm系列之python安装 下载网址https://www.python.org/downloads/ 之前就用的3.5.4版本,这次还下这个 安装,我直接选择的install now 默认位置安装 ...

  2. Eslint检测出的问题如何自动修复

    1. sublime 插件 eslintAutoFix 目前只试了windows下 真是大坑!如果你用了这个插件但不能自动修复,那就不要再用这个了!全网无解! 提示系统找不到指定的文件,各种路径加入系 ...

  3. Configure an PPTP Server on Debian

    安装PPTP apt-get update apt-get upgrade apt-get install iptables pptpd vim 设置并修改配置文件vim /etc/pptpd.con ...

  4. 【UNR #1】火车管理

    题目描述 uoj 旗下有一个火车站,用来管理属于 uoj 的小火车. 火车站一共有 nn 条编号为 1,…,n1,…,n 的,只有一端的用来存放小火车的铁路,由于小火车特殊的构造,每条铁路可以停放无数 ...

  5. centos7下安装部署mongodb集群(副本集模式)

    环境需求:Mongodb集群有三种模式:  Replica Set, Sharding,Master-Slaver.  这里部署的是Replica Set模式. 测试环境: 这里副本集(Replica ...

  6. nc 使用实例

    nc.exe -h即可看到各参数的使用方法.基本格式:nc [-options] hostname port[s] [ports] ...nc -l -p port [options] [hostna ...

  7. (七)修改上一条SQL语句,NULL值的滤空函数nvl

    修改上一条SQL语句 1.用c命令来修改(c 即 change ) 默认,光标闪烁位置指向上一条SQL语句的第一行.输入二则定位到第二行. c /错误的关键字/正确的关键字 SQL form emp; ...

  8. Codeforces Round #529 (Div. 3) C. Powers Of Two(数学????)

    传送门 题意: 给出一个整数 n ,问能否将 n 分解成 k 个数之和,且这 k 个数必须是2的幂. 如果可以,输出"YES",并打印出任意一组解,反之输出"NO&quo ...

  9. JAVA设计模式初探之适配器模式

    http://blog.csdn.net/jason0539/article/details/22468457 1. 概述 将一个类的接口转换成客户希望的另外一个接口.Adapter模式使得原本由于接 ...

  10. adb导出安卓 把手机内存文件导入到电脑里 adb安装软件

    记得先找对路劲adb shellls 最上面的ls: ./ 打头的没有权限.而下面的这些acct sdcard等 都有权限. 然后cd sdcardls 看下目录,发现gxm文件夹在sdcard下面. ...