利用orm 在业务代码无感知下,实现实现分库分表

当数据多到一定的程度时,分表可作为一种提升性能的方案。
这里以 sku 表为列子,分表的后并不用修改任何业务逻辑:
商品表:goods,sku 表:sku, 根据 good_id 取余数来分表。
原始语句

GoodModel::with('sku')->limit(10)->findAll();

这里用的 with 关联查询。分库分表往往涉及到改动的可能就是这种关联的地方,直接操作 sku 表都比较简单,这不介绍了,通过 orm 前置事件修改表名就可以了。

上面这是一对多,一个商品有多个 sku hasMany,这里其实只需要把一对多改成多态一对多就好了,上面的查询语句不用任何改动。orm 的完整配置
sku 模型

class Sku extends Model
{
    const TABLE = 'sku_';

    // 分表的数量
    const TABLE_COUNT = 7;

   //  这通过get前置事件,设置表名
   // 其他增加,更改,删除都有相应的前置事件 同理
    public function onBeforeGet($result, $args)
    {
        foreach ($result->getModelWhere() as $val) {
            if ($val[0] === 'good_id') {
                $result->from(self::TABLE . ($val[2][0] % self::TABLE_COUNT));
                return;
            }
        }
        // 这里处理条件里面没有good_id的情况
        // 抛出错误 条件里面必须要带 good_id
    }
}

goods 模型

class Goods extends Model
{
    const TABLE = 'goods';


    // 要用多态的关系,这里没有type字段,创建type虚拟字段,根据id取余数
    public function onAfterGet($result, $args)
    {
        if (is_array($result)) { // findAll 的情况
            foreach ($result as $v) {
                $v->type = $v->id % Sku::TABLE_COUNT;
            }
        }else{ // find 的情况
            $result->type = $result->id % Sku::TABLE_COUNT;
        }
    }

    // 把关联关系一对多 改成多态一对多
    function sku()
    {
        return $this->morphMany(
            array_fill(0, Sku::TABLE_COUNT, Sku::class),
            array_fill(0, Sku::TABLE_COUNT, 'good_id'),
            'type', 'id');
    }
}

好了,完整的修改就完成了。这里只配置查询的前置事件 onBeforeGet, 同样把 onBeforeDeleteonBeforeInsert,onBeforeUpdate 配置完成。业务调用层无任何改动就支持分表了。分表的数量也可以随时调整。
这里使用的是 one 框架自带的 orm 模型 github.com/lizhichao/one

如果需要分库 $result->from() 改成 $result->setConnection($key)->... 就好了

本作品采用《CC 协议》,转载必须注明作者和本文链接
本帖由系统于 3年前 自动加精
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 15

楼主指导一下 ORM 事件的前置呗,我 laravel 文档中我没找到 :sob:

3年前 评论

@jackven 这里用的是 one 的 orm ,前置事件叫 onBeforeGet。laravel 应该也有 如果没有 或者自己可以重写一下 build 添加一个

3年前 评论
jackven 3年前

onAfterGet 这个方法 Laravel ORM 本身是不支持的吧? 我记得当初用 TP6 的时候,我们做分库分表我也是想到了这种的思路。但是没有找到类似的方法。

3年前 评论
jackven 3年前

@白小白 恩 默认好像是没有 ,需要自己重写一下 。one 自带有 【增 、删、改、查 】 * 【前置 、后置 】 共 8 个事件,用这个可以做很多事情,分库分表、读写分离 ……

3年前 评论
WhiteDragon 3年前

建议直接充钱腾讯云的 tdsql :stuck_out_tongue_winking_eye:

3年前 评论

@largezhou 用云服务是要省很多事,有问题找他们就是了

3年前 评论

mycat 不方便很多

3年前 评论

mark 一下,减少了不少代码量

3年前 评论

有封装好的 composer 包可以直接使用嘛?

3年前 评论
探索者 (楼主) 3年前

one 自带 已经封装好来的 github.com/lizhichao/one

3年前 评论

很棒! mark !

2年前 评论