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 update && select
 
CREATE TABLE `testupdate` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `val` bigint(20) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
 
update testupdate
 
set val = val+1
 
where id = 1 and @value := val+1;
 
select @value;

时间: 2025-01-23 07:48:11

mysql SELECT FOR UPDATE 语句用法详解的相关文章

mysql中TRUNCATE TABLE 语句用法详解

TRUNCATE TABLE删除表中的所有行,而不记录单个行删除操作. 语法    TRUNCATE TABLE name; 参数    name(是要截断的表的名称或要删除其全部行的表的名称) TRUNCATE TABLE 在功能上与不带 WHERE 子句的 DELETE 语句相同:二者均删除表中的全部行.但 TRUNCATE TABLE 比 DELETE 速度快,且使用的系统和事务日志资源少. DELETE 语句每次删除一行,并在事务日志中为所删除的每行记录一项.TRUNCATE TABLE

MySQL中Update与Insert语句用法详解

MySQL 更新数据 Update 语句 update 语句的定义: UPDATE语法可以用新值更新原有表行中的各列.让我们先来看一下update语句标准的定义,放在[]内的都是可以省略的:  代码如下 复制代码 UPDATE [LOW_PRIORITY] [IGNORE] tbl_name SET col_name1=expr1 [, col_name2=expr2 ...] [WHERE where_definition] [ORDER BY ...] [LIMIT row_count] s

MySQL中BETWEEN子句的用法详解_Mysql

可以使用IN子句来代替相结合的"大于等于和小于等于"的条件. 要了解BETWEEN 子句考虑的EMPLOYEE_TBL表有以下记录: mysql> SELECT * FROM employee_tbl; +------+------+------------+--------------------+ | id | name | work_date | daily_typing_pages | +------+------+------------+---------------

mysql SELECT FOR UPDATE语句使用示例_Mysql

以MySQL 的InnoDB 为例,预设的Tansaction isolation level 为REPEATABLE READ,在SELECT 的读取锁定主要分为两种方式:SELECT ... LOCK IN SHARE MODE SELECT ... FOR UPDATE这两种方式在事务(Transaction) 进行当中SELECT 到同一个数据表时,都必须等待其它事务数据被提交(Commit)后才会执行.而主要的不同在于LOCK IN SHARE MODE 在有一方事务要Update 同

MySQL触发器的用途和用法详解介绍

触发器是一种特殊的存储过程,它在插入,删除或修改特定表中的数据时触发执行,它比数据库本身标准的功能有更精细和更复杂的数据控制能力.触发器的作用: 1. 安全性.可以基于数据库的值使用户具有操作数据库的某种权利: 可以基于时间限制用户的操作,例如不允许下班后和节假日修改数据库数据: 可以基于数据库中的数据限制用户的操作,例如不允许股票的价格的升幅一次超过10%. 2. 审计.可以跟踪用户对数据库的操作: 审计用户操作数据库的语句: 把用户对数据库的更新写入审计表. 3. 实现复杂的数据完整性规则:

MySQL · 性能优化 · SQL错误用法详解

前言 MySQL在2016年仍然保持强劲的数据库流行度增长趋势.越来越多的客户将自己的应用建立在MySQL数据库之上,甚至是从Oracle迁移到MySQL上来.但也存在部分客户在使用MySQL数据库的过程中遇到一些比如响应时间慢,CPU打满等情况.阿里云RDS专家服务团队帮助云上客户解决过很多紧急问题.现将<ApsaraDB专家诊断报告>中出现的部分常见SQL问题总结如下,供大家参考. 常见SQL错误用法 1. LIMIT 语句 分页查询是最常用的场景之一,但也通常也是最容易出问题的地方.比如

mysql SELECT查询的速度优化详解

总的来说,要想使一个较慢速select ... where更快,应首先检查是否能增加一个索引.不同表之间的引用通常通过索引来完成.你可以使用explain语句来确定select语句使用哪些索引.参见7.4.5节,"mysql教程如何使用索引"和7.2.1节,"explain语法(获取关于select的信息)". 下面是一些加速对myisam表的查询的一般建议: ·         为了帮助mysql更好地优化查询,在一个装载数据后的表上运行analyze table

Sqlite3中replace语句用法详解

  由于自己的孤陋寡闻, 也由于之前的项目中, 很少参与过数据库模块的开发, 以至于前几天才知道Sqlite数据库也支持replace语句. 本文主要讲解在Sqlite中replace语句的行为,也算是学习笔记.此外, replace语句和update语句有相似的地方, 但是也有很多不同之处. 本文还要对比一下Sqlite中的 replace语句和update语句 . 在本例中使用如下数据库表: (图 1) 该表的表名为student, 存储学生信息. 所有字段的数据类型都是TEXT . 其中i

mysql双向加密解密方式用法详解_Mysql

如果你使用的正是mysql数据库,那么你把密码或者其他敏感重要信息保存在应用程序里的机会就很大.保护这些数据免受黑客或者窥探者的获取是一个令人关注的重要问题,因为您既不能让未经授权的人员使用或者破坏应用程序,同时还要保证您的竞争优势.幸运的是,MySQL带有很多设计用来提供这 种类型安全的加密函数.本文概述了其中的一些函数,并说明了如何使用它们,以及它们能够提供的不同级别的安全. 双向加密 就让我们从最简单的加密开始:双向加密.在这里,一段数据通过一个密钥被加密,只能够由知道这个密钥的人来解密.