Yii2 自动分表 model
程序员文章站
2024-03-21 22:57:40
...
其实是借鉴了一下某同学的《动态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
<?php
namespace 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方法。
上一篇: Python3迭代器
下一篇: Python3 - 实现迭代器协议
推荐阅读
-
Yii2 自动分表 model
-
详解yii2实现分库分表的方案与思路
-
详解yii2实现分库分表的方案与思路
-
写一个PHP资料,自动循环创建MYSQL表,20分相送
-
yii2使用gii,如果两个表有关联关系,在models能自动生成关联关系的方法吗?
-
yii2使用gii,如果两个表有关联关系,在models能自动生成关联关系的方法吗?
-
在ASP.NET Core 2.0上操作MongoDB就是能这么的简便酷爽(自动完成分库分表)
-
制作表格时会用到的小技巧之总表输入数据自动拆分到分表
-
VBS实现工作表按指定表头自动分表
-
JAVAEE——BOS物流项目09:业务受理需求分析、创建表、实现自动分单、数据表格编辑功能使用方法和工作单快速录入