文档章节

SELECT ... FOR UPDATE

勇敢的蜗牛_Z
 勇敢的蜗牛_Z
发布于 2015/04/29 10:15
字数 918
阅读 179
收藏 10
点赞 0
评论 0

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 ,开二个视窗来做测试。


© 著作权归作者所有

共有 人打赏支持
勇敢的蜗牛_Z
粉丝 11
博文 49
码字总数 2531
作品 0
济南
程序员
MySQL SELECT ... FOR UPDATE

MySQL 使用SELECT ... FOR UPDATE 做事务写入前的确认 以MySQL 的InnoDB 为例,预设的Tansaction isolation level 为REPEATABLE READ,在SELECT 的读取锁定主要分为两种方式: SELECT ... LO...

克温s ⋅ 2016/05/03 ⋅ 0

MySQL 使用SELECT ... FOR UPDATE

MySQL 使用SELECT ... FOR UPDATE 做事务写入前的确认 以MySQL 的InnoDB 为例,预设的Tansaction isolation level 为REPEATABLE READ,在SELECT 的读取锁定主要分为两种方式: SELECT ... LO...

恶魔永生 ⋅ 2015/01/17 ⋅ 0

mysql事务、表锁、行锁

MySQL 使用SELECT ... FOR UPDATE 做事务写入前的确认 以MySQL 的InnoDB 为例,预设的Tansaction isolation level 为REPEATABLE READ,在SELECT 的读取锁定主要分为两种方式: SELECT ... LO...

块块 ⋅ 2014/03/27 ⋅ 1

oracle for update和for update nowait的区别

1、for update 和 for update nowait 的区别: 首先一点,如果只是select 的话,Oracle是不会加任何锁的,也就是Oracle对 select 读到的数据不会有任何限制,虽然这时候有可能另外一个进程正...

旺仔520 ⋅ 2014/07/24 ⋅ 0

mysql锁SELECT FOR UPDATE【转】

MySQL 使用SELECT ... FOR UPDATE 做事务写入前的确认 以MySQL 的InnoDB 为例,预设的Tansaction isolation level 为REPEATABLE READ,在SELECT 的读取锁定主要分为两种方式: 这两种方式在事...

无声胜有声 ⋅ 2016/10/21 ⋅ 0

oracle rownum分页 出现重复数据

通常一般的分页语句如下: select from ( select row_., rownum rownum from ( select p.id from table1 p order by p.DATAUPDATETIME desc ) row where rownum <= ?) b where b.rownum_ >......

神勇小白鼠 ⋅ 2013/07/12 ⋅ 0

关联表更新

我做了一下UPDATE关联表的思路总结,希望对不知道的同学有帮助! 我最近一直想研究一下UPDATE语句,尤其是多表关联UPDATE的时候,很容易出问题,于是我就在PUB上问,在资料上查,现在我终于弄明...

java-苦苦甜甜 ⋅ 2014/01/20 ⋅ 0

mysql 在一条语句中update和select同一张表

MySQL不允许SELECT FROM后面指向用作UPDATE的表,有时候让人纠结。本文解释如何UPDATE一张表,同时在查询子句中使用SELECT.问题描述假设我要UPDATE的表跟查询子句是同一张表,这样做有许多种...

张欢19933 ⋅ 2016/07/26 ⋅ 0

悲观锁总结和实践

最近学习了一下数据库的悲观锁和乐观锁,根据自己的理解和网上参考资料总结如下: 悲观锁介绍(百科): 悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系...

真爱2015 ⋅ 2016/01/07 ⋅ 0

mysql悲观锁总结和实践

最近学习了一下数据库的悲观锁和乐观锁,根据自己的理解和网上参考资料总结如下: 悲观锁介绍(百科): 悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系...

Carl_ ⋅ 2015/02/13 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Python模块/包/库安装(6种方法)

Python模块/包/库安装(6种方法) 冰颖机器人 2016-11-29 21:33:26 一、方法1: 单文件模块 直接把文件拷贝到 $python_dir/Lib 二、方法2: 多文件模块,带setup.py 下载模块包(压缩文件zip...

cswangyx ⋅ 33分钟前 ⋅ 0

零基础学习大数据人工智能,学习路线篇!系统规划大数据之路?

大数据处理技术怎么学习呢?首先我们要学习Python语言和Linux操作系统,这两个是学习大数据的基础,学习的顺序不分前后。 Python:Python 的排名从去年开始就借助人工智能持续上升,现在它已经...

董黎明 ⋅ 42分钟前 ⋅ 0

openJdk和sun jdk的区别

使用过LINUX的人都应该知道,在大多数LINUX发行版本里,内置或者通过软件源安装JDK的话,都是安装的OpenJDK, 那么到底什么是OpenJDK,它与SUN JDK有什么关系和区别呢? 历史上的原因是,Ope...

jason_kiss ⋅ 51分钟前 ⋅ 0

梳理

Redux 是 JavaScript 状态容器,提供可预测化的状态管理。 它是JS的状态容器,是一种解决问题的方式,所以即可以用于 react 也可以用于 vue。 需要理解其思想及实现方式。 应用中所有的 stat...

分秒 ⋅ 今天 ⋅ 0

Java 后台判断是否为ajax请求

/** * 是否是Ajax请求 * @param request * @return */public static boolean isAjax(ServletRequest request){return "XMLHttpRequest".equalsIgnoreCase(((HttpServletReques......

JavaSon712 ⋅ 今天 ⋅ 0

Redis 单线程 为何却需要事务处理并发问题

Redis是单线程处理,也就是命令会顺序执行。那么为什么会存在并发问题呢? 个人理解是,虽然redis是单线程,但是可以同时有多个客户端访问,每个客户端会有 一个线程。客户端访问之间存在竞争...

码代码的小司机 ⋅ 今天 ⋅ 0

到底会改名吗?微软GVFS 改名之争

微软去年透露了 Git Virtual File System(GVFS)项目,GVFS 是 Git 版本控制系统的一个开源插件,允许 Git 处理 TB 规模的代码库,比如 270 GB 的 Windows 代码库。该项目公布之初就引发了争...

linux-tao ⋅ 今天 ⋅ 0

笔试题之Java基础部分【简】【二】

1.静态变量和实例变量的区别 在语法定义上的区别:静态变量前要加static关键字,而实例变量前则不加。在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变...

anlve ⋅ 今天 ⋅ 0

Lombok简单介绍及使用

官网 通过简单注解来精简代码达到消除冗长代码的目的 优点 提高编程效率 使代码更简洁 消除冗长代码 避免修改字段名字时忘记修改方法名 4.idea中安装lombnok pom.xml引入 <dependency> <grou...

to_ln ⋅ 今天 ⋅ 0

【转】JS浮点数运算Bug的解决办法

37.5*5.5=206.08 (JS算出来是这样的一个结果,我四舍五入取两位小数) 我先怀疑是四舍五入的问题,就直接用JS算了一个结果为:206.08499999999998 怎么会这样,两个只有一位小数的数字相乘,怎...

NickSoki ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部