如何使用Eloquent编写支持MariaDB系统版本控制的查询
基于Eloquent实现MariaDB系统版本化历史查询的落地方案
- 若使用 Laravel 9.18 及以上版本,框架已原生内置对MariaDB系统版本控制(时态表)的查询语法支持,无需拼接整段原生SQL。
对应等价查询可直接调用查询构造器内置的forAllTime()方法,Eloquent模型、DB门面场景均可直接使用:
该方法生成的SQL与你原本编写的// 基于Address模型(对应addresses表)的查询写法 $addressHistory = Address::query() ->forAllTime() ->where('id', $id) ->get(); // 基于DB查询构造器的等价写法 $addressHistory = DB::table('addresses') ->forAllTime() ->where('id', $id) ->get();SELECT * FROM addresses FOR SYSTEM_TIME ALL WHERE id = ?完全等价,框架会自动完成数据库语法适配,同时自动对查询参数做绑定处理,避免此前直接将$id拼接进SQL字符串带来的SQL注入风险。
除查询全量历史版本外,框架还内置了其他常用的时态查询方法,覆盖不同历史数据查询场景:- 查询指定时间点的表版本:调用
forPointInTime($timestamp)方法,自动生成FOR SYSTEM_TIME AS OF 对应时间戳的语法 - 查询指定时间区间内的所有版本记录:调用
forTimeBetween($startTime, $endTime)方法,自动生成FOR SYSTEM_TIME BETWEEN 开始时间 AND 结束时间的语法
- 查询指定时间点的表版本:调用
- 若使用的Laravel版本低于9.18,无上述内置方法,也无需全程手写原生SQL,可通过查询构造器宏自定义封装对应方法,复用查询逻辑:
首先在App\Providers\AppServiceProvider的boot方法中注册宏:
注册完成后,可在任意查询中直接调用该自定义方法,使用体验与内置方法完全一致,同样会自动完成参数绑定,无需手动拼接SQL字符串。use Illuminate\Database\Query\Builder; Builder::macro('forAllSystemTime', function () { // 为主表添加系统时间全量查询语法 $this->from = $this->from . ' FOR SYSTEM_TIME ALL'; // 为关联的join表同步添加对应语法 $this->joins = collect($this->joins)->map(function ($joinClause) { $joinClause->table = $joinClause->table . ' FOR SYSTEM_TIME ALL'; return $joinClause; })->all(); return $this; }); - 绑定了系统版本控制的表,Eloquent模型默认执行的查询会自动过滤为当前生效的最新版本,与普通表的查询体验无差异,仅当主动调用上述历史查询方法时,才会拉取全量历史版本数据,无需额外在模型中编写特殊适配代码。
内容的提问来源于stack exchange,提问作者ayano
相关产品推荐
相关产品推荐

