记Cloudreve数据库迁移到PostgreSQL
发表于 2026-05-05 共 1104 字
分类于 记录

记Cloudreve数据库迁移到PostgreSQL

前言

我使用Cloudreve自建网盘,装好后数据库就默认用的是SQLite,随着数据的增加,我打算迁移到PostgreSQL上,以实现更好的性能。

遗憾的是,官方并没有给出不同数据库迁移的工具,那就只能自己尝试迁移了。

导出SQLite

为了保证数据一致性,操作前先把Cloudreve的进程终止了。

首先把SQLite的数据库文件找到,也就是在Cloudreve的data目录下的cloudreve.db文件。

我这里使用Navicat软件的数据传输工具,将其转成PostgreSQL的sql语句,得到data.sql,可以直接用文本编辑。

Navicat数据传输界面

sql格式调整

事实上,有了data.sql后还不能直接执行导入操作,因为存在着格式不同会报错。

这里需要手动编辑一下,首先有一些字段是boolean类型(都是"is_"开头的字段),但是值为0/1,对应到PostgreSQL应该是FALSE/TRUE。

我是用文本替换实现的(这里注意不要误伤,别把数值类型的0和1改了),其实也可以写个程序更快地处理。

其次是日期的格式问题,在SQLite中日期是存成类似2025-12-21 11:35:34.962063824 +0800 CST m=+91478.155786217的形式,而PostgreSQL中的TIMESTAMPTZ类型不能解析这种格式,会报错,因此要改为2025-12-21 11:35:34.962063824 +0800这种才行。

这里是耗时最久的部分,实际上我参照报错信息调了很久才终于不报错(

安装PostgreSQL

Ubuntu环境下,直接用apt安装一下:

sudo apt install postgresql postgresql-contrib

安装完成后可以这样执行两条命令,进入psql命令行:

sudo su - postgres
psql

之后改一下postgres账号的密码,new_password是新的密码:

ALTER USER postgres WITH PASSWORD 'new_password';

这样创建一下数据库:

CREATE DATABASE cloudreve;

如果要想让服务器外能访问数据库,还需要改一下监听绑定listen_addresses,并添加一下ip白名单,不再赘述。

修改数据库配置

修改Cloudreve的data目录下的conf.ini文件,加入Database的配置,使用我们之前创建的名为cloudreve的数据库:

[Database]
Type = postgres
Port = 端口号
User = postgres
Password = xxx
Host = 127.0.0.1
Name = cloudreve

迁移数据

修改数据库配置后,先启动一次Cloudreve来初始化一下数据库的结构。然后,终止Cloudreve,清空cloudreve数据库中所有数据表的数据。

这样做是为了确保PostgreSQL数据库表结构的正确性,这样我们就可以导入SQLite中的Records数据了,structure相关的sql语句就可以删掉不管了。

id_seq修正

迁移成功后启动Cloudreve,发现文件预览都没什么问题,但是尝试上传文件居然出问题了:

上传文件报错

这个报错说明,某一条数据的唯一索引在数据库中已存在,违反了唯一性约束。

按照AI的方法,需要批量修正各表的id_seq为最大id+1,下面的命令可以构造修正sql语句:

SELECT 'SELECT setval(' || quote_literal(quote_ident(s.relname)) || 
       ', COALESCE(MAX(' || quote_ident(c.attname) || '), 1)) FROM ' || 
       quote_ident(t.relname) || ';'
FROM pg_class s
JOIN pg_depend d ON d.objid = s.oid
JOIN pg_class t ON d.refobjid = t.oid
JOIN pg_attribute c ON (d.refobjid = c.attrelid AND d.refobjsubid = c.attnum)
WHERE s.relkind = 'S' AND t.relkind = 'r';

输出了以下内容,都执行一遍:

SELECT setval('direct_links_id_seq', COALESCE(MAX(id), 1)) FROM direct_links;
SELECT setval('entities_id_seq', COALESCE(MAX(id), 1)) FROM entities;
SELECT setval('fs_events_id_seq', COALESCE(MAX(id), 1)) FROM fs_events;
SELECT setval('metadata_id_seq', COALESCE(MAX(id), 1)) FROM metadata;
SELECT setval('oauth_clients_id_seq', COALESCE(MAX(id), 1)) FROM oauth_clients;
SELECT setval('oauth_grants_id_seq', COALESCE(MAX(id), 1)) FROM oauth_grants;
SELECT setval('passkeys_id_seq', COALESCE(MAX(id), 1)) FROM passkeys;
SELECT setval('shares_id_seq', COALESCE(MAX(id), 1)) FROM shares;
SELECT setval('tasks_id_seq', COALESCE(MAX(id), 1)) FROM tasks;
SELECT setval('settings_id_seq', COALESCE(MAX(id), 1)) FROM settings;
SELECT setval('nodes_id_seq', COALESCE(MAX(id), 1)) FROM nodes;
SELECT setval('storage_policies_id_seq', COALESCE(MAX(id), 1)) FROM storage_policies;
SELECT setval('groups_id_seq', COALESCE(MAX(id), 1)) FROM groups;
SELECT setval('users_id_seq', COALESCE(MAX(id), 1)) FROM users;
SELECT setval('dav_accounts_id_seq', COALESCE(MAX(id), 1)) FROM dav_accounts;
SELECT setval('files_id_seq', COALESCE(MAX(id), 1)) FROM files;

这样数据库迁移就宣告完成了。

筛选文章
类别选择 (分类/标签)
全屏 关闭