fix:登录错误尝试修改
This commit is contained in:
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;
|
||||
|
||||
-- 本脚本没有安装唯一约束;防止新增重复仍需后端修复及独立的唯一索引迁移。
|
||||
-- 如需撤销,先核对备份与后续变更。唯一索引安装后,不可直接恢复成两条有效记录。
|
||||
Reference in new issue
Block a user