步骤一、安装Docker
- Windows11 安装Docker客户端教程:自己百度一下。
步骤二、SQLCipher解密,转换为Sqlite3
- 访问官网进行下载
- 使用DB Browser (SQLCipher) 客户访问数据库文件后,点开菜单栏 "工具" --> "设置加密",密码置空后,即可进行解密,自动将SQLCipher转换为Sqlite3。
- 注意:这个解密的过程耗时比较长,请耐心等待;
步骤三、将Sqlite中的数据迁移到PostgreSql中
1. Docker安装PostgreSql
bash
docker run --name my_postgres \
-e POSTGRES_PASSWORD=mysecretpassword \ # 设置超级用户密码,务必修改
-p 5432:5432 \ # 映射主机端口 5432 到容器端口 5432
-v pgdata:/var/lib/postgresql/data \ # 使用命名卷 pgdata 持久化数据
-d \ # 后台运行容器
postgres # 使用官方镜像
-e POSTGRES_PASSWORD=mysecretpassword
: 务必修改mysecretpassword
为你自己设定的强密码,这是默认的超级用户postgres
的密码。-v pgdata:/var/lib/postgresql/data
: 这里的pgdata
是 Docker 管理的命名卷(Named Volume) 的名称。如果该卷不存在,Docker 会自动创建它。数据会存储在 Docker 的管理区域(例如/var/lib/docker/volumes/
),与容器生命周期分离,从而实现持久化。- 使用
docker volume ls
可以查看所有已创建的命名卷。 - 增加
--restart=unless-stopped
可以自动启动容器,除非手动停止。
2. 拉取pgloader镜像
bash
docker pull ghcr.io/dimitri/pgloader:latest
3. 准备迁移脚本 migration.load
bash
LOAD DATABASE
FROM sqlite:////data/main_data.db
INTO postgresql://postgres:123456@host.docker.internal:5432/main
WITH include drop, create tables, create indexes, reset sequences, foreign keys,
workers = 8, concurrency = 1
ALTER SCHEMA 'main' RENAME TO 'public'
BEFORE LOAD DO
$$ create schema if not exists public; $$;
🔔 参数说明:
-
FROM
: SQLite 源数据库连接字符串。这里使用了sqlite:///
前缀,后接文件路径。请注意,即使SQLite数据库有密码(你连接字符串中的Password=E32CE1F29B6745F984DA86FBC0159F9F
),pgloader对SQLite的支持目前可能不直接支持通过连接字符串传递密码 。你可能需要先使用SQLite工具解密数据库或寻找其他方法(如临时移除密码)再进行迁移。/
是路径分隔符,D:/NewData/main_data.db
是你的数据库文件路径。 -
INTO
: PostgreSQL 目标数据库连接字符串。格式为postgresql://username:password@host:port/database_name
。 -
WITH
子句:include drop
: 迁移前删除目标数据库中已存在的同名表(⚠️谨慎使用,会清除现有数据! 如果scan_spec
数据库是新创建的或可清空,则使用此选项;若需保留现有数据,请移除此选项)。create tables
: 在PostgreSQL中创建表。create indexes
: 创建索引。reset sequences
: 重置序列(例如自增主键的序列)。foreign keys
: 创建外键约束。workers = 8
: 使用8个工作线程加速迁移(可根据CPU核心数调整)。concurrency = 1
: 控制并发度。
-
ALTER SCHEMA
: SQLite 没有模式概念,其表通常可视为在main
模式中。此命令在迁移后将模式名改为 PostgreSQL 默认的public
。 -
BEFORE LOAD DO
: 迁移前执行的 SQL 语句,这里确保public
模式存在。
4. 执行迁移
使用 Docker 运行 pgloader
并执行迁移脚本。注意将 /path/to/your/migration.load
替换为你实际的 migration.load
文件的绝对路径。/path/to/your/data
替换为你实际的 db 文件的所在目录。
bash
docker run --rm -v /path/to/your/migration.load:/migration.load -v /path/to/your/data:/data ghcr.io/dimitri/pgloader:latest pgloader /migration.load
🔔 命令说明:
-
--rm
: 容器退出后自动删除。 -
-v /path/to/your/migration.load:/migration.load
: 将宿主机上的加载脚本挂载到容器内。 -
-v /path/to/your/data:/data
: 将包含你 SQLite 数据库文件的目录挂载到容器内的/data
目录,确保容器内的 pgloader 能访问到/path/to/your/data/main_data.db
文件(因此在.load文件中,路径可以写为sqlite:////data/main_data.db
,但上述脚本已使用宿主机绝对路径,此挂载是为了保证一致性)。 -
ghcr.io/dimitri/pgloader:latest
: pgloader 的 Docker 镜像。 -
pgloader /migration.load
: 在容器内运行的命令,执行迁移脚本。
步骤四、特别注意
由于 Pgloader 在将 SQLite 的 INTEGER
类型(在 SQLite 中通常用来表示布尔值,0 或 1)迁移到 PostgreSQL 时,将它映射成了 PostgreSQL 的 BIT
类型,而不是 BOOLEAN
或 INTEGER
。PostgreSQL 的 BIT
类型是位字符串类型,它和 INTEGER
类型无法直接进行 =
比较。所以当你执行 "isdelete" = 0
时,PostgreSQL 就会报错,提示找不到一个可以比较 BIT
和 INTEGER
的操作符。报错信息如下:
SQL 错误 [42883]: ERROR: operator does not exist: bit = integer
Hint: No operator matches the given name and argument types. You might need to add explicit type casts.
所以我们需要将数据库中所有bit(1)
类型的字段转换成boolean
类型,但是PostgreSql中这两个类型不能直接转换,所以要先将bit(1)
先转成 integer
再转成 boolean
。下面是一个可以完成这个任务的 PostgreSQL PL/pgSQL 代码块。你可以将其作为一个匿名代码块 (DO
语句) 在 psql 或任何 PostgreSQL 客户端中运行。
SQL
DO $$
DECLARE
rec RECORD;
table_name TEXT;
column_name TEXT;
alter_sql TEXT;
BEGIN
-- 遍历数据库中所有表的模式(public)
FOR rec IN
SELECT
c.table_schema,
c.table_name,
c.column_name
FROM
information_schema.columns c
WHERE
c.table_schema = 'public' -- 只在 public 模式下查找,可以根据需要更改
AND c.data_type = 'bit'
AND c.character_maximum_length = 1
LOOP
table_name := rec.table_name;
column_name := rec.column_name;
RAISE NOTICE '正在处理表: %, 列: %', table_name, column_name;
-- 构造 ALTER TABLE 语句,先转成 integer
alter_sql := format('ALTER TABLE %I.%I ALTER COLUMN %I TYPE INTEGER USING %I::integer;',
rec.table_schema, table_name, column_name, column_name);
-- 执行 SQL
EXECUTE alter_sql;
-- 构造 ALTER TABLE 语句,再转成 boolean
alter_sql := format('ALTER TABLE %I.%I ALTER COLUMN %I TYPE BOOLEAN USING %I::boolean;',
rec.table_schema, table_name, column_name, column_name);
-- 执行 SQL
EXECUTE alter_sql;
END LOOP;
RAISE NOTICE '所有 bit(1) 字段转换完成。';
END $$;
到此,SQLite的数据已经全部迁移到PostgreSql啦~