本文最后更新于 2023-10-13,文章内容可能已经过时。

数据库迁移教程

本教程用于从postgres数据库迁移到达梦数据库.

1.准备工作:

1.1 postgres:

正确安装postgres(如果连接远程数据库则不需要在本地安装,有数据库可视化工具即可).

参看postgresql保姆级安装教程pgsql安装食猫竹的博客-CSDN博客

注意:

如果pgsql版本过高,可能会出现navicat和pgsql版本不匹配问题,建议下载pgsql11.21版本.

Cache_79d1fe59052b3.

首次安装完成postgres后,需要登陆pg admin4应用程序(在搜索框直接搜索即可)

image-20230823215247626

登陆后在左上角注册一下server

image-20230823215459663

输入一下刚才指定的密码,然后就可以使用navicat等数据库连接工具访问了。

1.2 达梦数据库:

达梦数据库安装与初始化超详细教程_陈老老老板的博客-CSDN博客

正确安装达梦数据库(远程连接也需要安装).

安装达梦数据库后会出现一堆DM管理工具,能正确启动即可.

2.迁移过程:

2.1 达梦数据库设置

使用DM管理工具来管理达梦数据库.

image-20230823220328700

在此处连接远程数据库.

连接成功后截图如下:

image-20230823220404996

进行数据库迁移之前,要确保数据库中的数据库存在,表存不存在都可以进行迁移.

2.2 导入数据进入pgsql:

进行迁移之前,要先从sql文件中把数据导入进pgsql,由于该sql文件本身过大而且不能运行,所以要进行一些操作.

2.2.1 获取表结构:

新建数据库,运行仅含有表结构的sql文件,生成表结构.

如果该文件无法运行,用记事本打开,删除文件开头的模式即可正常运行.

2.2.2 拆分文件:

拆分过大的sql文件,方便接下来处理.

按大小拆分:用git bash打开

split 文件名 -b 每个文件的大小

按照特征行拆分:python代码

注意修改文件路径.

def split_file(input_file, output_prefix, feature):
    with open(input_file, 'r', encoding='utf-8') as f:
        lines = f.readlines()
​
    current_output_file = None
    file_count = 1
​
    for line in lines:
        if feature in line:
            if current_output_file:
                current_output_file.close()
                file_count += 1
            output_file_name = f"{output_prefix}_{file_count}.txt"
            current_output_file = open(output_file_name, 'w')
        if current_output_file:
            current_output_file.write(line)
​
    if current_output_file:
        current_output_file.close()
​
if __name__ == "__main__":
    input_file = "C:\\Users\\wpy\\Desktop\\xaa.txt"  # 输入文件路径
    output_prefix = "C:\\Users\\wpy\\Desktop\\output"  # 输出文件名前缀
    feature = "-- Data for Name:"  # 特征行的特征
​
    split_file(input_file, output_prefix, feature)
    print("File split completed.")
​

建议先根据大小进行拆分,然后在对拆分过一次的文件进行按特征行拆分的操作,避免电脑卡死.

2.2.2 修改格式:

在数据库里找到要迁移的表(此时只有表结构而无数据),在里面添加一行数据,然后选择导出sql脚本.选择结构和数据,这样就得到了一个sql文件,结构类似如下:

