mysql默认事务下乐观锁解决方案

一、sql语句

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for student
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL DEFAULT '',
  `subject` varchar(20) NOT NULL COMMENT '科目',
  `score` int(11) NOT NULL DEFAULT '0' COMMENT '分数',
  `version` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `unique_key` (`name`,`subject`) USING BTREE COMMENT '唯一索引'
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of student
-- ----------------------------
BEGIN;
INSERT INTO `student` VALUES (1, '阿飞', '语文', 99, 0);
INSERT INTO `student` VALUES (2, '阿飞', '数学', 98, 0);
INSERT INTO `student` VALUES (3, '阿飞', '英语', 79, 0);
INSERT INTO `student` VALUES (4, '雪梨', '语文', 89, 1);
INSERT INTO `student` VALUES (5, '雪梨', '数学', 78, 0);
INSERT INTO `student` VALUES (6, '雪梨', '英语', 67, 0);
INSERT INTO `student` VALUES (7, '小月', '语文', 100, 2);
INSERT INTO `student` VALUES (8, '小月', '数学', 99, 0);
INSERT INTO `student` VALUES (9, '小月', '英语', 98, 0);
COMMIT;

SET FOREIGN_KEY_CHECKS = 1;

二、问题及解决方案:

1、mysql的事务默认隔离级别为可重复读(repeatable-read):

1、 一个事务读取到另一个事务提交前后的数据保持不变
2、 如果两个事务对同一条数据做修改,都未提交时候,晚修改的会阻塞住,直到早提交的事务commit或rollback了才能继续执行

2、模拟程序:高并发下可能出问题的事务语句

BEGIN;
# 一个事务中查询的数据有可能在执行update的时候已经被别的事务修改并提交了,
# 所以这时候如果执行更新语句(更新内容依赖查询结果的数据)会出现非预期错误;
# 如下语句;
SELECT s.score FROM student s  WHERE s.`name` = '阿飞' and s.`subject` = '数学';
# 下面语句中score是从查询语句获取,此时的score有可能是错误的数据,已经被之前的事务所修改了
# 比如 开始查询的score是100,然后另一个事务修改成了99并提交,此时再执行update拿的score依然是100,然后修改成了99
# 实际上预期的值应该是98
UPDATE student s SET s.score = s.score-1 WHERE s.`name` = '阿飞' and s.`subject` = '数学';
# 此时提交不是预期结果
commit;

# 解决办法:乐观锁思想(版本号控制,即数据库加上版本号version字段)
BEGIN;
# 每次查询的时候都查出版本号version; 
SELECT s.score,s.`version` FROM student s  WHERE s.`name` = '阿飞' and s.`subject` = '数学';
# 程序中score是从查询语句获取,更新的时候条件带上版本号
UPDATE student s SET s.score = s.score-1 , s.`version`= s.`version`+1  
WHERE s.`name` = '阿飞' and s.`subject` = '数学' and s.`version` = 0;
# 有可能更新失败,因为版本号已经升级,不会出现错误结果
commit;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值