-- SW → Kra 自动升级后的旧表清理,兼容 MySQL 5.7。 -- 程序会自动调用本脚本;手工执行仅用于预览或恢复已到清理阶段的升级。 -- 自动流程已完成私有备份、结构/索引及业务角色校验后,才允许进入删除阶段。 -- 使用独立 MySQL 会话完整执行本文件;客户端需支持 DELIMITER,遇错停止,不使用 --force。 -- 默认仅预览。确认输出名单和目标库后,将下方 0 改为 1,再完整执行。 -- DROP TABLE 隐式提交,不能用 ROLLBACK 恢复;中途失败可在排除原因后重跑。 -- 删除名单为明确表名,绝不按 legacy_、bak_、sj_ 等前缀批量匹配。 -- 保留业务表、sys_schema_migrations 和 sys_business_upgrade_state;旧映射与核验明细已自动归档。 USE `sw10`; SET @sw_cleanup_execute = 0; SET NAMES utf8mb4; DELIMITER $$ DROP PROCEDURE IF EXISTS sw_kra_cleanup_20261106$$ CREATE PROCEDURE sw_kra_cleanup_20261106() cleanup_run: BEGIN DECLARE v_db VARCHAR(64); DECLARE v_lock_name VARCHAR(64); DECLARE v_locked INT DEFAULT 0; DECLARE v_prepared INT DEFAULT 0; DECLARE v_timeout_changed INT DEFAULT 0; DECLARE v_old_lock_wait BIGINT UNSIGNED; DECLARE v_name VARCHAR(64); DECLARE v_last VARCHAR(64) DEFAULT ''; DECLARE v_message VARCHAR(128); DECLARE v_present INT DEFAULT 0; DECLARE v_dropped INT DEFAULT 0; DECLARE v_started DATETIME(6); DECLARE v_step_started DATETIME(6); DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN IF v_prepared=1 THEN DEALLOCATE PREPARE sw_cleanup_drop; END IF; IF v_timeout_changed=1 THEN SET SESSION lock_wait_timeout=v_old_lock_wait; END IF; DROP TEMPORARY TABLE IF EXISTS _sw_cleanup_targets_20261106; DROP TEMPORARY TABLE IF EXISTS _sw_cleanup_required_tables_20261106; DROP TEMPORARY TABLE IF EXISTS _sw_cleanup_required_versions_20261106; IF v_locked=1 THEN DO RELEASE_LOCK(v_lock_name); END IF; RESIGNAL; END; SET v_started=SYSDATE(6), v_db=DATABASE(); IF v_db IS NULL OR LOWER(v_db) IN ('oa','game_lx','game_hw','game_yq','mysql','sys','information_schema','performance_schema') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Refusing cleanup of source/platform/system database'; END IF; IF @sw_cleanup_execute IS NULL OR @sw_cleanup_execute NOT IN (0,1) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='sw_cleanup_execute must be 0 (preview) or 1 (delete)'; END IF; IF @@SESSION.foreign_key_checks<>1 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Enable foreign_key_checks before cleanup'; END IF; -- 与旧框架转换和 -migrate 使用同一把库级锁。 SET v_lock_name=CONCAT('sw_to_kra:',MD5(v_db)); SELECT GET_LOCK(v_lock_name,0) INTO v_locked; IF COALESCE(v_locked,0)<>1 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Migration/cleanup already running for this database'; END IF; CREATE TEMPORARY TABLE _sw_cleanup_targets_20261106 ( table_name VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin PRIMARY KEY, category VARCHAR(80) NOT NULL ); INSERT INTO _sw_cleanup_targets_20261106(table_name,category) VALUES ('legacy_sw_20261103_sys_client','旧框架归档'), ('legacy_sw_20261103_sys_config','旧框架归档'), ('legacy_sw_20261103_sys_dept','旧框架归档'), ('legacy_sw_20261103_sys_dict_data','旧框架归档'), ('legacy_sw_20261103_sys_dict_type','旧框架归档'), ('legacy_sw_20261103_sys_login_info','旧框架归档'), ('legacy_sw_20261103_sys_menu','旧框架归档'), ('legacy_sw_20261103_sys_notice','旧框架归档'), ('legacy_sw_20261103_sys_oper_log','旧框架归档'), ('legacy_sw_20261103_sys_oss','旧框架归档'), ('legacy_sw_20261103_sys_oss_config','旧框架归档'), ('legacy_sw_20261103_sys_post','旧框架归档'), ('legacy_sw_20261103_sys_role','旧框架归档'), ('legacy_sw_20261103_sys_role_dept','旧框架归档'), ('legacy_sw_20261103_sys_role_menu','旧框架归档'), ('legacy_sw_20261103_sys_social','旧框架归档'), ('legacy_sw_20261103_sys_user','旧框架归档'), ('legacy_sw_20261103_sys_user_post','旧框架归档'), ('legacy_sw_20261103_sys_user_role','旧框架归档'), ('bak_sw2kra_20261103_sj_job','迁移前备份'), ('bak_sw2kra_20261103_sys_alert_operation_log','迁移前备份'), ('bak_sw2kra_20261103_sys_alert_record','迁移前备份'), ('bak_sw2kra_20261103_sys_alert_rule','迁移前备份'), ('bak_sw2kra_20261103_sys_client','迁移前备份'), ('bak_sw2kra_20261103_sys_config','迁移前备份'), ('bak_sw2kra_20261103_sys_dept','迁移前备份'), ('bak_sw2kra_20261103_sys_dict_data','迁移前备份'), ('bak_sw2kra_20261103_sys_dict_type','迁移前备份'), ('bak_sw2kra_20261103_sys_login_info','迁移前备份'), ('bak_sw2kra_20261103_sys_menu','迁移前备份'), ('bak_sw2kra_20261103_sys_message','迁移前备份'), ('bak_sw2kra_20261103_sys_notice','迁移前备份'), ('bak_sw2kra_20261103_sys_oper_log','迁移前备份'), ('bak_sw2kra_20261103_sys_oss','迁移前备份'), ('bak_sw2kra_20261103_sys_oss_config','迁移前备份'), ('bak_sw2kra_20261103_sys_post','迁移前备份'), ('bak_sw2kra_20261103_sys_role','迁移前备份'), ('bak_sw2kra_20261103_sys_role_dept','迁移前备份'), ('bak_sw2kra_20261103_sys_role_menu','迁移前备份'), ('bak_sw2kra_20261103_sys_social','迁移前备份'), ('bak_sw2kra_20261103_sys_user','迁移前备份'), ('bak_sw2kra_20261103_sys_user_bind_platform','迁移前备份'), ('bak_sw2kra_20261103_sys_user_post','迁移前备份'), ('bak_sw2kra_20261103_sys_user_preference','迁移前备份'), ('bak_sw2kra_20261103_sys_user_role','迁移前备份'), ('sj_distributed_lock','旧 SnailJob 框架'), ('sj_group_config','旧 SnailJob 框架'), ('sj_job','旧 SnailJob 框架'), ('sj_job_executor','旧 SnailJob 框架'), ('sj_job_log_message','旧 SnailJob 框架'), ('sj_job_summary','旧 SnailJob 框架'), ('sj_job_task','旧 SnailJob 框架'), ('sj_job_task_batch','旧 SnailJob 框架'), ('sj_namespace','旧 SnailJob 框架'), ('sj_notify_config','旧 SnailJob 框架'), ('sj_notify_recipient','旧 SnailJob 框架'), ('sj_retry','旧 SnailJob 框架'), ('sj_retry_dead_letter','旧 SnailJob 框架'), ('sj_retry_scene_config','旧 SnailJob 框架'), ('sj_retry_summary','旧 SnailJob 框架'), ('sj_retry_task','旧 SnailJob 框架'), ('sj_retry_task_log_message','旧 SnailJob 框架'), ('sj_server_node','旧 SnailJob 框架'), ('sj_system_user','旧 SnailJob 框架'), ('sj_system_user_permission','旧 SnailJob 框架'), ('sj_workflow','旧 SnailJob 框架'), ('sj_workflow_node','旧 SnailJob 框架'), ('sj_workflow_task_batch','旧 SnailJob 框架'), ('gen_table','旧代码生成与演示'), ('gen_table_column','旧代码生成与演示'), ('test_demo','旧代码生成与演示'), ('test_tree','旧代码生成与演示'), ('sys_alert_dedup_bak_20261020_105142_128391_5084329','旧预警去重备份'), ('sys_alert_dedup_bak_20261020_111958_265207_5085137','旧预警去重备份'), ('sw_kra_api_contract','已归档的迁移辅助表'), ('sw_kra_checks','已归档的迁移辅助表'), ('sw_kra_id_map','已归档的迁移辅助表'), ('sw_kra_menu_permissions','已归档的迁移辅助表'), ('sw_kra_state','已归档的迁移辅助表') ; CREATE TEMPORARY TABLE _sw_cleanup_required_tables_20261106 ( table_name VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin PRIMARY KEY ); INSERT INTO _sw_cleanup_required_tables_20261106(table_name) VALUES ('casbin_rule'), ('jwt_blacklists'), ('media_attachment_category'), ('media_file_upload_and_downloads'), ('media_uploads'), ('media_upload_chunks'), ('pay_events'), ('pay_orders'), ('sys_alert_channel_lock'), ('sys_alert_exemption'), ('sys_alert_gap'), ('sys_alert_operation_log'), ('sys_alert_record'), ('sys_alert_rule'), ('sys_announcements'), ('sys_apis'), ('sys_api_tokens'), ('sys_authorities'), ('sys_authority_apis'), ('sys_authority_btns'), ('sys_authority_departments'), ('sys_authority_menus'), ('sys_base_menus'), ('sys_base_menu_btns'), ('sys_base_menu_parameters'), ('sys_business_alert_locks'), ('sys_business_binding_locks'), ('sys_business_channel_effectiveness'), ('sys_business_effectiveness_state'), ('sys_business_groups'), ('sys_business_group_members'), ('sys_business_group_state'), ('sys_business_member_profiles'), ('sys_business_password_codes'), ('sys_business_password_resets'), ('sys_business_performance_goals'), ('sys_business_report_build_locks'), ('sys_data_access_logs'), ('sys_departments'), ('sys_dictionaries'), ('sys_dictionary_details'), ('sys_error'), ('sys_export_templates'), ('sys_export_template_condition'), ('sys_export_template_join'), ('sys_ignore_apis'), ('sys_integration_configs'), ('sys_login_logs'), ('sys_message'), ('sys_operation_records'), ('sys_params'), ('sys_positions'), ('sys_schema_migrations'), ('sys_security_config'), ('sys_timed_tasks'), ('sys_timed_task_logs'), ('sys_users'), ('sys_user_authority'), ('sys_user_bind_platform'), ('sys_user_departments'), ('sys_user_positions'), ('sys_user_preference'), ('sys_versions'), ('tab_game'), ('tab_game_server'), ('tab_promote'), ('tab_promote_apply'), ('tab_spend'), ('tab_sw_report_day'), ('tab_sw_report_day_key'), ('tab_sw_report_server_day'), ('tab_sw_report_server_day_key'), ('tab_user'), ('tab_user_day_login'), ('tab_user_play_info'), ('sys_business_upgrade_state') ; CREATE TEMPORARY TABLE _sw_cleanup_required_versions_20261106 ( id VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin PRIMARY KEY ); INSERT INTO _sw_cleanup_required_versions_20261106(id) VALUES ('202608200001_data_infrastructure'), ('202608200002_system_schema'), ('202608200003_payment_schema'), ('202608200004_payment_defaults'), ('202608210001_communication_integration_defaults'), ('202608210002_communication_surface'), ('202608210003_communication_test_surface'), ('202608220001_task_schema'), ('202608290001_payment_event_schema'), ('202608290002_payment_admin_surface'), ('202608290003_payment_order_read_permissions'), ('202608290004_kafka_integration_default'), ('202608290005_communication_integration_default_upgrade'), ('202609290001_sms_admin_surface'), ('202611030001_business_preference'), ('202611030002_business_user_fields'), ('202611030003_business_bindings'), ('202611030004_business_binding_locks'), ('202611030005_business_password_reset'), ('202611030006_business_alert_schema'), ('202611030007_business_alert_attachments'), ('202611040008_business_report_build_locks'), ('202611040009_business_menu_icons'), ('202611040010_business_alert_trigger_locks'), ('202611040011_business_registration_index'), ('202611040012_business_server_report_index'), ('202611040013_business_query_indexes'), ('202611040014_business_report_build_indexes'), ('202611040015_business_approved_game_index'), ('202611040016_business_other_settings_surface'), ('202611040017_business_groups_goals_effectiveness'), ('202611040018_business_effectiveness_query_index'), ('202611040019_business_performance_surface'), ('202611050020_business_alert_v2'), ('202611050021_business_alert_surface'), ('202611060022_business_promote_id_capacity'), ('202611060023_business_binding_status_index'), ('202611060024_business_role_identity'), ('202611060024_business_oa_remark'), ('202611060025_business_activation_surface'), ('202611060025_automatic_upgrade_state') ; -- 缺任意必需表时,在执行第一条 DROP 前停止。 SET v_name=(SELECT MIN(r.table_name) FROM _sw_cleanup_required_tables_20261106 r WHERE NOT EXISTS (SELECT 1 FROM information_schema.tables t WHERE t.table_schema=v_db AND BINARY t.table_name=BINARY r.table_name AND t.table_type='BASE TABLE')); IF v_name IS NOT NULL THEN SET v_message=CONCAT('Required current table is missing: ',v_name); SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT=v_message; END IF; IF NOT EXISTS (SELECT 1 FROM sys_business_upgrade_state WHERE name='legacy-sw' AND version='20261106_automatic_v1' AND phase IN ('cleanup','complete') AND verified_at IS NOT NULL AND LENGTH(verified_migrations)=64 AND cleanup_backup_path<>'' AND LENGTH(cleanup_sha256)=64) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Automatic upgrade and backup verification must finish before cleanup'; END IF; -- 初次删除复核旧记录;中断后旧记录可能已删除,改由持久化的自动升级状态证明已校验。 IF EXISTS(SELECT 1 FROM information_schema.tables WHERE table_schema=v_db AND table_name='sw_kra_state') AND EXISTS(SELECT 1 FROM information_schema.tables WHERE table_schema=v_db AND table_name='sw_kra_checks') THEN IF NOT EXISTS (SELECT 1 FROM sw_kra_state WHERE id=1 AND version='20261103_framework_migration_v5' AND phase='completed' AND completed_at IS NOT NULL) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Legacy framework migration has not completed'; END IF; IF (SELECT COUNT(DISTINCT check_name) FROM sw_kra_checks WHERE stage='backup')<>52 OR (SELECT COUNT(DISTINCT check_name) FROM sw_kra_checks WHERE stage='migration')<>24 OR EXISTS (SELECT 1 FROM sw_kra_checks WHERE passed<>1 OR expected_value IS NULL OR actual_value IS NULL OR expected_value<>actual_value) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Migration verification records are incomplete or failed'; END IF; END IF; IF (SELECT COUNT(*) FROM sys_authorities WHERE deleted_at IS NULL AND business_level BETWEEN 1 AND 3 AND authority_id<>888)<>3 OR (SELECT COUNT(DISTINCT business_level) FROM sys_authorities WHERE deleted_at IS NULL AND business_level BETWEEN 1 AND 3 AND authority_id<>888)<>3 OR EXISTS(SELECT 1 FROM sys_authorities WHERE business_level IS NOT NULL AND (business_level NOT BETWEEN 1 AND 3 OR authority_id=888)) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Stable business role bindings are incomplete'; END IF; IF (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema=v_db AND table_name='sys_authorities' AND index_name='uk_authority_business_level')<>1 OR NOT EXISTS(SELECT 1 FROM information_schema.statistics WHERE table_schema=v_db AND table_name='sys_authorities' AND index_name='uk_authority_business_level' AND column_name='business_level' AND seq_in_index=1 AND non_unique=0 AND sub_part IS NULL) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Business role unique index is missing or incompatible'; END IF; IF EXISTS (SELECT 1 FROM _sw_cleanup_required_versions_20261106 r WHERE NOT EXISTS (SELECT 1 FROM sys_schema_migrations m WHERE BINARY m.id=BINARY r.id)) THEN SELECT r.id AS missing_migration FROM _sw_cleanup_required_versions_20261106 r WHERE NOT EXISTS (SELECT 1 FROM sys_schema_migrations m WHERE BINARY m.id=BINARY r.id) ORDER BY r.id; SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Run all incremental migrations before cleanup'; END IF; -- 不能仅凭手工填写 completed 状态删除尚未归档的旧框架。 IF EXISTS (SELECT 1 FROM information_schema.tables t WHERE t.table_schema=v_db AND t.table_name IN ( 'sys_social','sys_dept','sys_user','sys_post','sys_role','sys_menu','sys_user_role','sys_role_menu', 'sys_role_dept','sys_user_post','sys_oper_log','sys_dict_type','sys_dict_data','sys_config', 'sys_login_info','sys_notice','sys_oss','sys_oss_config','sys_client')) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Unarchived legacy framework tables remain; cleanup stopped'; END IF; IF EXISTS (SELECT 1 FROM information_schema.tables t JOIN _sw_cleanup_targets_20261106 c ON BINARY c.table_name=BINARY t.table_name WHERE t.table_schema=v_db AND t.table_type<>'BASE TABLE') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='A cleanup target is not a base table'; END IF; -- 保留外键检查;任何引用(包括其他库)都需先处理,避免删除一半才遇到约束。 IF EXISTS (SELECT 1 FROM information_schema.key_column_usage k JOIN _sw_cleanup_targets_20261106 c ON BINARY k.referenced_table_name=BINARY c.table_name WHERE k.referenced_table_schema=v_db) THEN SELECT DISTINCT k.table_schema,k.table_name,k.constraint_name,k.referenced_table_name FROM information_schema.key_column_usage k JOIN _sw_cleanup_targets_20261106 c ON BINARY k.referenced_table_name=BINARY c.table_name WHERE k.referenced_table_schema=v_db; SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Foreign keys reference cleanup targets'; END IF; -- 检查当前库的视图、触发器、事件和存储程序;定义不可见时也停止。 IF EXISTS (SELECT 1 FROM information_schema.views v WHERE v.table_schema=v_db AND (v.view_definition IS NULL OR EXISTS (SELECT 1 FROM _sw_cleanup_targets_20261106 c WHERE LOWER(v.view_definition) REGEXP CONCAT('(^|[^0-9a-z_])',c.table_name,'([^0-9a-z_]|$)')))) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Review views referencing cleanup targets before deletion'; END IF; IF EXISTS (SELECT 1 FROM information_schema.triggers t WHERE t.trigger_schema=v_db AND (t.action_statement IS NULL OR EXISTS (SELECT 1 FROM _sw_cleanup_targets_20261106 c WHERE BINARY t.event_object_table=BINARY c.table_name OR LOWER(t.action_statement) REGEXP CONCAT('(^|[^0-9a-z_])',c.table_name,'([^0-9a-z_]|$)')))) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Review triggers referencing cleanup targets before deletion'; END IF; IF EXISTS (SELECT 1 FROM information_schema.events e WHERE e.event_schema=v_db AND (e.event_definition IS NULL OR EXISTS (SELECT 1 FROM _sw_cleanup_targets_20261106 c WHERE LOWER(e.event_definition) REGEXP CONCAT('(^|[^0-9a-z_])',c.table_name,'([^0-9a-z_]|$)')))) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Review events referencing cleanup targets before deletion'; END IF; IF EXISTS (SELECT 1 FROM information_schema.routines r WHERE r.routine_schema=v_db AND r.routine_name<>'sw_kra_cleanup_20261106' AND (r.routine_definition IS NULL OR EXISTS (SELECT 1 FROM _sw_cleanup_targets_20261106 c WHERE LOWER(r.routine_definition) REGEXP CONCAT('(^|[^0-9a-z_])',c.table_name,'([^0-9a-z_]|$)')))) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Review routines referencing cleanup targets before deletion'; END IF; SELECT COUNT(*) INTO v_present FROM information_schema.tables t JOIN _sw_cleanup_targets_20261106 c ON BINARY t.table_name=BINARY c.table_name WHERE t.table_schema=v_db; SELECT v_db AS target_database,IF(@sw_cleanup_execute=0,'PREVIEW','DELETE') AS mode, v_present AS existing_target_tables; SELECT c.table_name,c.category,IF(t.table_name IS NULL,'already absent','to delete') AS status, t.table_rows AS estimated_rows,COALESCE(t.data_length,0)+COALESCE(t.index_length,0) AS estimated_bytes FROM _sw_cleanup_targets_20261106 c LEFT JOIN information_schema.tables t ON t.table_schema=v_db AND BINARY t.table_name=BINARY c.table_name ORDER BY c.category,c.table_name; IF @sw_cleanup_execute=1 THEN SET v_old_lock_wait=@@SESSION.lock_wait_timeout, v_timeout_changed=1; -- 只限制等待元数据锁的时间,避免遗留连接占表后一直卡住;实际删除不设总超时。 SET SESSION lock_wait_timeout=15; drop_loop: LOOP SET v_name=(SELECT MIN(table_name) FROM _sw_cleanup_targets_20261106 WHERE table_name>v_last); IF v_name IS NULL THEN LEAVE drop_loop; END IF; SET v_last=v_name; IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema=v_db AND BINARY table_name=BINARY v_name) THEN SET v_step_started=SYSDATE(6); SET @sw_cleanup_drop_sql=CONCAT('DROP TABLE IF EXISTS `',REPLACE(v_db,'`','``'),'`.`',REPLACE(v_name,'`','``'),'`'); PREPARE sw_cleanup_drop FROM @sw_cleanup_drop_sql; SET v_prepared=1; EXECUTE sw_cleanup_drop; DEALLOCATE PREPARE sw_cleanup_drop; SET v_prepared=0, v_dropped=v_dropped+1; SELECT v_name AS dropped_table,TIMESTAMPDIFF(MICROSECOND,v_step_started,SYSDATE(6))/1000 AS elapsed_ms; END IF; END LOOP; SET SESSION lock_wait_timeout=v_old_lock_wait; SET v_timeout_changed=0; END IF; DROP TEMPORARY TABLE _sw_cleanup_targets_20261106; DROP TEMPORARY TABLE _sw_cleanup_required_tables_20261106; DROP TEMPORARY TABLE _sw_cleanup_required_versions_20261106; DO RELEASE_LOCK(v_lock_name); SET v_locked=0, @sw_cleanup_drop_sql=NULL; SELECT IF(@sw_cleanup_execute=0,'Preview completed; no tables deleted','Cleanup completed') AS result, v_dropped AS dropped_tables,TIMESTAMPDIFF(MICROSECOND,v_started,SYSDATE(6))/1000 AS elapsed_ms; END cleanup_run$$ CALL sw_kra_cleanup_20261106()$$ DROP PROCEDURE sw_kra_cleanup_20261106$$ DELIMITER ;