| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 |
- #!/usr/bin/env python3
- """
- 系统配置表迁移脚本
- 将横表改为纵表,并插入默认配置数据
- """
- import pymysql
- import os
- from pathlib import Path
- from dotenv import load_dotenv
- # 加载环境变量
- env_path = Path(__file__).parent / '.env'
- load_dotenv(dotenv_path=env_path)
- def get_db_connection():
- """获取数据库连接"""
- return pymysql.connect(
- host=os.getenv("DB_HOST", "localhost"),
- port=int(os.getenv("DB_PORT", "3306")),
- user=os.getenv("DB_USER", "root"),
- password=os.getenv("DB_PASSWORD", ""),
- database=os.getenv("DB_NAME", "buff"),
- charset='utf8mb4'
- )
- def migrate_system_config():
- """迁移system_config表"""
- print("开始迁移system_config表...")
- try:
- conn = get_db_connection()
- cursor = conn.cursor()
- # 1. 检查是否需要迁移(检查是否存在config_key字段)
- cursor.execute("SHOW COLUMNS FROM system_config LIKE 'config_key'")
- has_config_key = cursor.fetchone()
- if has_config_key:
- print("system_config表已经是纵表结构,跳过迁移")
- return
- # 2. 备份现有数据
- print("备份现有数据...")
- cursor.execute("SELECT * FROM system_config LIMIT 1")
- old_data = cursor.fetchone()
- if old_data:
- print(f"发现旧数据: {old_data}")
- else:
- print("没有找到旧数据,将创建新的纵表结构")
- # 3. 删除旧表结构
- print("删除旧表结构...")
- cursor.execute("DROP TABLE system_config")
- # 4. 创建新表结构
- print("创建新的纵表结构...")
- cursor.execute("""
- CREATE TABLE IF NOT EXISTS `system_config` (
- `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
- `config_key` varchar(100) NOT NULL COMMENT '配置键名',
- `config_value` varchar(500) NOT NULL COMMENT '配置值',
- `config_type` enum('int','string','bool','json') DEFAULT 'string' COMMENT '配置值类型',
- `description` varchar(255) DEFAULT NULL COMMENT '配置描述',
- `is_system` tinyint(1) DEFAULT '1' COMMENT '是否为系统配置:1-是,0-否',
- `is_editable` tinyint(1) DEFAULT '1' COMMENT '是否可编辑:1-是,0-否',
- `is_deleted` tinyint(1) DEFAULT '0' COMMENT '是否删除:0-否,1-是',
- `created_at` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
- `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
- PRIMARY KEY (`id`),
- UNIQUE KEY `uk_config_key` (`config_key`, `is_deleted`) COMMENT '配置键唯一约束'
- ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='系统配置表(纵表设计)'
- """)
- # 5. 插入默认配置数据
- print("插入默认配置数据...")
- config_data = [
- ('heartbeat_interval_seconds', '30', 'int', '心跳间隔秒数(默认30秒)', 1, 1),
- ('key_overlap_minutes', '30', 'int', '新旧密钥共存分钟数', 1, 1),
- ('key_expire_minutes', '60', 'int', '密钥过期分钟数(从创建时间算起)', 1, 1),
- ('max_heartbeat_failures', '10', 'int', '最大心跳失败次数,超过后暂停检测', 1, 1),
- ('max_network_failures', '15', 'int', '网络异常最大失败次数,超过后登出', 1, 1),
- ('prevent_duplicate_login', '1', 'bool', '是否防止重复登录:0-否,1-是', 1, 1),
- ('timestamp_tolerance_seconds', '300', 'int', '时间戳容忍秒数(前后5分钟)', 1, 1),
- ('session_extend_enabled', '1', 'bool', '是否启用心跳延长session:0-否,1-是', 1, 1),
- ('session_extend_threshold_hours', '4', 'int', 'session延长阈值(小时),距离过期小于此值时延长', 1, 1),
- ('session_extend_hours', '2', 'int', '每次心跳延长的小时数', 1, 1),
- ('api_timeout_seconds', '30', 'int', 'API请求超时秒数', 1, 1),
- ('client_heartbeat_interval_seconds', '30', 'int', '客户端心跳间隔秒数', 1, 1)
- ]
- cursor.executemany("""
- INSERT INTO `system_config` (`config_key`, `config_value`, `config_type`, `description`, `is_system`, `is_editable`)
- VALUES (%s, %s, %s, %s, %s, %s)
- ON DUPLICATE KEY UPDATE
- `config_value` = VALUES(`config_value`),
- `config_type` = VALUES(`config_type`),
- `description` = VALUES(`description`),
- `is_system` = VALUES(`is_system`),
- `is_editable` = VALUES(`is_editable`),
- `updated_at` = NOW()
- """, config_data)
- conn.commit()
- print("✅ 系统配置表迁移完成!")
- # 6. 验证迁移结果
- cursor.execute("SELECT COUNT(*) as count FROM system_config WHERE is_deleted = 0")
- count = cursor.fetchone()[0]
- print(f"✅ 成功插入 {count} 条配置记录")
- # 7. 显示配置列表
- cursor.execute("SELECT config_key, config_value, config_type, description FROM system_config WHERE is_deleted = 0 ORDER BY config_key")
- configs = cursor.fetchall()
- print("\n📋 配置列表:")
- for config in configs:
- print(f" {config[0]}: {config[1]} ({config[2]}) - {config[3]}")
- except Exception as e:
- print(f"❌ 迁移失败: {e}")
- if 'conn' in locals():
- conn.rollback()
- raise
- finally:
- if 'cursor' in locals():
- cursor.close()
- if 'conn' in locals():
- conn.close()
- if __name__ == "__main__":
- print("🗄️ 系统配置表迁移工具")
- print("=" * 50)
- # 检查是否为非交互环境,如果是则自动继续
- import sys
- is_interactive = sys.stdin.isatty()
- if is_interactive:
- # 确认操作
- confirm = input("⚠️ 此操作将重新创建system_config表,确定继续吗?(y/N): ")
- if confirm.lower() not in ['y', 'yes']:
- print("❌ 操作已取消")
- exit(0)
- else:
- print("🔄 非交互环境,自动继续迁移...")
- migrate_system_config()
- print("\n🎉 迁移完成!请重启后端应用以使用新的配置系统。")
|