MySQL 如何在一个语句中更新一个数值后返回该值 -- 自增长种子竞态问题处理
什么是竞态问题?
假设有一个计数器,首先当前值自增长,然后获取到自增长之后的当前值。自增长后的值有可能被有些操作用来当做唯一性标识,因此并发的操作不能允许取得相同的值。
为什么不能使用使用UPDATE语句更新计数器,然后SELECT语句获取自增长后的当前值?问题在于并发的操作有可能获取到相同的计数器值。
CREATE TABLE counters
(
id INT NOT NULL UNIQUE, -- 计数器ID,多个计数器可以存在一个表中,
value INT -- 计数器当前值
); -- 初始化计数器1,从10开始计数
INSERT INTO counters VALUES (1, 10); -- 计数器1自增步长1
UPDATE counters SET value = value + 1 WHERE id = 1; -- 获取计数器1自增长后的当前值
SELECT value FROM counters WHERE id = 1;
如何避免竞态问题?
方法一:使用Transaction和SELECT FOR UPDATE
如果一个Transaction中执行SELECT FOR UPDATE,该步操作会锁住该行记录。其它对该行记录的并发操作会被阻塞,直到当前SELECT FOR UPDATE所在Transaction提交或超时。
START TRANSACTION; -- 锁定计数器1
SELECT value FROM counters WHERE id = 1 FOR UPDATE; -- 计数器1自增长步长1
UPDATE counters SET value = value + 1 WHERE id = 1; -- 获取自增长后的当前值
SELECT value FROM counters WHERE id = 1; COMMIT;
方法二:在一个语句中完成UPDATE和SELECT
方案一虽然可行并且可靠,但是加上了锁后一定程度上可能会影响一些性能。幸运的是我们可以使用方案二,在一个语句中完成UPDATE和SELECT,可以有两种方法实现。
实现1:通过Session变量。
-- 计数器1当前值自增长步长1
UPDATE counters
SET value = (@newValue := value + 1)
WHERE id = 1; -- 获取自增长之后的值
SELECT @newValue;
实现2:通过MySQL自带的LAST_INSERT_ID方法
LAST_INSERT_ID方法常用的场景是获取自增长列最后一次插入的值。它还有另外一个用法,当传入一个值时它会返回传入的值,并且在下一次调用不含参数的LAST_INSERT_ID()方法时,还是会返回先前传入的值。
-- 计数器1自增长步长1,并通过LAST_INSERT_ID(Num)方法记录插入的值
UPDATE counters
SET value = LAST_INSERT_ID(value + 1)
WHERE id = 1; -- 获取最后一次插入的值 (自增长之后的当前值)
SELECT LAST_INSERT_ID();
MySQL 如何在一个语句中更新一个数值后返回该值 -- 自增长种子竞态问题处理的更多相关文章
- MySql的like语句中的通配符:百分号、下划线和escape
MySql的like语句中的通配符:百分号.下划线和escape %:表示任意个或多个字符.可匹配任意类型和长度的字符. Sql代码 select * from user where user ...
- MySql的like语句中的通配符:百分号、下划线和escape 的使用
MySql的like语句中的通配符:百分号.下划线和escape %代表任意多个字符 select * from user where username like '%huxiao'; select ...
- 在开发中进入一个方法后想要到原来那行 ctrl+alt+左 回到上一步 ctrl+alt+右 回到下一步
在开发中进入一个方法后想要到原来那行 ctrl+alt+左 回到上一步ctrl+alt+右 回到下一步
- mysql中查询语句中的一个知识点说明
1, 简单说明. select * from tb_name where 1[不为零即可];则会显示所有记录,select * from tb_name where 0;则不显示任何记录 假设数据库中 ...
- mysql实例---sql语句中使用@变量
本文介绍下,在mysql语句中使用@变量的一个例子,学习下这个特殊变量的用法,有需要的朋友参考下吧. 要求: 计算用户距上次访问的天数,根据imei号区分不同的用户,如果时间段内只有一次访问则为0. ...
- MySQL在windows系统中修改datadir路径后无法启动问题,报错1067
windows server2008下如何更改MySQL数据库的目录的帖子已经很多了,这里简单介绍一个步骤,如果不成功请先查看其它帖子. 更改默认的mysql数据库目录 将 C:\Documents ...
- 网易笔试题:浏览器中输入一个url后回车到返回页面信息的过程
You enter a URL into the browser输入一个url地址 The browser looks up the IP address for the domain name浏览器 ...
- 在浏览器中输入一个URL后都发生了什么
这道题目没有所谓的完全的正确答案,这个题目可以让你在任意的一个点深入下去, 只要你对这个点是熟悉的.以下是一个大概流程: 浏览器向DNS服务器查找输入URL对应的IP地址. DNS服务器返回网站的IP ...
- 解释一下,在你往浏览器中输入一个URL后都发生了什么,要尽可能详细
这道题目没有所谓的完全的正确答案,这个题目可以让你在任意的一个点深入下去, 只要你对这个点是熟悉的.以下是一个大概流程: 浏览器向DNS服务器查找输入URL对应的IP地址. DNS服务器返回网站的IP ...
随机推荐
- kettle每天自动发送邮件总结_20161128
kettle作为java开发的工具,很多功能在目前工作中还用不到,原来它也是支持java代码的,现在用到的也就是它从服务器导数到数据库,然后再进行数据处理的功能. 如何快速学会使用kettle发送邮件 ...
- 使用外网控制你的STM32单片机
转自:http://blog.csdn.net/xdxlove/article/details/50837459 本文章假设读者已经在STM32单片机上成功移植LWIP,且已经实现在局域网内控制STM ...
- 怎么在docker容器的mysql的编码格式变为utf8
第一个方法: 1. 编辑MySql的配置文件 MySql的配置文件Windows下一般在系统目录下或者在MySql的安装目录下名字叫my.ini,可以搜索,Linux下一般是/etc/my.cnf ...
- 同时安装Python2与Python3,安装第三方包,老是报错
同时安装Python2与Python3,安装第三方包,老是报错提示Fatal error in launcher: Unable to create process using '"',那可 ...
- java去任意范围的随机数
一.java.uitl.Randomrandom.nextInt(20),任意取[0,20)之间整数,其中0可以取到,20取不到 二.取某个范围的任意数public static String get ...
- MSSQl分布式查询(转)
MSSQlServer所谓的分布式查询(Distributed Query)是能够访问存放在同一部计算机或不同计算机上的SQL Server或不同种类的数据源, 从概念上来说分布式查询与普通查询区别 ...
- Robot Framework基础学习(六)
网页弹窗 参考:http://blog.csdn.net/Allan_shore_ma/article/details/65629246 常见的网页弹窗,有如下几类: alert ajax ifram ...
- 《Java多线程编程核心技术》读后感(二)
方法内的变量为线程安全 package Second; public class HasSelfPrivateNum { public void addI(String username) { try ...
- shell程序---编译目录下全部.c或.cpp文件
今天大波又提起昨天我说的那个程序.这样的,起初我想写一个makefile,每次写完新代码后一键编译目录下所有的.cpp文件. 原因是用makefile的话,每次要把目标文件加紧去才能编译.感觉不方便. ...
- sqlserver2012——EXISTS关键字
1.返回TRUE或者FALSE 如果exists查询存在,则能查询出来 select a.* From 成绩信息 a ’) 2.判断用户登录 ) ) ' set @pwd='xxxxxxx' if e ...