---
order: 1
---
# 系统迁移

在实际项目中会有迁移合并正在使用中的环境的需求，本文将以把B环境迁移合并到A环境为例，介绍如何迁移合并两个环境。

::: tip
迁移前准备工作如下：

1. 防止迁移过程中出现不可控的错误，迁移之前请备份目标环境default数据源库
2. 确保两个环境的版本号相同，若不同请更换相同的war
3. 获得被迁移系统的所有数据源信息
   ::::

迁移合并系统的主要步骤为：

1. [迁移数据源配置](#迁移数据源配置)
2. [备份恢复项目元数据](#备份恢复项目元数据)
3. [迁移权限数据](#迁移权限数据)
4. [迁移文件数据源](#迁移文件数据源)

## 系统迁移步骤{#step}

### 迁移数据源配置{#configuration}

在A系统中添加B系统中的所有数据源连接(详见[数据源连接](../../data-connect/datasources.md))，此处需要添加ODS数据源
![添加数据源](./images/2020-07-01-10-06-28.png)
当需要迁移的数据源较多时，可以在B系统的系统数据项目下，进入`资源`模块，导出`data-source`下的所有项目，再导入到A系统的相同位置即可
![导出数据源](./images/2020-07-07-16-48-28.png)

### 备份恢复项目元数据{#backup-restore}

备份元数据步骤如下：

1. 在B系统的`系统设置-备份`页面中，点击`立即备份`生成备份包
2. 在`备份日志`列表中，点击下载新生成的备份包
   ![备份](./images/2020-07-01-10-03-03.png)

恢复元数据分为以下两部分：

- **恢复项目元数据**：恢复备份包中的模型、仪表板、表单等元数据
- **迁移系统权限数据**：包括部门、用户、用户组、用户组成员、权限数据，分别对应default数据源中的**SZSYS\_4\_DEPTS**、**SZSYS\_4\_USERS**、**SZSYS\_4\_USER\_GROUPS**、**SZSYS\_4\_USER\_GROUP\_MEMBERS**、**SZSYS\_4\_PERMISSIONS**

恢复元数据步骤如下：

1. 在A系统的`系统设置-恢复`页面上传[备份元数据步骤](#备份元数据)中下载的备份包
2. 在`选择需要恢复的项目`列表中勾选B，不勾选`恢复系统设置`

::: warning
由于元数据恢复功能支持将备份包中的权限数据覆盖到当前系统，所以此处根据对权限迁移的实际需求不同有不同的处理方式，常见情况及其处理方式见[迁移权限数据](#迁移权限数据)
:::

### 迁移权限数据{#permission-data}

迁移权限数据常见需求及处理方式如下：

- [使用迁移目标系统权限数据](#使用迁移目标系统权限数据)：在元数据恢复时不勾选`恢复用户和权限数据`
- [使用被迁移系统权限数据](#使用被迁移系统权限数据)：在元数据恢复时勾选`恢复用户和权限数据`
- [选择性保留双方权限数据](#保留双方权限数据)：在元数据恢复时不勾选`恢复用户和权限数据`，手动处理权限数据，步骤如下：
  1. 备份两系统权限相关数据
  2. 在A系统中连接B系统default数据源，将B中的权限相关系统表以新表的方式导入A系统
  3. 插入权限数据，顺序依次为部门，用户，用户组，用户组成员，权限。
  4. 备份当前权限信息表
  5. 删除不需要的权限数据，顺序依次为权限、用户组成员、用户组、用户、部门
  6. 合并部门信息

#### 使用迁移目标系统权限数据{#use-migration-data}

若合并后的系统中，不需要原B系统的权限设置，则在元数据恢复时不勾选`恢复用户和权限数据`，点击恢复即可完成元数据恢复
![不处理权限数据](./images/2020-07-01-10-26-15.png)

#### 使用被迁移系统权限数据{#use-migrated-data}

若合并后的系统中，使用原B系统的权限设置，且A系统中的权限设置不再使用，则在元数据恢复时勾选`恢复用户和权限数据`，将备份包中的权限数据覆盖当前系统中的数据，然后点击`恢复`即可完成元数据恢复
![覆盖权限数据](./images/2020-07-01-10-29-33.png)

#### 保留双方权限数据{#keep-data}

本次迁移合并需求为保留A系统中的"上级单位" "外单位"部门，B中的"无锡市市场监督管理局"部门，并合并dev、赛思部门，保留所有用户组，因此在元数据恢复时不勾选`恢复用户和权限数据`，点击`恢复`完成项目元数据恢复
![不处理权限数据](./images/2020-07-01-10-26-15.png)

为实现需求需要手动处理权限相关数据，具体步骤如下：

1. 防止处理权限数据时出现误操作，需要先备份相关表，推荐使用`CREATE TABLE SZSYS_5_DEPTS_SJZT AS SELECT * FROM SZSYS_5_DEPTS`语句

2. 在A系统中连接B系统default数据源，将B中的权限相关系统表以新表的方式导入A系统，具体方法如下:
   - 进入恢复的A项目，将原A系统default数据源添加到数据中台系统中，命名为ZHJGDEFAULT
   - 右键点击ZHJGDEFAULT中的部门表(SZSYS\_4\_DEPTS)，选择开始加工
     ![导入权限信息1](./images/2020-07-01-17-42-43.png)
   - 给模型添加输出节点，设置目标物理表为`default/SDI/SZSYS_4_DEPTS_B`，并提取数据
     ![导入权限信息2](./images/2020-07-01-17-41-20.png)
   - 依次导入用户、用户组、用户组成员、权限数据，物理表名依次为SZSYS\_4\_USERS\_B、SZSYS\_4\_USER\_GROUPS\_B、SZSYS\_4\_USER\_GROUP\_MEMBERS\_B、SZSYS\_4\_PERMISSIONS\_B

3. 插入权限相关数据，可使用数据库管理工具或直接运行INSERT语句的方式，顺序依次为部门，用户，用户组，用户组成员，权限。插入时注意：
   - 确保各表主键字段数据不重复，重复部分以A系统优先，可使用`NOT EXISTS(SELECT 1 FROM t1 WHERE t1.PK=t2.PK)`语句
   - 用户组成员、权限确保导入的用户、用户组数据在当前系统是存在的，可使用`EXISTS (SELECT 1 FROM t1 WHERE t1.GROUP_ID=t2.GROUP_ID)`

4. 备份当前权限信息表，方法与步骤1相同

5. 删除权限相关数据，可使用数据库管理工具或直接运行DELETE语句的方式，顺序依次为权限、用户组成员、用户组、用户、部门。删除时注意：
   - 部门表以`SZ_PID`字段记录部门层级，因此通过`SZ_PID0=xx`条件筛选出部门ID为xx的部门及其所有下级部门的权限数据
   - 权限表中`OWNER_TYPE`字段记录权限拥有者类型，'u'为用户，'g'为用户组，语句中需要增加类型的判断，例如`WHERE t2.USER_ID=t1.OWNER_ID AND t1.OWNER_TYPE='u')`

6. 合并部门信息，可使用数据库管理工具或直接运行UPDATE语句的方式，例如将dev(DEPT\_ID为'01')和赛思(DEPT\_ID为'Succez')合并步骤如下：
   1. 在用户表中将DEPT\_ID为'01'的DEPT\_ID列修改为'Succez'
   2. 在部门表中删除dev部门

<details>
  <summary><font size=5>本次迁移权限数据SQL如下</font></summary>

```sql
1. 后面还需要删除不需要的部门、用户、权限信息，保险起见备份当前权限信息表
    # 备份部门表
    CREATE TABLE SZSYS_5_DEPTS_A AS SELECT * FROM SZSYS_5_DEPTS

    # 备份用户表
    CREATE TABLE SZSYS_5_USERS_A AS SELECT * FROM SZSYS_5_DEPTS

    # 备份用户组表
    CREATE TABLE SZSYS_5_USER_GROUPS_A AS SELECT * FROM SZSYS_5_USER_GROUPS

    # 备份用户组成员表
    CREATE TABLE SZSYS_5_USER_GROUP_MEMBERS_A AS SELECT * FROM SZSYS_5_USER_GROUP_MEMBERS

    # 备份权限表
    CREATE TABLE SZSYS_5_PERMISSIONS_A AS SELECT * FROM SZSYS_5_PERMISSIONS

2. 按照中的需求将原B系统中的权限数据插入到当前环境系统表中
    #从SZSYS_4_DEPTS_B插入部门数据到部门表中
    INSERT INTO SZSYS_5_DEPTS(SZ_PID0 ,
            SZ_PID1 ,
            SZ_PID2 ,
            SZ_PID3 ,
            SZ_PID4 ,
            SZ_PID5 ,
            PARENT_ID ,
            DEPT_ID ,
            DEPT_NAME ,
            ORG_ID ,
            ORDER_ID ,
            CREATE_FROM ,
            SZ_LEVEL ,
            SZ_ISLEAF) SELECT SZ_PID0 ,
            SZ_PID1 ,
            SZ_PID2 ,
            SZ_PID3 ,
            SZ_PID4 ,
            SZ_PID5 ,
            PARENT_ID ,
            DEPT_ID ,
            DEPT_NAME ,
            ORG_ID ,
            ORDER_ID ,
            CREATE_FROM ,
            SZ_LEVEL ,
            SZ_ISLEAF
    FROM SZSYS_5_DEPTS_B

    #从SZSYS_4_USERS_B导入用户数据到用户表中，NOT EXISTS语句防止主键(USER_ID)数据重复
    #重复数据以A优先
    INSERT INTO SZSYS_5_USERS(USER_ID ,
            USER_NAME ,
            ORG_ID ,
            DEPT_ID ,
            ORDER_ID ,
            PASSWORD ,
            SALT ,
            PHONE ,
            EMAIL ,
            CREATOR ,
            QQ ,
            WECHAT ,
            QQ_OPENID ,
            WECHAT_OPENID ,
            SIGNUP_FROM ,
            DELEGATE_TO ,
            ENTERPRISE_USER_ID ,
            USER_LABELS ,
            ENABLED ,
            CREATE_TIME ,
            DELEGATE_START_TIME ,
            DELEGATE_END_TIME) SELECT USER_ID ,
            USER_NAME ,
            ORG_ID ,
            DEPT_ID ,
            ORDER_ID ,
            PASSWORD ,
            SALT ,
            PHONE ,
            EMAIL ,
            CREATOR ,
            QQ ,
            WECHAT ,
            QQ_OPENID ,
            WECHAT_OPENID ,
            SIGNUP_FROM ,
            DELEGATE_TO ,
            ENTERPRISE_USER_ID ,
            USER_LABELS ,
            ENABLED ,
            CREATE_TIME ,
            DELEGATE_START_TIME ,
            DELEGATE_END_TIME
    FROM SZSYS_5_USERS_B t2
    WHERE NOT EXISTS
        (SELECT 1
        FROM SZSYS_5_USERS t1
        WHERE t1.USER_ID=t2.USER_ID)

    #从SZSYS_4_USER_GROUPS_B导入用户组数据到用户组表中
    #NOT EXISTS语句防止主键(GROUP_ID)数据重复，重复数据以A优先
    INSERT INTO SZSYS_5_USER_GROUPS(GROUP_ID ,
            GROUP_NAME ,
            MATCH_EXP ,
            DESC ,
            CREATE_TIME ,
            MODIFY_TIME ,
            CREATOR ,
            MODIFIER ,
            ENABLED ,
            REFRESH_STATE) SELECT GROUP_ID ,
            GROUP_NAME ,
            MATCH_EXP ,
            DESC ,
            CREATE_TIME ,
            MODIFY_TIME ,
            CREATOR ,
            MODIFIER ,
            ENABLED ,
            REFRESH_STATE
    FROM SZSYS_5_USER_GROUPS_B t2
    WHERE NOT EXISTS
        (SELECT 1
        FROM SZSYS_5_USER_GROUPS t1
        WHERE t1.GROUP_ID=t2.GROUP_ID)

    #从SZSYS_4_USER_GROUP_MEMBERS_B导入用户组成员数据到用户组成员表中
    #NOT EXISTS语句防止主键(USER_ID、GROUP_ID、AUTO_MATCH)数据重复，重复数据以A优先
    #EXISTS语句保证导入的用户、用户组是在A系统存在的
        INSERT INTO SDI.SZSYS_4_USER_GROUP_MEMBERS(USER_ID ,
                GROUP_ID ,
                AUTO_MATCH ,
                GRANTOR ,
                GRANT_TIME) SELECT USER_ID ,
                GROUP_ID ,
                AUTO_MATCH ,
                GRANTOR ,
                GRANT_TIME
        FROM SZSYS_5_USER_GROUP_MEMBERS_B t2
        WHERE NOT EXISTS
            (SELECT 1
            FROM SZSYS_5_USER_GROUP_MEMBERS t1
            WHERE t1.USER_ID=t2.USER_ID
                    AND t1.GROUP_ID=t2.GROUP_ID
                    AND t1.AUTO_MATCH=t2.AUTO_MATCH)
                AND EXISTS
            (SELECT 1
            FROM SZSYS_5_USER_GROUPS t3
            WHERE t2.GROUP_ID=t3.GROUP_ID)
                AND EXISTS
            (SELECT 1
            FROM SZSYS_5_USERS t4
            WHERE t2.USER_ID=t4.USER_ID)

    #从**SZSYS_4_PERMISSIONS_B**导入权限数据到权限表中
    #EXISTS语句保证导入的用户、用户组是在当前系统存在的
    #权限表的主键PERMISSION_ID是唯一的MD5码，因此不需要考虑重复数据的情况
        INSERT INTO SDI.SZSYS_4_PERMISSIONS(PERMISSION_ID ,
                OWNER_ID ,
                OWNER_TYPE ,
                RES_PATH ,
                ALLOWS ,
                FORBIDS ,
                DATA_RANGE ,
                GRANTOR ,
                GRANT_TIME) SELECT PERMISSION_ID ,
                OWNER_ID ,
                OWNER_TYPE ,
                RES_PATH ,
                ALLOWS ,
                FORBIDS ,
                DATA_RANGE ,
                GRANTOR ,
                GRANT_TIME
        FROM SZSYS_5_PERMISSIONS_B t2
        WHERE EXISTS
            (SELECT 1
            FROM SZSYS_5_USERS t1
            WHERE t1.USER_ID=t2.OWNER_ID
                    AND t2.OWNER_TYPE='u')
                OR EXISTS
            (SELECT 1
            FROM SZSYS_5_USER_GROUPS t3
            WHERE t3.GROUP_ID=t2.OWNER_ID
                    AND t2.OWNER_TYPE='g')

3. 按照需求，后面还需要删除不需要的部门、用户、权限信息，保险起见备份当前权限信息表
    # 备份部门表
    CREATE TABLE SZSYS_5_DEPTS_NEW AS SELECT * FROM SZSYS_5_DEPTS

    # 备份用户表
    CREATE TABLE SZSYS_5_USERS_NEW AS SELECT * FROM SZSYS_5_DEPTS

    # 备份用户组表
    CREATE TABLE SZSYS_5_USER_GROUPS_NEW AS SELECT * FROM SZSYS_5_USER_GROUPS

    # 备份用户组成员表
    CREATE TABLE SZSYS_5_USER_GROUP_MEMBERS_NEW AS SELECT * FROM SZSYS_5_USER_GROUP_MEMBERS

    # 备份权限表
    CREATE TABLE SZSYS_5_PERMISSIONS_NEW AS SELECT * FROM SZSYS_5_PERMISSIONS

4. 按照需求，删除不需要的"江苏市场监督管理局"(DEPT_ID为'100')及其所有下级部门的权限数据

    # 筛选出需要删除的部门数据，条件为最高层级部门ID为'100'，并创建为TEMP_DEPT表
    CREATE TABLE TEMP_DEPT AS SELECT * FROM SZSYS_5_DEPTS WHERE SZ_PID0='100'


    # 筛选出需要删除的用户数据，并创建为TEMP_USER表
    CREATE TABLE TEMP_USER AS SELECT *
    FROM SZSYS_5_USERS_NEW t1
    WHERE EXISTS
        (SELECT 1
        FROM TEMP_DEPT t2
        WHERE t1.DEPT_ID=t2.DEPT_ID)


    #删除TEMP_USER中用户的权限数据
    #权限表中OWNER_TYPE字段记录权限拥有者类型，'u'为用户
    DELETE
    FROM SZSYS_5_PERMISSIONS t1
    WHERE EXISTS
        (SELECT 1
        FROM TEMP_USER t2
        WHERE t2.USER_ID=t1.OWNER_ID
        AND t1.OWNER_TYPE='u')

    #在用户组成员表中删除TEMP_USER中存在的用户组成员数据
    DELETE
    FROM SZSYS_5_USER_GROUP_MEMBERS t1
    WHERE EXISTS
        (SELECT 1
        FROM TEMP_USER t2
        WHERE t2.USER_ID=t1.USER_ID)

    #在用户表中删除TEMP_USER中存在的用户数据
    DELETE
    FROM SZSYS_5_USERS t1
    WHERE EXISTS
        (SELECT 1
        FROM TEMP_USER t2
        WHERE t2.USER_ID=t1.USER_ID)

    # 在部门表删除TEMP_DEPT中存在的部门数据
    DELETE
    FROM SZSYS_5_DEPTS t1
    WHERE EXISTS
        (SELECT 1
        FROM TEMP_DEPT t2
        WHERE t2.DEPT_ID=t1.DEPT_ID)

5. 合并dev(DEPT_ID为'01')和赛思(DEPT_ID为'Succez')两个部门的用户信息
    #在用户表中将DEPT_ID为'01'的DEPT_ID列修改为'Succez'
    UPDATE SZSYS_5_USERS SET DEPT_ID='Succez'
    WHERE DEPT_ID='01'

    #在部门表中删除dev部门
    DELETE FROM SZSYS_5_DEPTS
    WHERE DEPT_ID='01'
```

</details>

### 迁移文件数据源{#file-data}

经过以上步骤，B项目已经合并迁移到了A项目所在的系统中来，但由于文件数据源不包含在元数据内且目前文件数据源不支持导出，所以需要在服务器中手动将文件数据源迁移，步骤如下：

1. 进入原B项目所在服务器的`workdir/clusters-share/data-files/B`目录，拷贝该目录下的所有文件到A项目所在服务器的相同目录下，工作目录在`/Tomcat/bin/setenv.sh`下配置，详见[此处](../install/basic-install/workdir-and-defdb.md#set-workdir)
2. 重启Tomcat

## 迁移完工验证{#verify}

经过以上步骤，迁移合并系统已完成，需要对迁移后的系统进行相关测试，确定该系统下的项目都能稳定运行，大致范围如下:

1. 数据源：连接其他数据库
2. 数据：上传数据文件，数据加工，SQL查询等
3. 分析：设计、分享、评论仪表板
4. 表单：设计表单、流程并发布报表填报应用
5. 应用：设计门户
6. 资源：管理系统资源，如新建、删除、移动、复制资源等
7. 系统设置：设置系统登录页
