# 数据库迁移脚本指南(PostgreSQL → MySQL) ## 1. 概述 本文档提供了将 urbanLifeline 数据库从 PostgreSQL 迁移到 MySQL(pigx 平台)的完整脚本和指南。 ## 2. 数据类型映射 | PostgreSQL | MySQL | 说明 | |-----------|-------|------| | VARCHAR(n) | VARCHAR(n) | 字符串 | | TEXT | TEXT | 长文本 | | INTEGER | INT | 整数 | | BIGINT | BIGINT | 长整数 | | BOOLEAN | TINYINT(1) | 布尔值 | | TIMESTAMPTZ | DATETIME | 时间戳 | | JSONB | JSON | JSON数据 | | NUMERIC(p,s) | DECIMAL(p,s) | 小数 | | VARCHAR(n)[] | JSON | 数组转JSON | | SERIAL | INT AUTO_INCREMENT | 自增 | ## 3. pigx-dify 模块数据库脚本 ### 3.1 智能体表 (tb_agent) ```sql -- 智能体配置表 CREATE TABLE `tb_agent` ( `optsn` varchar(50) NOT NULL COMMENT '流水号', `agent_id` varchar(50) NOT NULL COMMENT '智能体ID', `name` varchar(50) NOT NULL COMMENT '智能体名称', `description` varchar(500) DEFAULT NULL COMMENT '智能体描述', `link` varchar(500) DEFAULT NULL COMMENT '智能体url', `api_key` varchar(500) NOT NULL COMMENT 'dify智能体APIKEY', `is_outer` tinyint(1) DEFAULT '0' COMMENT '是否是对外智能体,未登录可用', `introduce` varchar(500) NOT NULL COMMENT '引导词', `prompt_cards` json DEFAULT NULL COMMENT '提示卡片数组 [{file_id:, prompt:}]', `category` varchar(50) NOT NULL COMMENT '分类', `tenant_id` bigint NOT NULL DEFAULT '1' COMMENT '租户ID', `creator` varchar(50) DEFAULT NULL COMMENT '创建者', `updater` varchar(50) DEFAULT NULL COMMENT '更新者', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `delete_time` datetime DEFAULT NULL COMMENT '删除时间', `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除', PRIMARY KEY (`agent_id`), UNIQUE KEY `uk_optsn` (`optsn`), UNIQUE KEY `uk_api_key` (`api_key`), KEY `idx_tenant_id` (`tenant_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI智能体配置表'; ``` ### 3.2 对话表 (tb_chat) ```sql -- AI智能体对话表 CREATE TABLE `tb_chat` ( `optsn` varchar(50) NOT NULL COMMENT '流水号', `chat_id` varchar(50) NOT NULL COMMENT '对话ID', `agent_id` varchar(50) NOT NULL COMMENT '智能体ID', `user_id` varchar(50) NOT NULL COMMENT '用户ID', `user_type` tinyint(1) NOT NULL DEFAULT '1' COMMENT '用户类型 1-系统内部人员 0-系统外部人员', `title` varchar(500) NOT NULL COMMENT '对话标题', `channel` varchar(50) DEFAULT 'agent' COMMENT '对话渠道 agent、wechat', `tenant_id` bigint NOT NULL DEFAULT '1' COMMENT '租户ID', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `delete_time` datetime DEFAULT NULL COMMENT '删除时间', `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除', PRIMARY KEY (`chat_id`), UNIQUE KEY `uk_optsn` (`optsn`), KEY `idx_agent_id` (`agent_id`), KEY `idx_user_id` (`user_id`), KEY `idx_tenant_id` (`tenant_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI智能体对话表'; ``` ### 3.3 聊天消息表 (tb_chat_message) ```sql -- AI智能体对话消息表 CREATE TABLE `tb_chat_message` ( `optsn` varchar(50) NOT NULL COMMENT '流水号', `message_id` varchar(50) NOT NULL COMMENT '消息ID', `dify_message_id` varchar(100) DEFAULT NULL COMMENT 'Dify消息ID', `chat_id` varchar(50) NOT NULL COMMENT '对话ID', `role` varchar(50) NOT NULL COMMENT '角色:user-用户/ai-智能体/recipient-来客', `content` text NOT NULL COMMENT '消息内容', `files` json DEFAULT NULL COMMENT '文件id数组', `comment` varchar(50) DEFAULT NULL COMMENT '评价', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `delete_time` datetime DEFAULT NULL COMMENT '删除时间', `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除', PRIMARY KEY (`message_id`), UNIQUE KEY `uk_optsn` (`optsn`), KEY `idx_chat_id` (`chat_id`), KEY `idx_dify_message_id` (`dify_message_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI智能体对话消息表'; ``` ### 3.4 知识库表 (tb_knowledge) ```sql -- 知识库配置表 CREATE TABLE `tb_knowledge` ( `optsn` varchar(50) NOT NULL COMMENT '流水号', `knowledge_id` varchar(50) NOT NULL COMMENT '知识库ID', `title` varchar(255) NOT NULL COMMENT '知识库标题', `avatar` varchar(255) DEFAULT NULL COMMENT '知识库头像', `description` varchar(500) DEFAULT NULL COMMENT '知识库描述', `dify_dataset_id` varchar(100) DEFAULT NULL COMMENT 'Dify知识库ID(Dataset ID)', `dify_indexing_technique` varchar(50) DEFAULT 'high_quality' COMMENT 'Dify索引方式(high_quality/economy)', `embedding_model` varchar(100) DEFAULT NULL COMMENT '向量模型名称', `embedding_model_provider` varchar(100) DEFAULT NULL COMMENT '向量模型提供商', `rerank_model` varchar(100) DEFAULT NULL COMMENT 'Rerank模型名称', `rerank_model_provider` varchar(100) DEFAULT NULL COMMENT 'Rerank模型提供商', `reranking_enable` tinyint(1) DEFAULT '0' COMMENT '是否启用Rerank', `retrieval_top_k` int DEFAULT '2' COMMENT '检索Top K(返回前K个结果)', `retrieval_score_threshold` decimal(3,2) DEFAULT '0.00' COMMENT '检索分数阈值(0.00-1.00)', `document_count` int DEFAULT '0' COMMENT '文档数量', `total_chunks` int DEFAULT '0' COMMENT '总分段数', `service` varchar(50) DEFAULT NULL COMMENT '所属服务 workcase、bidding', `project_id` varchar(50) DEFAULT NULL COMMENT 'bidding所属项目ID', `category` varchar(50) DEFAULT NULL COMMENT '所属分类', `tenant_id` bigint NOT NULL DEFAULT '1' COMMENT '租户ID', `creator` varchar(50) NOT NULL COMMENT '创建者(用户ID)', `dept_path` varchar(50) DEFAULT NULL COMMENT '创建者部门路径', `updater` varchar(50) DEFAULT NULL COMMENT '更新者', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `delete_time` datetime DEFAULT NULL COMMENT '删除时间', `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除', PRIMARY KEY (`optsn`), UNIQUE KEY `uk_knowledge_id` (`knowledge_id`), UNIQUE KEY `uk_dify_dataset_id` (`dify_dataset_id`), KEY `idx_tenant_id` (`tenant_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='知识库配置表'; ``` ### 3.5 知识库文件表 (tb_knowledge_file) ```sql -- 知识库文件表 CREATE TABLE `tb_knowledge_file` ( `optsn` varchar(50) NOT NULL COMMENT '流水号', `knowledge_id` varchar(50) NOT NULL COMMENT '知识库ID', `file_root_id` varchar(50) NOT NULL COMMENT '文件根ID', `file_id` varchar(50) NOT NULL COMMENT '文件ID', `dify_file_id` varchar(50) NOT NULL COMMENT 'dify文件ID', `version` int NOT NULL DEFAULT '1' COMMENT '文件版本', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `delete_time` datetime DEFAULT NULL COMMENT '删除时间', `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除', PRIMARY KEY (`optsn`), UNIQUE KEY `uk_knowledge_file` (`knowledge_id`, `file_id`), KEY `idx_file_root_id` (`file_root_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='知识库文件表'; ``` ## 4. pigx-app-server 模块数据库脚本 ### 4.1 工单表 (tb_workcase) ```sql -- 工单表 CREATE TABLE `tb_workcase` ( `optsn` varchar(50) NOT NULL COMMENT '流水号', `workcase_id` varchar(50) NOT NULL COMMENT '工单ID', `room_id` varchar(50) NOT NULL COMMENT '聊天室ID', `user_id` varchar(50) NOT NULL COMMENT '来客ID', `username` varchar(200) NOT NULL COMMENT '来客姓名', `phone` varchar(20) NOT NULL COMMENT '来客电话', `type` varchar(50) NOT NULL COMMENT '故障类型', `device` varchar(50) DEFAULT NULL COMMENT '设备名称', `device_code` varchar(50) DEFAULT NULL COMMENT '设备代码', `device_name_plate` varchar(50) DEFAULT NULL COMMENT '设备名称牌', `device_name_plate_img` varchar(50) NOT NULL COMMENT '设备名称牌图片', `address` varchar(1000) DEFAULT NULL COMMENT '现场地址', `description` varchar(1000) DEFAULT NULL COMMENT '故障描述', `imgs` json DEFAULT NULL COMMENT '工单图片id数组', `emergency` varchar(50) NOT NULL DEFAULT 'normal' COMMENT '紧急程度 normal-普通 emergency-紧急', `status` varchar(50) NOT NULL DEFAULT 'pending' COMMENT '状态 pending-待处理 processing-处理中 done-已完成', `processor` varchar(50) DEFAULT NULL COMMENT '处理人', `tenant_id` bigint NOT NULL DEFAULT '1' COMMENT '租户ID', `creator` varchar(50) NOT NULL COMMENT '创建人', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `delete_time` datetime DEFAULT NULL COMMENT '删除时间', `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除', PRIMARY KEY (`workcase_id`), UNIQUE KEY `uk_room_id` (`room_id`), UNIQUE KEY `uk_optsn` (`optsn`), KEY `idx_user_id` (`user_id`), KEY `idx_status` (`status`), KEY `idx_tenant_id` (`tenant_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='工单表'; ``` ### 4.2 聊天室表 (tb_chat_room) ```sql -- IM聊天室表 CREATE TABLE `tb_chat_room` ( `optsn` varchar(50) NOT NULL COMMENT '流水号', `room_id` varchar(50) NOT NULL COMMENT '聊天室ID', `workcase_id` varchar(50) DEFAULT NULL COMMENT '关联工单ID', `room_name` varchar(200) NOT NULL COMMENT '聊天室名称', `room_type` varchar(20) NOT NULL DEFAULT 'workcase' COMMENT '聊天室类型:workcase-工单客服', `status` varchar(20) NOT NULL DEFAULT 'active' COMMENT '状态:active-活跃 closed-已关闭 archived-已归档', `guest_id` varchar(50) NOT NULL COMMENT '来客ID(创建者)', `guest_name` varchar(100) NOT NULL COMMENT '来客姓名', `ai_session_id` varchar(50) DEFAULT NULL COMMENT 'AI对话会话ID(从ai.tb_chat同步)', `message_count` int NOT NULL DEFAULT '0' COMMENT '消息总数', `device_code` varchar(50) NOT NULL COMMENT '设备代码', `last_message_time` datetime DEFAULT NULL COMMENT '最后消息时间', `last_message` text DEFAULT NULL COMMENT '最后一条消息内容', `comment_level` int DEFAULT '0' COMMENT '服务评分(1-5)', `closed_by` varchar(50) DEFAULT NULL COMMENT '关闭人', `closed_time` datetime DEFAULT NULL COMMENT '关闭时间', `tenant_id` bigint NOT NULL DEFAULT '1' COMMENT '租户ID', `creator` varchar(50) NOT NULL COMMENT '创建人', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `delete_time` datetime DEFAULT NULL COMMENT '删除时间', `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除', PRIMARY KEY (`room_id`), UNIQUE KEY `uk_workcase_id` (`workcase_id`), UNIQUE KEY `uk_optsn` (`optsn`), KEY `idx_guest` (`guest_id`, `status`), KEY `idx_last_message_time` (`last_message_time`), KEY `idx_tenant_id` (`tenant_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='IM聊天室表,一个工单对应一个聊天室'; ``` ### 4.3 聊天室成员表 (tb_chat_room_member) ```sql -- 聊天室成员表 CREATE TABLE `tb_chat_room_member` ( `optsn` varchar(50) NOT NULL COMMENT '流水号', `member_id` varchar(50) NOT NULL COMMENT '成员记录ID', `room_id` varchar(50) NOT NULL COMMENT '聊天室ID', `user_id` varchar(50) NOT NULL COMMENT '用户ID(来客ID或员工ID)', `user_type` varchar(20) NOT NULL COMMENT '用户类型:guest-来客 staff-客服 ai-AI助手', `user_name` varchar(100) NOT NULL COMMENT '用户名称', `status` varchar(20) NOT NULL DEFAULT 'active' COMMENT '状态:active-活跃 left-已离开 removed-被移除', `unread_count` int NOT NULL DEFAULT '0' COMMENT '未读消息数', `last_read_time` datetime DEFAULT NULL COMMENT '最后阅读时间', `last_read_msg_id` varchar(50) DEFAULT NULL COMMENT '最后阅读的消息ID', `join_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '加入时间', `leave_time` datetime DEFAULT NULL COMMENT '离开时间', `creator` varchar(50) NOT NULL COMMENT '创建人', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (`member_id`), UNIQUE KEY `uk_room_user` (`room_id`, `user_id`), KEY `idx_room_status` (`room_id`, `status`), KEY `idx_user` (`user_id`, `user_type`, `status`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='聊天室成员表'; ``` ### 4.4 聊天室消息表 (tb_chat_room_message) ```sql -- 聊天室消息表 CREATE TABLE `tb_chat_room_message` ( `optsn` varchar(50) NOT NULL COMMENT '流水号', `message_id` varchar(50) NOT NULL COMMENT '消息ID', `room_id` varchar(50) NOT NULL COMMENT '聊天室ID', `sender_id` varchar(50) NOT NULL COMMENT '发送者ID', `sender_type` varchar(20) NOT NULL COMMENT '发送者类型:guest-来客 agent-客服 ai-AI助手 system-系统消息', `sender_name` varchar(100) NOT NULL COMMENT '发送者名称', `message_type` varchar(20) NOT NULL DEFAULT 'text' COMMENT '消息类型', `content` text NOT NULL COMMENT '消息内容', `files` json DEFAULT NULL COMMENT '附件文件ID数组', `content_extra` json DEFAULT NULL COMMENT '扩展内容(会议链接、引用信息等)', `reply_to_msg_id` varchar(50) DEFAULT NULL COMMENT '回复的消息ID', `is_ai_message` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否AI消息', `ai_message_id` varchar(50) DEFAULT NULL COMMENT 'AI原始消息ID', `status` varchar(20) NOT NULL DEFAULT 'sent' COMMENT '状态', `read_count` int NOT NULL DEFAULT '0' COMMENT '已读人数', `send_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '发送时间', `creator` varchar(50) NOT NULL COMMENT '创建人', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (`message_id`), KEY `idx_room_time` (`room_id`, `send_time`), KEY `idx_sender` (`sender_id`, `sender_type`), KEY `idx_ai_message` (`ai_message_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='IM聊天消息表'; ``` ### 4.5 视频会议表 (tb_video_meeting) ```sql -- Jitsi Meet视频会议表 CREATE TABLE `tb_video_meeting` ( `optsn` varchar(50) NOT NULL COMMENT '流水号', `meeting_id` varchar(50) NOT NULL COMMENT '会议ID(也是Jitsi房间名)', `room_id` varchar(50) NOT NULL COMMENT '关联聊天室ID', `workcase_id` varchar(50) NOT NULL COMMENT '关联工单ID', `meeting_name` varchar(200) NOT NULL COMMENT '会议名称', `meeting_password` varchar(50) DEFAULT NULL COMMENT '会议密码', `description` varchar(500) DEFAULT NULL COMMENT '会议描述', `jwt_token` text DEFAULT NULL COMMENT 'JWT Token(用于身份验证)', `jitsi_room_name` varchar(200) NOT NULL COMMENT 'Jitsi房间名', `jitsi_server_url` varchar(500) NOT NULL DEFAULT 'https://meet.jit.si' COMMENT 'Jitsi服务器地址', `status` varchar(20) NOT NULL DEFAULT 'scheduled' COMMENT '状态', `creator_type` varchar(20) NOT NULL COMMENT '创建者类型', `creator_name` varchar(100) NOT NULL COMMENT '创建者名称', `participant_count` int NOT NULL DEFAULT '0' COMMENT '参与人数', `max_participants` int DEFAULT '10' COMMENT '最大参与人数', `start_time` datetime NOT NULL COMMENT '定义会议开始时间', `end_time` datetime NOT NULL COMMENT '定义会议结束时间', `advance` int DEFAULT '5' COMMENT '提前入会时间(分钟)', `actual_start_time` datetime DEFAULT NULL COMMENT '真正会议开始时间', `actual_end_time` datetime DEFAULT NULL COMMENT '真正会议结束时间', `duration_seconds` int DEFAULT '0' COMMENT '会议时长(秒)', `iframe_url` text DEFAULT NULL COMMENT 'iframe嵌入URL', `config` json DEFAULT NULL COMMENT 'Jitsi配置项', `tenant_id` bigint NOT NULL DEFAULT '1' COMMENT '租户ID', `creator` varchar(50) NOT NULL COMMENT '创建人', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `delete_time` datetime DEFAULT NULL COMMENT '删除时间', `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除', PRIMARY KEY (`meeting_id`), UNIQUE KEY `uk_jitsi_room_name` (`jitsi_room_name`), KEY `idx_room` (`room_id`, `status`), KEY `idx_workcase` (`workcase_id`, `status`), KEY `idx_create_time` (`create_time`), KEY `idx_tenant_id` (`tenant_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Jitsi Meet视频会议表'; ``` ## 5. 数据迁移步骤 ### 5.1 准备工作 ```bash # 1. 导出 PostgreSQL 数据 pg_dump -h localhost -p 5432 -U postgres -d urbanlifeline \ --data-only \ --column-inserts \ --no-owner \ --no-privileges \ --no-tablespaces \ > urbanlifeline_data.sql # 2. 创建 MySQL 数据库 mysql -u root -p -e "CREATE DATABASE pigx_dify DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;" ``` ### 5.2 执行表结构创建 ```bash # 执行所有建表语句 mysql -u root -p pigx_dify < create_tables.sql ``` ### 5.3 数据转换脚本 ```python #!/usr/bin/env python3 # convert_data.py - PostgreSQL 到 MySQL 数据转换脚本 import re import json def convert_postgresql_to_mysql(input_file, output_file): with open(input_file, 'r', encoding='utf-8') as f: content = f.read() # 替换 PostgreSQL 特有语法 replacements = [ # 布尔值转换 (r'\btrue\b', '1'), (r'\bfalse\b', '0'), # 时间戳转换 (r"now\(\)", "CURRENT_TIMESTAMP"), # 数组转JSON (r"'{([^}]*)}'::\w+\[\]", lambda m: f"'{json.dumps(m.group(1).split(',') if m.group(1) else [])}'"), # Schema 去除 (r'\b(workcase|ai|sys|message|bidding)\\.', ''), ] for pattern, replacement in replacements: if callable(replacement): content = re.sub(pattern, replacement, content) else: content = re.sub(pattern, replacement, content, flags=re.IGNORECASE) # 添加租户ID到每个INSERT语句 content = add_tenant_id(content) with open(output_file, 'w', encoding='utf-8') as f: f.write(content) def add_tenant_id(content): """为所有INSERT语句添加tenant_id字段""" lines = content.split('\n') result = [] for line in lines: if line.startswith('INSERT INTO'): # 检查表是否需要tenant_id if any(table in line for table in ['tb_agent', 'tb_chat', 'tb_workcase', 'tb_chat_room']): # 在VALUES前添加tenant_id字段 line = re.sub( r'(\([^)]+)\)', r'\1, tenant_id)', line, count=1 ) # 在值列表中添加1作为默认租户ID line = re.sub( r'VALUES\s*\(([^)]+)\)', r'VALUES (\1, 1)', line ) result.append(line) return '\n'.join(result) if __name__ == '__main__': convert_postgresql_to_mysql('urbanlifeline_data.sql', 'pigx_data.sql') print("数据转换完成!") ``` ### 5.4 导入数据到 MySQL ```bash # 导入转换后的数据 mysql -u root -p pigx_dify < pigx_data.sql # 验证数据 mysql -u root -p pigx_dify -e " SELECT COUNT(*) FROM tb_agent; SELECT COUNT(*) FROM tb_chat; SELECT COUNT(*) FROM tb_workcase; " ``` ## 6. 添加租户字段指南 ### 6.1 需要添加 tenant_id 的表 所有业务表都需要添加 `tenant_id` 字段: - tb_agent - tb_chat - tb_chat_message(通过chat关联获取) - tb_knowledge - tb_workcase - tb_chat_room - tb_video_meeting ### 6.2 添加租户字段的SQL模板 ```sql -- 为现有表添加租户字段(如果表已存在) ALTER TABLE `tb_agent` ADD COLUMN `tenant_id` BIGINT NOT NULL DEFAULT 1 COMMENT '租户ID' AFTER `category`, ADD INDEX `idx_tenant_id` (`tenant_id`); -- 更新现有数据的租户ID(默认为1) UPDATE tb_agent SET tenant_id = 1 WHERE tenant_id IS NULL; ``` ### 6.3 MyBatis-Plus 配置 ```java // 实体类添加租户字段 @TableField(fill = FieldFill.INSERT) private Long tenantId; // 自动填充处理器 @Component public class MybatisPlusMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { PigxUser user = SecurityUtils.getUser(); this.strictInsertFill(metaObject, "tenantId", Long.class, user.getTenantId()); } } // 租户拦截器配置 @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new TenantLineHandler() { @Override public Expression getTenantId() { return new LongValue(SecurityUtils.getUser().getTenantId()); } @Override public String getTenantIdColumn() { return "tenant_id"; } })); return interceptor; } ``` ## 7. 验证和测试 ### 7.1 数据完整性检查 ```sql -- 检查数据迁移完整性 SELECT 'tb_agent' AS table_name, COUNT(*) AS record_count FROM tb_agent UNION ALL SELECT 'tb_chat', COUNT(*) FROM tb_chat UNION ALL SELECT 'tb_workcase', COUNT(*) FROM tb_workcase; -- 检查租户ID设置 SELECT tenant_id, COUNT(*) AS record_count FROM tb_agent GROUP BY tenant_id; ``` ### 7.2 索引优化 ```sql -- 添加常用查询索引 ALTER TABLE tb_chat ADD INDEX idx_user_agent (user_id, agent_id); ALTER TABLE tb_workcase ADD INDEX idx_create_time (create_time DESC); ALTER TABLE tb_chat_message ADD INDEX idx_chat_time (chat_id, create_time DESC); ``` ## 8. 回滚方案 如果迁移失败,可以使用以下方式回滚: ```bash # 备份当前MySQL数据 mysqldump -u root -p pigx_dify > backup_before_migration.sql # 如需回滚 mysql -u root -p -e "DROP DATABASE pigx_dify; CREATE DATABASE pigx_dify;" mysql -u root -p pigx_dify < backup_before_migration.sql ``` ## 9. 注意事项 1. **字符集**:确保 MySQL 使用 utf8mb4 字符集 2. **时区**:注意 PostgreSQL 的 TIMESTAMPTZ 转换为 MySQL DATETIME 可能有时区差异 3. **数组类型**:PostgreSQL 的数组类型需要转换为 JSON 4. **事务**:大批量数据导入时注意事务大小 5. **权限**:确保 MySQL 用户有足够权限创建表和索引 6. **外键**:本脚本未创建外键约束,如需要可后续添加 ## 10. 迁移清单 - [ ] 导出 PostgreSQL 数据 - [ ] 创建 MySQL 数据库和表结构 - [ ] 执行数据转换脚本 - [ ] 导入数据到 MySQL - [ ] 添加租户字段和索引 - [ ] 验证数据完整性 - [ ] 测试查询性能 - [ ] 配置 MyBatis-Plus 租户拦截器 - [ ] 执行应用集成测试 - [ ] 准备回滚方案