Yii2 自动分表 model

来源:互联网 发布:tensorflow 人脸比对 编辑:程序博客网 时间:2024/05/17 20:35

其实是借鉴了一下某同学的《动态model》

<?php/** * Created by IntelliJ IDEA. * User: Septan * Date: 2017/8/4 * Time: 下午5:25 */namespace app\library;use Yii;use yii\base\InvalidCallException;use yii\base\InvalidConfigException;use yii\db\ActiveQuery;use yii\db\Exception;use yii\helpers\ArrayHelper;/** * 分表基础类 * Class Modelx * @package library */class Modelx extends \yii\db\ActiveRecord{    //原始表名,表结构母版    protected static $originalName = '';    //动态表名    protected static $tableName = '';    //分表关键字    protected static $targetKey = '';    //redis表名set key    protected static $tableSetKey = '';    /**     * @param null $targetKey     * @param array $config     * @throws Exception     */    public function __construct($targetKey = null, $config = []){        parent::__construct($config);        static::$tableName = static::renderTable($targetKey);    }    public static function tableName(){        return static::$tableName;    }    /**     * 根据关键值获得表名     * @throws Exception     * @return string     */    public static function getTableName(){        throw new Exception(get_called_class() . "::" . __FUNCTION__ . ' must be override');        //return static::$originalName . '_'. (static::$targetKey % 10);    }    /**     * 根据vip_card探测表名     * @param null $targetKey     * @return string     * @throws Exception     */    public static function renderTable($targetKey = null){        if(!$targetKey)            return static::$originalName;        static::$targetKey = $targetKey;        $tableName = static::getTableName();        //if hit cache        /** @var \Redis $redis */        $redis = Yii::$app->redis;        if($redis->sismember(static::$tableSetKey, $tableName))            return $tableName;        //if hit db        $db = static::getDb();        if($db->createCommand("SHOW TABLES LIKE '{$tableName}'")->queryAll()){            $redis->sadd(static::$tableSetKey, $tableName);            return $tableName;        }else{ //maybe            $redis->srem(static::$tableSetKey, $tableName);        }        //just do it        $originalTable = static::$originalName;        $createTableRet = $db->createCommand("SHOW CREATE TABLE `{$originalTable}`")->queryOne();        $createTable = str_replace("`{$originalTable}`","`{$tableName}`",$createTableRet['Create Table']);        $createTable = preg_replace('/\sAUTO_INCREMENT=\d+/','',$createTable);        try{            $db->createCommand($createTable)->execute();            $redis->sadd(static::$tableSetKey, $tableName);        }catch (Exception $ex){            throw new Exception("Error execute sql: {$createTable}");        }        return $tableName;    }    /**     * 扩展的find     * @param $targetKey     * @return \yii\db\ActiveQuery     */    public static function findx($targetKey = null){        static::$tableName = static::renderTable($targetKey);        return Yii::createObject(ActiveQuery::className(), [get_called_class(), ['from' => [static::tableName()]]]);    }    /**     * 扩展的findAll     * @param null $targetKey     * @param array $params     * @return \yii\db\ActiveQuery[]     */    public static function findAllx($targetKey = null,$params = []){        return static::findByConditionx($targetKey, $params)->all();    }    /**     * @Override     * @param array $row     * @return static     */    public static function instantiate($row){        return new static(static::$targetKey);    }    /**     * 禁止使用findBySql     * @param string $sql     */    public static function findBySql($sql){        throw new InvalidCallException("not allowed. {$sql}");    }    /**     * 扩展的findOne     * @param null $targetKey     * @param array $condition     * @return null|static|ActiveQuery     */    public static function findOnex($targetKey = null, $condition = []){        return static::findByConditionx($targetKey, $condition)->one();    }    /**     * 内部实现     * @param null $targetKey     * @param $condition     * @return ActiveQuery[]|ActiveQuery     * @throws InvalidConfigException     */    protected static function findByConditionx($targetKey = null, $condition){        $query = static::findx($targetKey);        if (!ArrayHelper::isAssociative($condition)) {            // query by primary key            $primaryKey = static::primaryKey();            if (isset($primaryKey[0])) {                $condition = [$primaryKey[0] => $condition];            } else {                throw new InvalidConfigException('"' . get_called_class() . '" must have a primary key.');            }        }        return $query->andWhere($condition);    }}

分表model

<?phpnamespace app\models;use Yii;use app\library\Modelx;/** * Test 根据vip_card分表实现 * Class Test * @package app\models * @use $m = new Test($vip_card); * @use Test::findx($vip_card)->where([]); * @use Test::findAllx($vip_card,[]); * @use Test::findOnex($vip_card,[]); * */class Test extends Modelx{    //原始表名,表结构母版    protected static $originalName = 'test';    //redis表名set key    protected static $tableSetKey = 'project:tableset';    /**     * 根据分表关键值获得表名     * @Override     * @return string     */    public static function getTableName(){        return static::$originalName . '_'. (static::$targetKey % 10);    }}


分表使用原始表为模板进行结构复制,复制后的分表结构,不会同步原始表的结构、索引等改变。
建议在分表使用之前,对原始表做好充分优化。
分表之后的Model,不再支持findBySql方法。