# 多租户改造执行指南 ## 🎯 当前状态 ✅ **代码层已完成:** - Entity 层:14个实体的 `tenant_id` 字段已统一 - Service 层:关键服务的租户过滤已实现 - SQL 查询:字段名已统一为 `tenant_id` ⏳ **待执行:数据库迁移** ## 📋 执行步骤 ### 步骤 1:执行主迁移脚本(必需) 为所有业务表添加 `tenant_id` 字段: ```bash # PowerShell 执行 Get-Content "d:\DEMONET\tools\sql\add_tenant_id_to_business_tables.sql" | mysql --host=localhost --user=root --password=你的密码 --database=aidopdev # 或直接用 MySQL 客户端 mysql -u root -p aidopdev < d:\DEMONET\tools\sql\add_tenant_id_to_business_tables.sql ``` **影响的表(13张):** - ado_contract_review - ado_contract_review_flow - LinkagePlan - ProductDesign - ProductDesignBom - ProductDesignRouting - crm_seorder(已有字段,脚本会跳过) - crm_seorderentry - ShippingPlan - ShippingPlanDetail - AsnShipperMaster - AsnShipperDetail - ScheduleExceptionMaster ### 步骤 2:添加 HolidayMaster 表字段(推荐) HolidayMaster 是主数据表,Service 层已实现租户过滤: ```bash # PowerShell 执行 Get-Content "d:\DEMONET\tools\sql\add_tenant_id_to_holiday_master.sql" | mysql --host=localhost --user=root --password=你的密码 --database=aidopdev # 或直接用 MySQL 客户端 mysql -u root -p aidopdev < d:\DEMONET\tools\sql\add_tenant_id_to_holiday_master.sql ``` ### 步骤 3:为现有数据设置租户ID(如有历史数据) 如果数据库中已有业务数据,需要为它们设置租户ID: ```sql -- 假设默认租户ID为 1,请根据实际情况调整 -- Order 模块 UPDATE crm_seorder SET tenant_id = 1 WHERE tenant_id IS NULL; UPDATE crm_seorderentry SET tenant_id = 1 WHERE tenant_id IS NULL; UPDATE ado_contract_review SET tenant_id = 1 WHERE tenant_id IS NULL; UPDATE ado_contract_review_flow SET tenant_id = 1 WHERE tenant_id IS NULL; UPDATE LinkagePlan SET tenant_id = 1 WHERE tenant_id IS NULL; UPDATE ProductDesign SET tenant_id = 1 WHERE tenant_id IS NULL; UPDATE ProductDesignBom SET tenant_id = 1 WHERE tenant_id IS NULL; UPDATE ProductDesignRouting SET tenant_id = 1 WHERE tenant_id IS NULL; UPDATE ShippingPlan SET tenant_id = 1 WHERE tenant_id IS NULL; UPDATE ShippingPlanDetail SET tenant_id = 1 WHERE tenant_id IS NULL; UPDATE AsnShipperMaster SET tenant_id = 1 WHERE tenant_id IS NULL; UPDATE AsnShipperDetail SET tenant_id = 1 WHERE tenant_id IS NULL; -- Production 模块 UPDATE ScheduleExceptionMaster SET tenant_id = 1 WHERE tenant_id IS NULL; UPDATE HolidayMaster SET tenant_id = 1 WHERE tenant_id IS NULL; ``` ### 步骤 4:验证迁移结果 ```sql -- 验证所有表的 tenant_id 字段 SELECT TABLE_NAME AS 表名, COLUMN_NAME AS 字段名, COLUMN_TYPE AS 字段类型, IS_NULLABLE AS 是否可空 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'aidopdev' AND COLUMN_NAME = 'tenant_id' AND TABLE_NAME IN ( 'ado_contract_review', 'ado_contract_review_flow', 'LinkagePlan', 'ProductDesign', 'ProductDesignBom', 'ProductDesignRouting', 'crm_seorder', 'crm_seorderentry', 'ShippingPlan', 'ShippingPlanDetail', 'AsnShipperMaster', 'AsnShipperDetail', 'ScheduleExceptionMaster', 'HolidayMaster' ) ORDER BY TABLE_NAME; -- 验证索引 SELECT TABLE_NAME AS 表名, INDEX_NAME AS 索引名, COLUMN_NAME AS 字段名 FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA = 'aidopdev' AND COLUMN_NAME = 'tenant_id' AND INDEX_NAME = 'idx_tenant_id' ORDER BY TABLE_NAME; ``` ## 🧪 测试验证 ### 1. 功能测试 - 使用不同租户账号登录 - 创建、查询、修改、删除业务数据 - 验证只能看到本租户的数据 ### 2. 数据隔离测试 ```sql -- 创建测试数据(假设租户1和租户2) INSERT INTO crm_seorder (Id, bill_no, tenant_id, ...) VALUES (..., 1, ...); -- 租户1 INSERT INTO crm_seorder (Id, bill_no, tenant_id, ...) VALUES (..., 2, ...); -- 租户2 -- 使用租户1登录,应该只能看到租户1的数据 -- 使用租户2登录,应该只能看到租户2的数据 ``` ### 3. 性能测试 ```sql -- 检查索引是否生效 EXPLAIN SELECT * FROM crm_seorder WHERE tenant_id = 1; -- 应该显示使用了 idx_tenant_id 索引 ``` ## 📁 相关文件 ### SQL 脚本 - `tools/sql/add_tenant_id_to_business_tables.sql` - 主迁移脚本 - `tools/sql/add_tenant_id_to_holiday_master.sql` - HolidayMaster 专用脚本 ### PowerShell 工具 - `tools/fix_tenant_id_column_name.ps1` - 字段名统一工具 - `tools/add_tenant_id_to_entities.ps1` - Entity 批量添加工具 ### 文档 - `tools/TENANT_MIGRATION_REPORT.md` - 完整改造报告 - `tools/TENANT_FIELD_NAME_UNIFICATION_REPORT.md` - 字段名统一报告 ## ⚠️ 注意事项 1. **备份数据库** ```bash mysqldump -u root -p aidopdev > aidopdev_backup_$(date +%Y%m%d).sql ``` 2. **生产环境执行** - 建议在低峰期执行 - 先在测试环境验证 - 通知相关人员 3. **回滚方案** 如需回滚,可以删除 tenant_id 字段: ```sql ALTER TABLE 表名 DROP COLUMN tenant_id; DROP INDEX idx_tenant_id ON 表名; ``` ## 🎉 完成标志 执行完成后,您应该看到: - ✅ 所有业务表都有 `tenant_id` 字段 - ✅ 所有表都有 `idx_tenant_id` 索引 - ✅ 现有数据(如有)已设置租户ID - ✅ 功能测试通过,数据正确隔离 ## 📞 问题排查 ### 问题1:字段已存在 ``` ERROR: Duplicate column name 'tenant_id' ``` **解决方案:** 正常,说明该表已有字段,脚本会自动跳过 ### 问题2:索引已存在 ``` ERROR: Duplicate key name 'idx_tenant_id' ``` **解决方案:** 正常,说明索引已创建,脚本会自动跳过 ### 问题3:权限不足 ``` ERROR: Access denied ``` **解决方案:** 确保使用有 ALTER TABLE 权限的数据库用户 --- 生成时间:2026-04-22 字段标准:tenant_id(小写下划线) 执行顺序:迁移脚本 → 数据初始化 → 验证测试