CREATE TABLE `a` ( `uid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '审核记录主表 guid', `approval_status` int(11) NULL DEFAULT 1 COMMENT '审核状态(1:审核中,2:通过)', `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键 id', PRIMARY KEY (`id`) USING BTREE, INDEX `idx_guid`(`uid`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 22 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '审核记录主表' ROW_FORMAT = Dynamic;
-- ---------------------------- -- Records of a -- ---------------------------- INSERT INTO `a` VALUES ('a1', 1, 1); INSERT INTO `a` VALUES ('a2', 1, 2);
CREATE TABLE `a_detail` ( `approval_status` int(11) NULL DEFAULT 1 COMMENT '审核状态(1:审核中;2:通过)', `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键 id', `auid` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE, INDEX `idx_aid`(`auid`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 74 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '审核记录明细表' ROW_FORMAT = Dynamic;
-- ---------------------------- -- Records of a_detail -- ---------------------------- INSERT INTO `a_detail` VALUES (1, 1, 'a1'); INSERT INTO `a_detail` VALUES (1, 2, 'a1'); INSERT INTO `a_detail` VALUES (1, 3, 'a2'); INSERT INTO `a_detail` VALUES (1, 4, 'a2');
会话一和 会话二 同时执行 SELECT @@GLOBAL.TX_ISOLATION;
begin;
-- 查询字表明细记录(这部如果去除整个流程正常)- SELECT * FROM a_detail WHERE id = 1
-- 根据索引利用行锁 锁定主表的记录-- SELECT * FROM `a` where uid='a1' for update;
-- 跟新字表状态为 2 审核通过-- UPDATE a_detail set approval_status = 2 WHERE id = 1 and approval_status = 1;
-- 查看子表是不是都已经审核通过了-- select count(0) from a_detail WHERE auid = 'a1' and approval_status!=2; -- 接下来如果 count(0) 数量是 0 代表所有子记录都通过,则去修改主表状态 update a set approval_status=2 where uid='a1' --
commit;
SELECT @@GLOBAL.TX_ISOLATION;
begin;
-- 查询字表明细记录(这部如果去除整个流程正常)- SELECT * FROM a_detail WHERE id = 2
-- 根据索引利用行锁 锁定主表的记录-- SELECT * FROM `a` where uid='a1' for update;
-- 跟新字表状态为 2 审核通过-- UPDATE a_detail set approval_status = 2 WHERE id = 2 and approval_status = 1;
-- 查看子表是不是都已经审核通过了-- select count(0) from a_detail WHERE auid = 'a1' and approval_status!=2; -- 接下来如果 count(0) 数量是 0 代表所有子记录都通过,则去修改主表状态 update a set approval_status=2 where uid='a1' --
UPDATE a_detail set approval_status = 2 WHERE id = 2 and approval_status = 1; UPDATE a set approval_status=(select count(0)==0 from a_detail WHERE auid = 'a1' and approval_status!=2) where uid='a1'
@rqxiao 难道是在事务开始时候的 select * from a_detail where id =这一句影响了后面的 count ?就算去掉开始的语句我也觉得会有幻读的问题的,两个事务里面的 count 应该都是快照读才对。
rqxiao
169 天前
@wengyanbin 并发时,每个会话开启事务,获取到行锁之后,进行一次快照读。只要能获取到行锁,说明上个事务已经提交了。所以并发情况下,达到了串行执行业务。获取到行锁一定能查询当前准确的数据。为什么说会有幻读? 目前来看 select * from a_detail where id =这一句是影响了后面的 count 。就算我替换成 select * from student a 。与本业务完全不相关的表查询,也会有问题。不是很理解为什么 碍于本人现在的认知水平,理解有可能也不是对的。