/*
 Navicat Premium Data Transfer
​
 Source Server         : weihai
 Source Server Type    : PostgreSQL
 Source Server Version : 110021
 Source Host           : localhost:7777
 Source Catalog        : postgres
 Source Schema         : public
​
 Target Server Type    : PostgreSQL
 Target Server Version : 110021
 File Encoding         : 65001
​
 Date: 31/08/2023 22:20:03
*/
​
​
-- ----------------------------
-- Table structure for auditlog_log_line
-- ----------------------------
DROP TABLE IF EXISTS "public"."auditlog_log_line";
CREATE TABLE "public"."auditlog_log_line" (
  "id" int4 NOT NULL DEFAULT nextval('auditlog_log_line_id_seq'::regclass),
  "create_uid" int4,
  "log_id" int4,
  "new_value_text" text COLLATE "pg_catalog"."default",
  "field_id" int4 NOT NULL,
  "write_uid" int4,
  "create_date" timestamp(6),
  "old_value_text" text COLLATE "pg_catalog"."default",
  "write_date" timestamp(6),
  "new_value" text COLLATE "pg_catalog"."default",
  "old_value" text COLLATE "pg_catalog"."default"
)
;
COMMENT ON COLUMN "public"."auditlog_log_line"."create_uid" IS 'Created by';
COMMENT ON COLUMN "public"."auditlog_log_line"."log_id" IS 'Log';
COMMENT ON COLUMN "public"."auditlog_log_line"."new_value_text" IS '更新后数据';
COMMENT ON COLUMN "public"."auditlog_log_line"."field_id" IS '字段名';
COMMENT ON COLUMN "public"."auditlog_log_line"."write_uid" IS 'Last Updated by';
COMMENT ON COLUMN "public"."auditlog_log_line"."create_date" IS 'Created on';
COMMENT ON COLUMN "public"."auditlog_log_line"."old_value_text" IS '旧数据';
COMMENT ON COLUMN "public"."auditlog_log_line"."write_date" IS 'Last Updated on';
COMMENT ON COLUMN "public"."auditlog_log_line"."new_value" IS '更新后数据';
COMMENT ON COLUMN "public"."auditlog_log_line"."old_value" IS '更新前数据';
COMMENT ON TABLE "public"."auditlog_log_line" IS 'Auditlog - Log details (fields updated)';
​
-- ----------------------------
-- Records of auditlog_log_line
-- ----------------------------
INSERT INTO "public"."auditlog_log_line" VALUES (1, 1, 1, '电梯安全生产责任保险', 1716, 1, '2021-12-30 06:10:01.749365', NULL, '2021-12-30 06:10:01.749365', '电梯安全生产责任保险', NULL);
INSERT INTO "public"."auditlog_log_line" VALUES (2, 1, 1, '浦林成山(山东)轮胎有限公司', 4333, 1, '2021-12-30 06:10:01.749365', NULL, '2021-12-30 06:10:01.749365', '浦林成山(山东)轮胎有限公司', NULL);
INSERT INTO "public"."auditlog_log_line" VALUES (10, 1, 2, '中国人民财产保险股份有限公司威海市分公司', 4412, 1, '2021-12-30 06:10:01.749365', NULL, '2021-12-30 06:10:01.749365', '中国人民财产保险股份有限公司威海市分公司', NULL);
​

然后找到上一步根据特征行拆分的文件,他们的格式应该是类似于:

--
-- Data for Name: change_password_wizard; Type: TABLE DATA; Schema: public; Owner: odoo
--
​
COPY public.change_password_wizard (id, create_uid, write_uid, write_date, create_date) FROM stdin;
9   1   1   2021-06-03 01:32:19.293484  2021-06-03 01:32:19.293484
10  1   1   2021-06-18 03:10:30.937604  2021-06-18 03:10:30.937604
11  1   1   2021-11-10 07:26:22.03843   2021-11-10 07:26:22.03843
12  1   1   2022-04-21 08:43:53.089246  2022-04-21 08:43:53.089246
13  1   1   2022-04-21 08:44:56.657448  2022-04-21 08:44:56.657448
14  1   1   2022-04-21 08:46:36.041996  2022-04-21 08:46:36.041996
15  1   1   2022-04-21 08:47:47.267276  2022-04-21 08:47:47.267276
16  1   1   2022-04-21 08:49:35.377544  2022-04-21 08:49:35.377544
17  1   1   2022-04-21 08:53:36.79122   2022-04-21 08:53:36.79122
18  1   1   2023-02-27 07:34:04.423225  2023-02-27 07:34:04.423225
19  1   1   2023-05-31 02:50:56.048634  2023-05-31 02:49:41.244431

把除了数据之外的东西全删了,变成这样:

