fix:登录错误尝试修改

This commit is contained in:
dzc committed 2026-11-05 17:54:37 +08:00
1 parent f55561c98d
commit 4518856ccd
9 files changed
+381 -64

No files matched your search

@@ -0,0 +1,155 @@
-- 已核查数据的精确修复,兼容 MySQL 5.7 / 8.0。
-- 只读核查时间:2026-11-05 15:46:31(北京时间),数据库 chat_v1。
-- 当时仅一组重复:member_id=64,VIP(type=4),有效记录 id=210、211。
-- member_user.id=64 已逻辑删除;本脚本不修改、不恢复用户。
-- 保留210,仅逻辑删除211。不清理其他标签,不执行全库去重或 ALTER。
--
-- 使用方法:在 chat_v1 的独立会话中执行整份脚本(会话不可有未提交事务)。
-- 默认 @apply_tag_repair=0:锁定并核验后回滚,仅预演;不创建备份表。
-- 预演返回 PREVIEW_OK 后,把下行改成1,重新执行整份脚本才真正修复。
-- 正式修复自动备份两行;字段/数量/用户状态变化,或备份已存在,均报错回滚。
-- 请在低流量时执行,并暂停该用户的标签编辑,避免长时间锁等待。
-- 正式执行失败可能留下空备份表,须人工核查;脚本不会复用或覆盖任何同名表。
SET NAMES utf8mb4;
SET @apply_tag_repair = 0;
DELIMITER $$
DROP PROCEDURE IF EXISTS codex_repair_member_tag_211_20261105$$
CREATE PROCEDURE codex_repair_member_tag_211_20261105(IN p_apply TINYINT)
BEGIN
DECLARE v_count INT DEFAULT 0;
DECLARE v_active_count INT DEFAULT 0;
DECLARE v_changed INT DEFAULT 0;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
RESIGNAL;
END;
IF DATABASE() <> 'chat_v1' OR DATABASE() IS NULL THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Wrong database: expected chat_v1';
END IF;
IF p_apply IS NULL OR p_apply NOT IN (0, 1) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'p_apply must be 0 (preview) or 1 (apply)';
END IF;
SELECT COUNT(*) INTO v_count
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME IN ('member_user', 'member_recent_tag') AND ENGINE = 'InnoDB';
IF v_count <> 2 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Both business tables must use InnoDB';
END IF;
-- DDL必须放在修复事务之前。仅创建独立备份表,不改业务表结构。
-- 明确列定义,避免复制业务表未来的生成列/唯一索引而妨碍备份重复记录。
IF p_apply = 1 THEN
CREATE TABLE member_recent_tag_backup_20261105_64 (
id BIGINT NOT NULL,
member_id BIGINT NOT NULL,
tag_title VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
tag_biz_id BIGINT NULL,
tag_biz_type CHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL,
creator VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL,
create_time DATETIME NOT NULL,
updater VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL,
update_time DATETIME NOT NULL,
deleted BIT(1) NOT NULL,
tenant_id BIGINT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB COMMENT='20261105用户64重复VIP标签修复前原始记录';
END IF;
-- 显式使用RR范围锁,避免会话处于READ COMMITTED时漏锁新插入的第三条记录。
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
-- 当前读并锁住用户及该组标签。无相关索引时可能锁住较多行,应整段及时执行。
SELECT id, deleted + 0 AS user_deleted
FROM member_user WHERE id = 64 FOR UPDATE;
SELECT id, member_id, tag_biz_type, tag_title, tag_biz_id, tenant_id,
creator, create_time, updater, update_time, deleted + 0 AS deleted
FROM member_recent_tag
WHERE member_id = 64 AND tag_biz_type = '4'
ORDER BY id FOR UPDATE;
SELECT COUNT(*) INTO v_count
FROM member_user WHERE id = 64 AND deleted = b'1';
IF v_count <> 1 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'User state changed; inspect again';
END IF;
SELECT COUNT(*) INTO v_active_count
FROM member_recent_tag
WHERE member_id = 64 AND tag_biz_type = '4' AND deleted = b'0';
SELECT COUNT(*) INTO v_count
FROM member_recent_tag
WHERE id IN (210, 211)
AND member_id = 64
AND BINARY tag_biz_type = BINARY '4'
AND BINARY tag_title = BINARY 'VIP用户'
AND tag_biz_id IS NULL
AND tenant_id <=> 1
AND BINARY creator <=> BINARY '1'
AND BINARY updater <=> BINARY '1'
AND create_time = '2026-07-31 18:30:28'
AND update_time = '2026-07-31 18:30:28'
AND deleted = b'0';
IF v_active_count <> 2 OR v_count <> 2 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Tag snapshot changed or already repaired; inspect again';
END IF;
IF p_apply = 0 THEN
ROLLBACK;
SELECT 'PREVIEW_OK' AS result, 210 AS keep_tag_id, 211 AS delete_tag_id,
1 AS expected_changed_rows, 'No data changed' AS message;
ELSE
-- 不使用 IGNORE / REPLACE:备份冲突时必须停止,不能覆盖原备份。
INSERT INTO member_recent_tag_backup_20261105_64
(id, member_id, tag_title, tag_biz_id, tag_biz_type, creator,
create_time, updater, update_time, deleted, tenant_id)
SELECT id, member_id, tag_title, tag_biz_id, tag_biz_type, creator,
create_time, updater, update_time, deleted, tenant_id
FROM member_recent_tag WHERE id IN (210, 211);
SET v_count = ROW_COUNT();
IF v_count <> 2 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Backup must contain exactly two rows';
END IF;
UPDATE member_recent_tag
SET deleted = b'1', update_time = CURRENT_TIMESTAMP
WHERE id = 211 AND member_id = 64 AND tag_biz_type = '4' AND deleted = b'0';
SET v_changed = ROW_COUNT();
IF v_changed <> 1 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Repair must change exactly one row';
END IF;
SELECT COUNT(*) INTO v_count
FROM member_recent_tag
WHERE (id = 210 AND deleted = b'0') OR (id = 211 AND deleted = b'1');
SELECT COUNT(*) INTO v_active_count
FROM member_recent_tag
WHERE member_id = 64 AND tag_biz_type = '4' AND deleted = b'0';
IF v_count <> 2 OR v_active_count <> 1 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Post-repair validation failed';
END IF;
COMMIT;
SELECT 'REPAIRED' AS result, v_changed AS changed_rows,
'member_recent_tag_backup_20261105_64' AS backup_table;
END IF;
END$$
DELIMITER ;
CALL codex_repair_member_tag_211_20261105(@apply_tag_repair);
DROP PROCEDURE codex_repair_member_tag_211_20261105;
-- 全库复核:正式修复后预期0行。预演则仍返回原来的一组。
SELECT member_id, tag_biz_type, COUNT(*) AS active_count,
GROUP_CONCAT(id ORDER BY id) AS active_tag_ids
FROM member_recent_tag
WHERE deleted = b'0'
GROUP BY member_id, tag_biz_type
HAVING COUNT(*) > 1;
-- 本脚本没有安装唯一约束;防止新增重复仍需后端修复及独立的唯一索引迁移。
-- 如需撤销,先核对备份与后续变更。唯一索引安装后,不可直接恢复成两条有效记录。