Merql
纯 PHP 三方数据库合并,支持列级冲突解决。将 Git 风格的合并语义应用于 MySQL 和 SQLite 表。
composer require merql/merql最新版本 v0.4.1 MIT PHP 8.2+
use Merql\Merql;
Merql::init($connection);
// Snapshot all tables.
$snapshot = Merql::snapshot('baseline');
// Snapshot specific tables.
$snapshot = Merql::snapshot('baseline', ['posts', 'comments', 'users']);实践应用
合并会读取三个已保存的快照,并返回要写入的操作和要解决的冲突。
合并三个快照
在两个副本发生分歧前创建 base 快照,然后分别为两侧创建快照,例如线上数据库和沙盒副本。ThreeWayMerge 会将双方与 base 进行比较,并合并两个变更集。
在结果标签页中,ours 编辑了同一行的 content,theirs 编辑了 title 和 status,因此合并会保留全部三项更改,不会产生冲突。
use Merql\Merge\ThreeWayMerge;
$merge = new ThreeWayMerge();
$result = $merge->merge($base, $ours, $theirs);
echo $result->operationCount(); // resolved operations
echo $result->conflictCount(); // unresolved conflictsBase: { title: "Hello", content: "Body", status: "draft" }
Ours: { title: "Hello", content: "Body v2", status: "draft" }
Theirs: { title: "New Title", content: "Body", status: "publish" }
Result: { title: "New Title", content: "Body v2", status: "publish" }三方合并
基线、我方、对方。采用 git 风格的三方合并,处理带键的数据库行和列,而非文本行。检测两个分支中的插入、更新和删除。
列级解决
双方更改同一行时,merql 会逐列比较。只有同一列被改为不同值时才会发生冲突。
可选的单元格合并
将 CellMergeConfig 传给 ThreeWayMerge 后,TEXT 列会使用 Myers diff 逐行合并,JSON 列则按键合并。Merql 门面和 CLI 不会启用此功能。
多数据库支持
提供可插拔的连接适配器和方言驱动,并内置 MySQL 和 SQLite。
冲突检测
更新对更新、更新对删除、删除对更新,以及插入对插入,都会连同表和行一起报告。更新对更新的冲突还会指出列名。
SQL 生成
使用参数化 INSERT、UPDATE、DELETE 语句,并按外键关系排序。可在事务中预览或应用更改。
CLI
通过命令行创建快照、比较和合并。可通过环境变量使用 MySQL 和 SQLite。
经过测试
包含 32 个带有手写预期结果的回归场景(composer test:oracle)。CI 会运行 231 单元测试和集成测试,并检查 PHPStan 10 级标准。
为什么选择 Merql
快照以文件形式保存
每个快照都是一个 JSON 文件,可以在机器间复制,也可以提交到版本控制中。比较和合并会读取这些文件,因此无需连接数据库即可运行。
写入前先审查
合并计划会为每个操作和变更组分配稳定 ID,并保留 base、ours、theirs 和结果行。选择所需分组后,只应用这些分组。
过期计划会停止执行
受保护的应用只会写入仍与所审查快照匹配的行。如果语句影响了零行,事务就会回滚,结果中也会包含错误信息。
通过漂移检查进行回滚
在写入前,根据实时行构建回滚计划,并将其保存为 JSON。撤销之前,漂移检查会比较行指纹,并返回自此之后发生变化的行对应的操作。
对比
Merql 会合并三个快照中的行数据。这些工具用于数据库版本管理、同步或迁移,处理的是相邻领域的任务。
| 工具 | 擅长领域 | 与 Merql 的区别 |
|---|---|---|
| Dolt | 擅长领域Dolt 是一个 SQL 数据库,你可以像操作 Git 仓库一样对它进行分叉、克隆、创建分支、合并、推送和拉取。连接方式与任何 MySQL 数据库相同,并会追踪每个单元格的沿袭关系。 | 与 Merql 的区别Merql 保留你已在使用的 MySQL 或 SQLite 数据库。它将表保存为 JSON 快照文件,并合并其中三个快照,base 快照由你选择。 |
| pt-table-sync | 擅长领域pt-table-sync 会查找并修复 MySQL 表之间的差异,支持单向同步,也支持服务器间双向同步。同步副本时,它会在复制源上进行更改。 | 与 Merql 的区别在双向同步中,pt-table-sync 会根据冲突列选出胜出行并复制其值。Merql 则会将双方与共同的 base 进行比较,合并同一行不同列上的编辑,并将不兼容的更改报告为冲突,供你解决。 |
| sqldiff | 擅长领域sqldiff 会比较两个 SQLite 数据库,并输出将第一个数据库转换为第二个数据库的 SQL 脚本。它还可以为 SQLite 会话扩展写入二进制变更集,或按表汇总已更改的行。 | 与 Merql 的区别双向差异比较无法判断一侧是新增了行,还是另一侧删除了行。Merql 会添加 base 快照来回答这个问题、合并两组更改,并且也支持 MySQL。 |
| Doctrine Migrations | 擅长领域Doctrine Migrations 会管理数据库架构的版本,因此可以在部署到生产环境之前审查并测试架构更改。 | 与 Merql 的区别Merql 不是架构迁移工具。它会合并行数据,并报告快照之间新增或删除的列,由你负责处理架构更改。 |
问答
来自 Merql 文档的简明解答。
通过 PDO 或 mysqli 适配器支持 MySQL 和 SQLite。对于其他引擎,你可以编写一个实现 Driver 接口的类,并通过 DriverFactory::register() 注册该类。
不是。它不会迁移架构、复制数据库,也不会实时同步数据库。给定三个数据库状态后,它会生成合并后的第四个状态,并指出其中的冲突。
如果双方将同一行的同一列改为不同值,一方更新了另一方已删除的行,或者双方使用相同的键插入同一行,就会发生冲突。同一行不同列上的编辑可以顺利合并。
不需要。它们会读取已保存的快照文件,因此只有创建快照和应用结果时才需要连接数据库。
可以。创建合并计划,按 ID 选择变更组,然后将所选内容转换为干净的结果,供 Merql::apply() 或 Merql::applyGuarded() 使用。
只有在构造 ThreeWayMerge 时传入 CellMergeConfig(例如 CellMergeConfig::auto()),主动启用后才会进行。Merql::merge()、Merql::plan() 和 CLI 会将每个列值视为一个整体。
跟随指南,从第一个快照开始,逐步了解合并计划、受保护的应用和回滚。