9   1   1   2021-06-03 013219.293484    2021-06-03 013219.293484
10  1   1   2021-06-18 031030.937604    2021-06-18 031030.937604
11  1   1   2021-11-10 072622.03843 2021-11-10 072622.03843
12  1   1   2022-04-21 084353.089246    2022-04-21 084353.089246
13  1   1   2022-04-21 084456.657448    2022-04-21 084456.657448
14  1   1   2022-04-21 084636.041996    2022-04-21 084636.041996
15  1   1   2022-04-21 084747.267276    2022-04-21 084747.267276
16  1   1   2022-04-21 084935.377544    2022-04-21 084935.377544
17  1   1   2022-04-21 085336.79122 2022-04-21 085336.79122
18  1   1   2023-02-27 073404.423225    2023-02-27 073404.423225
19  1   1   2023-05-31 025056.048634    2023-05-31 024941.244431
20  1   1   2023-07-26 003505.650939    2023-07-26 003505.650939
21  1   1   2023-07-26 074721.418794    2023-07-26 074721.418794
22  1   1   2023-07-28 020920.553142    2023-07-28 020915.254526
23  1   1   2023-07-28 020926.714814    2023-07-28 020926.714814
24  1   1   2023-07-28 020932.358786    2023-07-28 020932.358786
25  1   1   2023-07-28 020938.048105    2023-07-28 020938.048105
26  1   1   2023-07-28 020943.347591    2023-07-28 020943.347591
27  1   1   2023-07-28 020947.737791    2023-07-28 020947.737791

然后运行下面这个转换文件,转换为insert格式:java语言

注意修改文件路径.

