Select…For Update语句的语法与select语句相同,只是在select语句的后面加FOR UPDATE [NOWAIT]子句。

该语句用来锁定特定的行(如果有where子句,就是满足where条件的那些行)。当这些行被锁定后,其他会话可以选择这些行,但不能更改或删除这些行,直到该语句的事务被commit语句或rollback语句结束为止。

MySQL  使用SELECT ... FOR UPDATE 做事务写入前的确认

以MySQL 的InnoDB 为例,预设的Tansaction isolation level 为REPEATABLE READ,在SELECT 的读取锁定主要分为两种方式:

SELECT ... LOCK IN SHARE MODE SELECT ... FOR UPDATE

这两种方式在事务(Transaction) 进行当中SELECT 到同一个数据表时,都必须等待其它事务数据被提交(Commit)后才会执行。而主要的不同在于LOCK IN SHARE MODE 在有一方事务要Update 同一个表单时很容易造成死锁 。

简单的说,如果SELECT 后面若要UPDATE 同一个表单,最好使用SELECT ... UPDATE。

举个例子: 假设商品表单products 内有一个存放商品数量的quantity ,在订单成立之前必须先确定quantity 商品数量是否足够(quantity>0) ,然后才把数量更新为1。

不安全的做法:

SELECT quantity FROM products WHERE id=3; UPDATE products SET quantity = 1 WHERE id=3;

为什么不安全呢?

少量的状况下或许不会有问题,但是大量的数据存取「铁定」会出问题。

如果我们需要在quantity>0 的情况下才能扣库存,假设程序在第一行SELECT 读到的quantity 是2 ,看起来数字没有错,但是当MySQL 正准备要UPDATE 的时候,可能已经有人把库存扣成0 了,但是程序却浑然不知,将错就错的UPDATE 下去了。

因此必须透过的事务机制来确保读取及提交的数据都是正确的。

于是我们在MySQL 就可以这样测试: (注1)

SET AUTOCOMMIT=0; BEGIN WORK; SELECT quantity FROM products WHERE id=3 FOR UPDATE; ===========================================

此时products 数据中id=3 的数据被锁住(注3),其它事务必须等待此次事务 提交后才能执行

SELECT * FROM products WHERE id=3 FOR UPDATE (注2) 如此可以确保quantity 在别的事务读到的数字是正确的。 ===========================================

UPDATE products SET quantity = '1' WHERE id=3 ; COMMIT WORK;

===========================================

提交(Commit)写入数据库,products 解锁。

注1: BEGIN/COMMIT 为事务的起始及结束点,可使用二个以上的MySQL Command 视窗来交互观察锁定的状况。

注2: 在事务进行当中,只有SELECT ... FOR UPDATE 或LOCK IN SHARE MODE 同一笔数据时会等待其它事务结束后才执行,一般SELECT ... 则不受此影响。

注3: 由于InnoDB 预设为Row-level Lock,数据列的锁定可参考这篇。

注4: InnoDB 表单尽量不要使用LOCK TABLES 指令,若情非得已要使用,请先看官方对于InnoDB 使用LOCK TABLES 的说明,以免造成系统经常发生死锁。

MySQL SELECT ... FOR UPDATE 的Row Lock 与Table Lock

上面介绍过SELECT ... FOR UPDATE 的用法,不过锁定(Lock)的数据是判别就得要注意一下了。由于InnoDB 预设是Row-Level Lock,所以只有「明确」的指定主键,MySQL 才会执行Row lock (只锁住被选取的数据) ,否则MySQL 将会执行Table Lock (将整个数据表单给锁住)。

举个例子:

假设有个表单products ,里面有id 跟name 二个栏位,id 是主键。

例1: (明确指定主键,并且有此数据,row lock)

SELECT * FROM products WHERE id='3' FOR UPDATE;

例2: (明确指定主键,若查无此数据,无lock)

SELECT * FROM products WHERE id='-1' FOR UPDATE;

例2: (无主键,table lock)

SELECT * FROM products WHERE name='Mouse' FOR UPDATE;

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

SELECT * FROM products WHERE id<>'3' FOR UPDATE;

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

SELECT * FROM products WHERE id LIKE '3' FOR UPDATE;

注1: FOR UPDATE 仅适用于InnoDB,且必须在事务区块(BEGIN/COMMIT)中才能生效。

注2: 要测试锁定的状况,可以利用MySQL 的Command Mode ,开二个视窗来做测试。

MySQL 使用SELECT ... FOR UPDATE 做事务写入前的确认(转)的更多相关文章

  1. mysql锁SELECT FOR UPDATE【转】

    MySQL 使用SELECT ... FOR UPDATE 做事务写入前的确认 以MySQL 的InnoDB 为例,预设的Tansaction isolation level 为REPEATABLE ...

  2. MySQL中select * for update锁表的范围

    MySQL中select * for update锁表的问题 由于InnoDB预设是Row-Level Lock,所以只有「明确」的指定主键,MySQL才会执行Row lock (只锁住被选取的资料例 ...

  3. MySQL中select * for update锁表的问题

    MySQL中select * for update锁表的问题 由于InnoDB预设是Row-Level Lock,所以只有「明确」的指定主键,MySQL才会执行Row lock (只锁住被选取的资料例 ...

  4. 数据库:Mysql中“select ... for update”排他锁分析

    Mysql InnoDB 排他锁 用法: select … for update; 例如:select * from goods where id = 1 for update; 排他锁的申请前提:没 ...

  5. Mysql中“select ... for update”排他锁(转)

    原帖地址 https://blog.csdn.net/claram/article/details/54023216 Mysql InnoDB 排他锁 用法: select … for update; ...

  6. MySQL的SELECT ...for update

    最近的项目中,因为涉及到Mysql数据中乐观锁和悲观锁的使用,所以结合项目和网上的知识点对乐观锁和悲观锁的知识进行总结. 悲观锁介绍 悲观锁是对数据被的修改持悲观态度(认为数据在被修改的时候一定会存在 ...

  7. MySQL中select * for update锁表的问题(转)

    由于InnoDB预设是Row-Level Lock,所以只有「明确」的指定主键,MySQL才会执行Row lock (只锁住被选取的资料例) ,否则MySQL将会执行Table Lock (将整个资料 ...

  8. mysql 中select for update 锁表的范围备注

    mysql的锁表范围测试 1.主键明确时,行级锁: 解释:指定主键并且数据存在时,仅锁定指定的行,其它行可以进行操作 实例:指定了锁定id=1的行且数据存在①,在更新1时lock wait超时②,但是 ...

  9. mysql进阶(四)mysql中select

    mysql中select * for update 注:  FOR UPDATE 仅适用于InnoDB,且必须在事务区块(BEGIN/COMMIT)中才能生效. 作用 锁定该语句所选择到的对象.防止在 ...

随机推荐

  1. 【CodeForces 699B】One Bomb

    r[i],c[i]分别表示第i行有几个*,第i列有几个*. 枚举每个位置如果c[i]+r[j]-(本身是不是*)==总*数,则该位置即为答案. #include<cstdio> #incl ...

  2. Unity 移动端触摸屏操作

    Unity 触屏操作 当将Unity游戏运行到IOS或Android设备上时,桌面系统的鼠标左键可以自动变为手机屏幕上的触屏操作,但如多点触屏等操作却是无法利用鼠标操作进行的.Unity的Input类 ...

  3. 57. Android之程序调试LogCat (转)

    无论什么样的程序开发过程中,出现错误都是不可避免的,一般情况下,语法错误会被开发环境检测到,并能及时的提示我们错误的位置以及修改的方法,但是逻辑错误就不是那么容易被发现了,通常逻辑错误的定位和分析是一 ...

  4. Hadoop-2.2.0 (传 hadoop-2.2.0.tar.gz)

    配置hadoop 2.1 上传hadoop包 2.2 解压hadoop包 首先在根目录下创建一个cloud目录 mkdir /cloud tar -zxvf hadoop-2.2.0.tar.gz - ...

  5. 为什么你不应该用angularjs?

    AngularJS的问题 为什么你不该用angularjs,https://medium.com/@mnemon1ck/why-you-should-not-use-angularjs-1df5ddf ...

  6. Bzoj1189 [HNOI2007]紧急疏散evacuate

    1189: [HNOI2007]紧急疏散evacuate Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2293  Solved: 715 Descr ...

  7. 记一次rsync增量同步远程服务器文件

    rsync remote shell 增量方式同步数据 rsync同步文件有两种方式,一种是daemon的方式(rsync daemon)另一种方式是通过远程shell方式(rsync remote ...

  8. xml小记1

    xml小记1 关于边框的实现 这是一个比较简单的东西,但是今天莫名的低效率,在这上面花了比较多的时间.之前有咨询过同学如何实现单向的边框,他们采用的方法是调用别人的接口. 我采用的方法如下: < ...

  9. 给linux添加yum源。

    在玩linux的过程中,经常会下载一些源码包.软件大多是国外人写的,由于众所周知的原因,网络下载很慢. 所以想到了更新yum源的方法. 我的linux版本是CentOS6.3的. 以下参考百度. 1, ...

  10. JavaWeb学习总结-07 Filter 学习和使用

    一 Filter简介 Filter也称之为过滤器,它是Servlet技术中最激动人心的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态 ...