利用orm 在業務程式碼無感知下,實現實現分庫分表

探索者發表於2021-06-09

當資料多到一定的程度時,分表可作為一種提升效能的方案。
這裡以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 協議》,轉載必須註明作者和本文連結

相關文章