"""PROD数据库 UUID 迁移 — 保留现有数据""" import pymysql, uuid conn = pymysql.connect(host='db1.prod.zgitm.com', port=3306, user='mokeegateway', password='mokee.', database='mokeegateway', charset='utf8mb4') cur = conn.cursor() def uid(): return uuid.uuid4().hex def ex(sql, *args): cur.execute(sql, args) conn.commit() # 1. 为所有表添加 uuid_id 列(每次单独执行,忽略已存在错误) tables = ['sys_system','sys_user','sys_role','sys_menu','sys_api','sys_dict','sys_file','sys_user_system','sys_user_role','sys_role_menu','sys_login_log','sys_operation_log'] for t in tables: try: ex(f"ALTER TABLE {t} ADD COLUMN uuid_id VARCHAR(64) NOT NULL DEFAULT ''") except Exception as e: print(f'{t} add col: {e}') # 2. 生成UUID for t in tables: ex(f"UPDATE {t} SET uuid_id = REPLACE(UUID(),'-','')") print('UUID generated') # 3. 收集新旧ID映射(先收集所有,避免 JOIN 更新时列类型冲突) id_map = {} for t in tables: cur.execute(f"SELECT id, uuid_id FROM {t}") id_map[t] = {str(old): new for old, new in cur.fetchall()} print('ID maps collected') # 4. 先将所有FK列扩大为VARCHAR(64) (允许NULL先) print('Modifying FK columns to VARCHAR...') for child_tbl, fks in { 'sys_api': ['system_id'], 'sys_role': ['system_id'], 'sys_menu': ['system_id','parent_id'], 'sys_user_system': ['user_id','system_id'], 'sys_user_role': ['user_id','role_id'], 'sys_role_menu': ['role_id','menu_id'], 'sys_login_log': ['user_id','system_id'], 'sys_operation_log': ['user_id','system_id'], 'sys_system': ['created_by','updated_by'], }.items(): for col in fks: try: ex(f"ALTER TABLE {child_tbl} MODIFY {col} VARCHAR(64)") except: pass try: ex("ALTER TABLE sys_role MODIFY created_by VARCHAR(64)") except: pass try: ex("ALTER TABLE sys_role MODIFY updated_by VARCHAR(64)") except: pass print('FK columns widened') # 5. 更新外键引用 fk_updates = { 'sys_api': {'system_id': 'sys_system'}, 'sys_role': {'system_id': 'sys_system'}, 'sys_menu': {'system_id': 'sys_system'}, 'sys_user_system': {'system_id': 'sys_system', 'user_id': 'sys_user'}, 'sys_user_role': {'user_id': 'sys_user', 'role_id': 'sys_role'}, 'sys_role_menu': {'role_id': 'sys_role', 'menu_id': 'sys_menu'}, 'sys_login_log': {'user_id': 'sys_user', 'system_id': 'sys_system'}, 'sys_operation_log':{'user_id': 'sys_user', 'system_id': 'sys_system'}, } for child_tbl, fks in fk_updates.items(): for fk_col, parent_tbl in fks.items(): # 读取当前FK值,通过id_map转换后更新 cur.execute(f"SELECT id, {fk_col} FROM {child_tbl}") rows = cur.fetchall() for row_id, old_fk in rows: if old_fk and str(old_fk) in id_map.get(parent_tbl, {}): new_fk = id_map[parent_tbl][str(old_fk)] ex(f"UPDATE {child_tbl} SET {fk_col}=%s WHERE id=%s", new_fk, row_id) print(f'{child_tbl}.{fk_col} updated') # 6. menu parent_id 自引用 cur.execute(f"SELECT id, parent_id FROM sys_menu WHERE parent_id != '0'") for mid, pid in cur.fetchall(): if str(pid) in id_map['sys_menu']: ex(f"UPDATE sys_menu SET parent_id=%s WHERE id=%s", id_map['sys_menu'][str(pid)], mid) print('menu parent_id updated') # 7. 切换主键 for t in tables: cur.execute(f"ALTER TABLE {t} DROP PRIMARY KEY, DROP COLUMN id, CHANGE uuid_id id VARCHAR(64) NOT NULL, ADD PRIMARY KEY (id)") print('PK switched') # 8. 重建索引 try: ex("ALTER TABLE sys_api DROP INDEX uk_system_path_method"); ex("ALTER TABLE sys_api ADD UNIQUE KEY uk_system_path_method (system_id, api_path, api_method)") except: pass try: ex("ALTER TABLE sys_role DROP INDEX uk_system_role_code"); ex("ALTER TABLE sys_role ADD UNIQUE KEY uk_system_role_code (system_id, role_code)") except: pass # 验证 cur.execute('SELECT id, username FROM sys_user LIMIT 1') r = cur.fetchone() print(f'验证: user id len={len(str(r[0]))}, username={r[1]}') for t in tables: cur.execute(f"SELECT COUNT(*) FROM {t}") print(f'{t}: {cur.fetchone()[0]}') cur.close(); conn.close() print('PROD MIGRATION DONE')