package org.example;
​
import java.io.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
​
public class Main {
​
    public static void main(String[] args) {
        String inputFilePath = "C:\\Users\\wpy\\Desktop\\123.txt"; // 输入文件路径
        String outputFilePath = "C:\\Users\\wpy\\Desktop\\4.txt"; // 输出文件路径
        try {
            convertFileContent(inputFilePath, outputFilePath,"public","123");
            System.out.println("File content converted successfully.");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
​
    public static void convertFileContent(String inputFilePath, String outputFilePath, String schemaName, String tableName) throws IOException {
        ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
​
        try (BufferedReader reader = new BufferedReader(new FileReader(inputFilePath));
             BufferedWriter writer = new BufferedWriter(new FileWriter(outputFilePath))) {
​
            String line;
            AtomicInteger count = new AtomicInteger();
​
            while ((line = reader.readLine()) != null) {
                final String currentLine = line;
                executor.submit(() -> {
                    String[] parts = currentLine.split("\\s+");
                    int numParams = parts.length;
                    String regex = "\\d{4}-\\d{2}-\\d{2}";
                    Pattern pattern = Pattern.compile(regex);
​
                    if (numParams >= 2) {
                        StringBuilder values = new StringBuilder();
                        for (int i = 0; i < numParams; i++) {
//                            System.out.println(parts[i]);
                            if (i != 0) {
                                values.append(", ");
                            }
                            if (parts[i].equals("\\N")) {
                                values.append("null");
                                continue;
                            }
                            Matcher matcher = pattern.matcher(parts[i]);
                            if (matcher.matches()){
                                values.append("'").append(parts[i]+' '+parts[i+1]).append("'");
                                i++;
                            } else {
                                values.append("'").append(parts[i]).append("'");
                            }
                        }
                        String insertStatement = String.format(
                                "INSERT INTO \"%s\".\"%s\" VALUES (%s);",
                                schemaName, tableName, values.toString());
                        synchronized (writer) {
                            try {
                                writer.write(insertStatement);
                                writer.newLine();
                                count.getAndIncrement();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                });
            }
​
            executor.shutdown();
            try {
                executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
​
            System.out.println(count + " lines converted.");
        }
    }
}
​

然后在你指定的文件夹下得到了一个文件,结构类似于:

INSERT INTO "public"."123" VALUES ('17', '1', '1', '2022-04-21 085336.79122', '2022-04-21 085336.79122');
INSERT INTO "public"."123" VALUES ('16', '1', '1', '2022-04-21 084935.377544', '2022-04-21 084935.377544');
INSERT INTO "public"."123" VALUES ('23', '1', '1', '2023-07-28 020926.714814', '2023-07-28 020926.714814');
INSERT INTO "public"."123" VALUES ('15', '1', '1', '2022-04-21 084747.267276', '2022-04-21 084747.267276');
INSERT INTO "public"."123" VALUES ('10', '1', '1', '2021-06-18 031030.937604', '2021-06-18 031030.937604');
INSERT INTO "public"."123" VALUES ('24', '1', '1', '2023-07-28 020932.358786', '2023-07-28 020932.358786');
INSERT INTO "public"."123" VALUES ('20', '1', '1', '2023-07-26 003505.650939', '2023-07-26 003505.650939');
INSERT INTO "public"."123" VALUES ('22', '1', '1', '2023-07-28 020920.553142', '2023-07-28 020915.254526');
INSERT INTO "public"."123" VALUES ('11', '1', '1', '2021-11-10 072622.03843', '2021-11-10 072622.03843');
INSERT INTO "public"."123" VALUES ('19', '1', '1', '2023-05-31 025056.048634', '2023-05-31 024941.244431');
INSERT INTO "public"."123" VALUES ('18', '1', '1', '2023-02-27 073404.423225', '2023-02-27 073404.423225');
INSERT INTO "public"."123" VALUES ('12', '1', '1', '2022-04-21 084353.089246', '2022-04-21 084353.089246');
INSERT INTO "public"."123" VALUES ('9', '1', '1', '2021-06-03 013219.293484', '2021-06-03 013219.293484');
INSERT INTO "public"."123" VALUES ('14', '1', '1', '2022-04-21 084636.041996', '2022-04-21 084636.041996');
INSERT INTO "public"."123" VALUES ('21', '1', '1', '2023-07-26 074721.418794', '2023-07-26 074721.418794');
INSERT INTO "public"."123" VALUES ('13', '1', '1', '2022-04-21 084456.657448', '2022-04-21 084456.657448');
INSERT INTO "public"."123" VALUES ('26', '1', '1', '2023-07-28 020943.347591', '2023-07-28 020943.347591');
INSERT INTO "public"."123" VALUES ('25', '1', '1', '2023-07-28 020938.048105', '2023-07-28 020938.048105');
INSERT INTO "public"."123" VALUES ('27', '1', '1', '2023-07-28 020947.737791', '2023-07-28 020947.737791');

2.2.3 合并文件

把刚才导出的sql文件的表头复制进入这个文件的开头,最终的结果类似于:

 Source Schema         : public
​
 Target Server Type    : PostgreSQL
 Target Server Version : 110021
 File Encoding         : 65001
​
 Date: 31/08/2023 22:20:03
*/
​
​
-- ----------------------------
-- Table structure for auditlog_log_line
-- ----------------------------
DROP TABLE IF EXISTS "public"."auditlog_log_line";
CREATE TABLE "public"."auditlog_log_line" (
  "id" int4 NOT NULL DEFAULT nextval('auditlog_log_line_id_seq'::regclass),
  "create_uid" int4,
  "log_id" int4,
  "new_value_text" text COLLATE "pg_catalog"."default",
  "field_id" int4 NOT NULL,
  "write_uid" int4,
  "create_date" timestamp(6),
  "old_value_text" text COLLATE "pg_catalog"."default",
  "write_date" timestamp(6),
  "new_value" text COLLATE "pg_catalog"."default",
  "old_value" text COLLATE "pg_catalog"."default"
)
;
COMMENT ON COLUMN "public"."auditlog_log_line"."create_uid" IS 'Created by';
COMMENT ON COLUMN "public"."auditlog_log_line"."log_id" IS 'Log';
COMMENT ON COLUMN "public"."auditlog_log_line"."new_value_text" IS '更新后数据';
COMMENT ON COLUMN "public"."auditlog_log_line"."field_id" IS '字段名';
COMMENT ON COLUMN "public"."auditlog_log_line"."write_uid" IS 'Last Updated by';
COMMENT ON COLUMN "public"."auditlog_log_line"."create_date" IS 'Created on';
COMMENT ON COLUMN "public"."auditlog_log_line"."old_value_text" IS '旧数据';
COMMENT ON COLUMN "public"."auditlog_log_line"."write_date" IS 'Last Updated on';
COMMENT ON COLUMN "public"."auditlog_log_line"."new_value" IS '更新后数据';
COMMENT ON COLUMN "public"."auditlog_log_line"."old_value" IS '更新前数据';
COMMENT ON TABLE "public"."auditlog_log_line" IS 'Auditlog - Log details (fields updated)';
​
-- ----------------------------
-- Records of auditlog_log_line
-- ----------------------------
INSERT INTO "public"."123" VALUES ('17', '1', '1', '2022-04-21 085336.79122', '2022-04-21 085336.79122');
INSERT INTO "public"."123" VALUES ('16', '1', '1', '2022-04-21 084935.377544', '2022-04-21 084935.377544');
INSERT INTO "public"."123" VALUES ('23', '1', '1', '2023-07-28 020926.714814', '2023-07-28 020926.714814');
INSERT INTO "public"."123" VALUES ('15', '1', '1', '2022-04-21 084747.267276', '2022-04-21 084747.267276');
INSERT INTO "public"."123" VALUES ('10', '1', '1', '2021-06-18 031030.937604', '2021-06-18 031030.937604');
INSERT INTO "public"."123" VALUES ('24', '1', '1', '2023-07-28 020932.358786', '2023-07-28 020932.358786');
INSERT INTO "public"."123" VALUES ('20', '1', '1', '2023-07-26 003505.650939', '2023-07-26 003505.650939');
INSERT INTO "public"."123" VALUES ('22', '1', '1', '2023-07-28 020920.553142', '2023-07-28 020915.254526');
INSERT INTO "public"."123" VALUES ('11', '1', '1', '2021-11-10 072622.03843', '2021-11-10 072622.03843');
INSERT INTO "public"."123" VALUES ('19', '1', '1', '2023-05-31 025056.048634', '2023-05-31 024941.244431');
INSERT INTO "public"."123" VALUES ('18', '1', '1', '2023-02-27 073404.423225', '2023-02-27 073404.423225');
INSERT INTO "public"."123" VALUES ('12', '1', '1', '2022-04-21 084353.089246', '2022-04-21 084353.089246');
INSERT INTO "public"."123" VALUES ('9', '1', '1', '2021-06-03 013219.293484', '2021-06-03 013219.293484');
INSERT INTO "public"."123" VALUES ('14', '1', '1', '2022-04-21 084636.041996', '2022-04-21 084636.041996');
INSERT INTO "public"."123" VALUES ('21', '1', '1', '2023-07-26 074721.418794', '2023-07-26 074721.418794');
INSERT INTO "public"."123" VALUES ('13', '1', '1', '2022-04-21 084456.657448', '2022-04-21 084456.657448');
INSERT INTO "public"."123" VALUES ('26', '1', '1', '2023-07-28 020943.347591', '2023-07-28 020943.347591');
INSERT INTO "public"."123" VALUES ('25', '1', '1', '2023-07-28 020938.048105', '2023-07-28 020938.048105');
INSERT INTO "public"."123" VALUES ('27', '1', '1', '2023-07-28 020947.737791', '2023-07-28 020947.737791');

然后去数据库里执行这个sql文件,就可以正确的在pgsql里面导入所需要的数据.

3.进行迁移:

使用安装时达梦数据库自带的DM数据迁移工具进行迁移。

在左上角新建.

image-20230823220656100

迁移方式选择从pgsql到达梦。

image-20230823220815656

正确输入数据源pgsql相关连接信息。

image-20230823221004823

如果输入错误,则会报错导致无法进行下一步.

正确输入达梦数据库相关信息

image-20230823221023359

然后进入迁移选项,选择 “选择迁移对象”,迁移策略不用动,点击下一步。

image-20230823221250519

进入指定模式,此处选择的是需要迁移的表。

image-20230823221425937

如果选择的表中什么都没有,下一步什么都不会出现,如果表中有内容,则会出现这样

image-20230823221918088

可以在这里修改模式.

选择要迁移的对象,然后就会出现目的模式和对象。

image-20230823222242519

出现后,可以修改目的对象(即目的表中的表名).

如果是整张表迁移,可以直接点击下一步。

如果是按列进行迁移,则双击选中的这一行,点击出现设置表映射关系。

image-20230823224003051

选择列映射选项.

image-20230823235420347

如果只需要迁移部分列,只需要把不需要迁移的部分列进行删除。

注意,这样要求你选择的表上必须有一个数据格式符合条件的字段,名字无所谓.如果没有则会报错.

完成之后,会弹出审阅迁移任务界面

image-20230823235644642

没有问题可以点击完成进行

image-20230823235759057

大批量按列迁移截图: