数据库同时更新问题

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介:

Netkiller MySQL 手札

MySQL MariaDB...

MrNeo Chan陈景峰(BG7NYT)


中国广东省深圳市龙华新区民治街道溪山美地
518131
+86 13113668890
+86 755 29812080

文档始创于2010-11-18

版权声明

转载请与作者联系,转载时请务必标明文章原始出处和作者信息及本声明。

文档出处:
http://netkiller.github.io
http://netkiller.sourceforge.net

 

$Date: 2013-04-10 15:03:49 +0800 (Wed, 10 Apr 2013) $

 

8.2.3. 解决更新冲突

CREATE TABLE `account` (
	`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
	`user` VARCHAR(50) NOT NULL DEFAULT '0',
	`cash` FLOAT NOT NULL DEFAULT '0',
	`point` INT(10) UNSIGNED NOT NULL DEFAULT '0',
	PRIMARY KEY (`id`),
	UNIQUE INDEX `user` (`user`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB;
		
INSERT INTO `test`.`account` (`user`, `cash`,`point`) VALUES ('neo', 10,10);
		

下面通过account表,我来模拟一个返点场景,例如电商网站经常会用到“返点”,购买一定数量的商品赠送一定的点数,可以通过点数买东西,这样涉及到点的加于减操作。

表 8.1. 更新丢失演示

Session A Session B
select point into @point from account where user='neo';
					
 
 
select point into @point from account where user='neo';
					
update account set point=@point+20 where user='neo';
					
 
 
update account set point=@point+50 where user='neo';
					

 

看看最后用户有多少点?

		
mysql> select point from account where user='neo';
+-------+
| point |
+-------+
|    30 |
+-------+
1 row in set (0.00 sec)
		
		

傻了吧,老板发火,测试不能重现,运维说这是程序计算错误,程序员说程序没有错误,这样的场景国内很多公司都出现过吧?

问题出在哪里呢?出在并发上,很多web程序员很少考虑并发是产生的问题,怎么解决?很多方案,在我的职业生涯过程就见过很多奇葩方案,都能解决问题但不太完美。

如果更新语句改为 update account set point=@point+50 where user='neo' and point=@point; 会更保险,但仍然不能解决同意时间所产生的更新操作

下面是通过事务与锁彻底解决上面的问题。

表 8.2. 防止更新丢失加锁演示

Session A Session B
begin;
select point into @point from account where user='neo' for update;
					
 
 
begin;
select point into @point from account where user='neo' for update;
					

执行到此处会挂起

update account set point=@point+20 where user='neo';
commit;
					
 
 
update account set point=@point+50 where user='neo';
commit;
					

 

上面解决更新覆盖问题,但从数据库设计角度是不应该这样设计表的。仅供参考

CREATE TABLE `account` (
	`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
	`user` VARCHAR(50) NOT NULL DEFAULT '0',
	`cash` FLOAT NOT NULL DEFAULT '0',
	`point` INT(10) NOT NULL DEFAULT '0',
	PRIMARY KEY (`id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB;
		

每一次数据变化新增一条数据

INSERT INTO `test`.`account` (`user`, `point`) VALUES ('neo', -10);
INSERT INTO `test`.`account` (`user`, `point`) VALUES ('neo', -5);
INSERT INTO `test`.`account` (`user`, `point`) VALUES ('neo', 30);
INSERT INTO `test`.`account` (`user`, `point`) VALUES ('neo', -20);
		

计算剩余点数

select sum(point) as point from account where user='neo';
相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
5月前
|
存储 SQL NoSQL
什么是数据库
【10月更文挑战第8天】
99 1
|
9月前
|
存储 关系型数据库 MySQL
系统数据库
【6月更文挑战第20天】系统数据库。
60 1
|
10月前
|
数据库
数据库(二)
数据查询教程包括单表查询操作,如Select语句用于选取属性,可指定列名、使用别名、计算表达式,并通过Distinct去除重复元组。条件查询(Where子句)支持比较运算,如Between、In、Like(支持模糊匹配)及空值判断。连接查询用于合并多表数据,如内连接、外连接和笛卡尔积。例如,通过连接emp和dept表,可获取员工姓名及其所在部门名称。
59 3
|
SQL 存储 NoSQL
数据库详解
数据库详解
84 0
|
SQL 数据库 Windows
数据库—耿建玲视频总结(二)
首先建库,就好比我们盖房子,我们可以自己盖(企业管理器建库),也可以包给别人让别人给盖(T语言建库)。
|
10月前
|
数据库
数据库视频(五)
数据库视频(五)
46 0
|
10月前
|
存储 SQL 关系型数据库
初识数据库
初识数据库
|
存储 SQL NoSQL
(一)数据库介绍
(一)数据库介绍
196 0
数据库—耿建玲视频总结(一)
基本上每一个材料开始都有其介绍发展史的,了解一下发展史可以培养我们一部分的兴趣,然后就是SQL server的安装介绍,这个在之前我们已经亲身实践了安装的过程,并且还为这安装问题苦恼过好久呢
|
存储 缓存 数据库连接
数据库写入操作及其优化
数据库写入操作是将数据从应用程序或用户输入插入到数据库中的过程。这包括向数据库中添加新的记录、更新已有记录或删除不再需要的记录。数据库写入操作对于保持数据的最新状态和一致性非常重要。
221 0