ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

LLDAP 数据库后端迁移实战:从 SQLite 平滑切换至 PostgreSQL / MySQL / MariaDB

2026/10/8 8:06:42 拓冰建站 浏览量
LLDAP 数据库后端迁移实战:从 SQLite 平滑切换至 PostgreSQL / MySQL / MariaDB 后端认证鉴权【免费下载链接】lldapLight LDAP implementation项目地址https://gitcode.com/gh_mirrors/ll/lldap点击查看免费下载LLDAP 是一款轻量级 LDAP 实现其数据默认存储在 SQLite 数据库中适合中小规模部署但当你需要更高并发、更强的备份恢复能力或与既有数据库基础设施统一管理时就需要把数据从 SQLite 迁移到 PostgreSQL、MySQL 或 MariaDB。本文以 docs/database_migration.md 为骨架完整讲解建库 → 停机导出 → 数据清洗 → 导入 → 切换配置五步迁移流程并结合仓库源码create_schema命令实现、SQL 建表逻辑、数据库 URL 解析与官方辅助脚本scripts/sqlite_dump_commands.sh让你能安全、可回滚地完成数据库后端切换。迁移总体思路与适用前提迁移的本质是数据搬运 格式转换LLDAP 各数据库后端共享同一套表结构由 SQL 迁移逻辑统一维护因此只要目标数据库里建好空表再把旧库数据以 INSERT 语句的形式灌入即可。官方文档给出的迁移流程共五步在目标数据库上创建空 schema表结构停止/暂停 LLDAP导出既有数据针对目标数据库做数据清洗并非总是需要将数据导入目标库修改 LLDAP 配置指向新库并重启文档明确指出后续步骤假设你已经为 LLDAP 准备好了一个空数据库实例PostgreSQL 或 MySQL迁移前无需向其中预置任何表——表结构由 LLDAP 自己创建。小贴士如果目标是 PostgreSQL官方文档推荐优先考虑 pgloader 这类专门工具它可以从多种数据库自动迁移到 PostgreSQL本文的手工流程更适合 MySQL/MariaDB 或需要精细控制的情况。第一步在目标数据库创建 schemaLLDAP 提供了专用的 CLI 子命令create_schema它会连接目标数据库并初始化表结构。该命令的实现位于 server/src/main.rsasync fn create_schema_command(opts: RunOpts) - Result() { let config configuration::init(opts)?; let sql_pool setup_sql_tables(config.database_url).await?; info!(Schema created successfully.); ... }可以看到它复用了服务启动时相同的setup_sql_tables逻辑因此创建出的表结构与正式运行时完全一致。命令注册在 server/src/cli.rs子命令名为create_schema接收一个-d/--database-url参数对应环境变量LLDAP_DATABASE_URL。如果使用 Docker 部署推荐直接在正在运行的容器内执行这样能保证容器内网络可以访问到目标数据库docker exec -it LLDAP container name /app/lldap create_schema -d Target database url例如docker exec -it lldap /app/lldap create_schema -d postgres://lldap_user:passwordpostgres-server/lldap执行成功后日志会输出Schema created successfully.此时可以进入下一步。若失败请检查目标数据库连接串、权限需要建表权限以及网络连通性。schema 背后统一的建表逻辑从源码看LLDAP 各数据库后端共用 crates/sql-backend-handler/src/sql_tables.rs 中的init_table见该文件第 44 行起与一系列迁移语句例如用户表、组表、成员关系表、属性表等。其中groups表使用自增主键CREATE TABLE groups ( group_id INTEGER PRIMARY KEY, display_name TEXT );而metadata表专门记录 schema 版本version INTEGER用于启动时的自动迁移判定见 sql_tables.rs。这正是后续清洗步骤中需要特别处理groups.group_id自增序列的原因详见下文 PostgreSQL 小节。第二步导出既有数据停机导出导出的目标是生成一份只包含 INSERT 语句的 SQL 文件。有两类表需要排除metadata表它是 LLDAP 内部的 schema 版本管理表目标库已由create_schema建好无需迁移sqlite_sequence表仅当它存在时SQLite 的自增序列内部表。同时导出前务必停止/暂停 LLDAP文档明确指出如果 LLDAP 正处于写入状态某些数据库如 SQLite在 dump 时会直接报错。这与 SQLite 的写锁机制有关停机导出能保证数据快照的一致性。仓库提供了辅助脚本 scripts/sqlite_dump_commands.sh它按表输出.mode insert与select *命令配合 sqlite3 即可生成带INSERT INTO table VALUES (...)语句的 dump./sqlite_dump_commands.sh | sqlite3 /path/to/lldap/config/users.db /path/to/dump.sql脚本覆盖的表清单导出顺序即如下顺序users、groups、memberships、jwt_refresh_storage、jwt_storage、password_reset_tokens、group_attribute_schema、group_attributesuser_attribute_schema但排除内置的first_name、last_name、avatar三个属性它们由 LLDAP 在启动时自动重建无需迁移user_attributes用户的自定义属性值脚本开头还有一行.header on用于让 sqlite3 的.mode insert生成带列名的 INSERT 语句便于后续 sed 清洗时精确匹配表名。注意该脚本面向 SQLite 场景。若从 MySQL/PostgreSQL 迁移导出思路相同仅导出 INSERT 排除 metadata 表但导出命令需换成对应数据库的 dump 工具并同样先停止 LLDAP。第三步数据清洗SanitizeSQLite 导出的 INSERT 语句不一定能直接被 PostgreSQL/MySQL 接受差异主要集中在十六进制字符串语法PostgreSQL 与 SQLite 的 hex 字面量写法不同表名转义方式MySQL 用反引号而非双引号布尔值写法1/0与true/false的差异时间格式MariaDB 的 DATETIME 不支持时区偏移后缀事务包裹建议把全部 INSERT 包在一个事务里避免中途失败产生半截数据。官方针对三种目标数据库给出了三份sed -i清洗命令下面逐一说明。迁移到 PostgreSQLsed -i -r -e s/X([[:xdigit:]][^])/\\\x\\1/g \ -e :a; s/(INSERT INTO (user_attribute_schema|jwt_storage)\(.*\) VALUES\(.*),1([^]*\);)$/\1,true\3/; s/(INSERT INTO (user_attribute_schema|jwt_storage)\(.*\) VALUES\(.*),0([^]*\);)$/\1,false\3/; ta \ -e 1s/^/BEGIN;\n/ \ -e $aSELECT setval(pg_get_serial_sequence(\groups\, \group_id\), COALESCE((SELECT MAX(group_id) FROM groups), 1)); \ -e $aCOMMIT; /path/to/dump.sql这条命令依次做了四件事hex 格式转换把 SQLite 的XABCD形式转换为 PostgreSQL 的\xABCD形式g全局替换sed -i原地修改文件布尔值重写对user_attribute_schema与jwt_storage两张表的 INSERT把行尾的,1换成,true、,0换成,false:a; ...; ta循环确保替换到稳定为止。这两张表包含布尔列而 PostgreSQL 不接受整型1/0作为布尔值在文件头部插入BEGIN;将全部插入包进一个事务任何一条语句失败都可整体回滚文件尾部追加序列校正 COMMIT;groups.group_id在 PostgreSQL 中由序列serial生成直接插入显式 id 不会推进序列后续 LLDAP 新建组时会主键冲突。因此用setval把groups_group_id_seq调整到当前最大值。这与上文提到的groups表INTEGER PRIMARY KEY结构直接相关。迁移到 MySQLsed -i -r -e s/^INSERT INTO ?([a-zA-Z0-9_])?/INSERT INTO \1/ \ -e 1s/^/START TRANSACTION;\n/ \ -e $aCOMMIT; \ -e 1 i\SET FOREIGN_KEY_CHECKS 0; /path/to/dump.sqlMySQL 的差异点与处理表名反引号SQLite 生成的INSERT INTO groups (...)使用了双引号而 MySQL 需要用反引号转义表名。特别注意groups是 MySQL 的保留字不转义会直接报语法错误。该规则对全部表名生效事务包裹头部加START TRANSACTION;尾部加COMMIT;临时关闭外键检查第一行插入SET FOREIGN_KEY_CHECKS 0;避免按依赖顺序插入如先插 groups 再插 memberships时因外键约束报错导入完成后随COMMIT恢复默认行为。迁移到 MariaDBsed -i -r -e s/([^][0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{9})\00:00([^])/\1\2/g \ -e s/^INSERT INTO ?([a-zA-Z0-9_])?/INSERT INTO \1/ \ -e 1s/^/START TRANSACTION;\n/ \ -e $aCOMMIT; \ -e 1 i\SET FOREIGN_KEY_CHECKS 0; /path/to/dump.sqlMariaDB 与 MySQL 基本兼容但不支持 DATETIME 字符串上的时区偏移如2026-10-07T02:18:03.12345678900:00尾部的00:00因此先通过正则把形如...99999999900:00的时区后缀去掉再执行与 MySQL 相同的反引号、事务与外键处理。使用sed -i会直接改写原 dump 文件建议先对 dump.sql 做一次备份便于出错后重来。第四步导入目标数据库把清洗后的 dump 文件导入目标库官方给出了两种主流客户端的标准做法。导入 PostgreSQLpsql -d database -U username -W /path/to/dump.sql或使用-f参数指定文件-W会在连接时提示输入密码psql -d database -U username -W -f /path/to/dump.sql如果遇到报错常见原因有某行数据的格式仍未兼容可手动微调该行、导入中途失败导致部分数据进入因为有事务包裹整体回滚后修好 dump 重导即可、或序列未同步检查上一步的setval是否正确追加。导入 MySQLmysql -u username -p database /path/to/dump.sql如果出现错误官方建议两种处理路径手动调整 dump 中出问题的语句或者先在 LLDAP 界面/API 中修正对应数据再重新导出例如某条属性值格式异常直接在 LLDAP 里改掉后重新走一遍 dump 流程。第五步切换配置并重启导入成功后把 LLDAP 的数据库连接指向新库——注意必须与第一步创建 schema 时使用的 URL 完全一致。配置位置有两种等价方式配置文件中的database_url字段环境变量LLDAP_DATABASE_URL优先级覆盖配置文件。参考 lldap_config.docker_template.toml 中给出的 URL 格式## - postgres://postgres-user:passwordpostgres-server/my-database ## - mysql://mysql-user:passwordmysql-server/my-database # database_url sqlite:///data/users.db?moderwc # SQLite 默认 database_url postgres://lldap_user:passwordpostgres-server/lldap修改后重启 LLDAP并检查日志确认启动过程中没有数据库相关错误重点关注连接失败、表缺失、主键冲突等。启动正常后建议做一轮功能冒烟验证登录管理界面、查询用户列表、用 LDAP 客户端做一次 bind确认读写都正常。连接串解析的实现细节database_url在 server/src/database_string.rs 中被封装为DatabaseUrl类型它基于标准 URL 解析通过 URL 的 schemesqlite/postgres/mysql判断后端类型db_type()方法。该类型还做了密码脱敏处理——调试输出时密码会被替换为***PASSWORD***见该文件第 26-37 行避免日志泄露凭据。因此迁移切换后若日志中打印了连接串密码也会以掩码形式出现属于正常现象。迁移后的验证清单与回滚无论目标库是 PostgreSQL 还是 MySQL/MariaDB迁移完成后都建议按以下清单复核用户与组数量一致对比旧库与新库中users、groups、memberships的行数自定义属性完整确认user_attribute_schema非内置属性与user_attributes数据无丢失认证可用用任意用户执行一次 LDAP bind确认密码校验正常密码以加盐形式存储迁移过程不涉及密码解密直接搬运即可组创建正常新建一个测试组验证自增主键/序列没有冲突对应 PostgreSQL 的setval步骤是否生效JWT 会话jwt_storage、jwt_refresh_storage已迁移但若更换了jwt_secret/key_seed会话与密码校验会被重置请确认未误改相关配置。由于旧库在迁移前只是暂停而非销毁回滚非常简单把database_url改回旧库并重启即可。这也是官方流程先建新库、再切换设计的好处——确认新库完全正常前旧库始终是可用的退路。最后官方文档还提示更完整的端到端示例可参考仓库 CI 流程中的lldap-database-migration-test作业它会在构建流水线中实际执行建 schema → 导出 → 清洗 → 导入 → 切换的全过程是验证本文各命令可用性的最佳参考实现。赞分享后端认证鉴权【免费下载链接】lldapLight LDAP implementation项目地址https://gitcode.com/gh_mirrors/ll/lldap点击查看免费下载相关推荐Mailu 数据库后端切换指南从 SQLite 迁移到 PostgreSQL 与 MySQL/MariaDBMailu 数据库后端切换指南从 SQLite 迁移到 PostgreSQL 与 MySQL/MariaDB 导读 Mailu 是一套以 Docker 镜像形后端通信BTCPay Server 数据库迁移实战从 SQLite / MySQL 平滑迁移到 PostgreSQLBTCPay Server 数据库迁移实战从 SQLite / MySQL 平滑迁移到 PostgreSQL 导读 BTCPay Server 曾长期同时支持区块链金融科技后端LLDAP项目数据库迁移完整指南从SQLite到PostgreSQL/MySQLLLDAP项目数据库迁移完整指南从SQLite到PostgreSQL/MySQL 前言 在轻量级目录访问协议 LLDAP 项目的实际部署中随着业务规模的增长后端认证鉴权上一篇抖音内容下载新范式如何用开源工具构建个人数字资产库下一篇抖音批量下载器终极指南5分钟学会无水印视频保存技巧创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考