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 ...
随机推荐
- ACM学习历程—NPU1086 随机数 2015年陕西省程序设计竞赛网络预赛(正式赛)C题 (计数排序 || set容器)
Description 开学了,ACM队的边老板想在学校中请一些妹子一起做一项问卷调查,调查妹子们对ACM的了解情况,为了实验的客观性,他先用计算机生成了N个1到1000之间的随机整数(N≤100), ...
- 洛谷 P4512 [模板] 多项式除法
题目:https://www.luogu.org/problemnew/show/P4512 看博客:https://www.cnblogs.com/owenyu/p/6724611.html htt ...
- maven学习九 关于maven一些參數
一 maven profile: 不同的运行环境,比如开发环境.测试环境.生产环境,而我们的软件在不同的环境中,有的配置可能会不一样,比如数据源配置.日志文件配置.以及一些软件运行过程中的基 ...
- 关于System类中out属性 实例化的问题
System类中out属性的声明是这样的: public final static PrintStream out = nullPrintStream(); private static PrintS ...
- [bzoj2440]完全平方数(二分+mobius反演)
解题关键:由容斥原理得,num=1的倍数的数量−一个质数平方数(9,25,49...)的倍数的数量+两个质数的积平方数(36,100,225...)的数量−三个质数...... 这道题用莫比乌斯的正向 ...
- 【机器学习】分类算法——Logistic回归
一.LR分类器(Logistic Regression Classifier) 在分类情形下,经过学习后的LR分类器是一组权值w0,w1, -, wn,当测试样本的数据输入时,这组权值与测试数据按照线 ...
- Javascript 获取客户端的运营商 IP 地址 等
客户端获取运营商 会弹出安全隐患问题,需要修改IE activx 选项, 非常麻烦,用我的代码可以轻松获取. <script src="JS/jquery-1.4.1.js" ...
- hdu 3853 LOOPS (概率dp 逆推求期望)
题目链接 LOOPS Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 125536/65536 K (Java/Others)Tota ...
- UNPIVOT逆透视以及动态逆透视存储过程
前几天一直练习PIVOT透视,还实现了动态透视的存过程<动态透视表>https://www.cnblogs.com/insus/p/10888277.html 今天练习MS SQL Ser ...
- 洛谷P1655 小朋友的球(Stirling数)
P1655 小朋友的球 题目描述 @发源于 小朋友最近特别喜欢球.有一天他脑子抽了,从口袋里拿出了N个不同的球,想把它们放到M个相同的盒子里,并且要求每个盒子中至少要有一个球,他好奇有几种放法,于是尝 ...