ThinkOrm4.0分表最佳实践
一、定义模型,并在模型init时自动建表
<?php
namespace database\model\tenant;
use think\facade\Db;
use think\Model;
use think\model\concern\SoftDelete;
class User extends Model {
use SoftDelete;
// 模型配置
protected function getOptions(): array {
return [
'name' => 'user',
// 'suffix' => '_en',
];
}
protected function init(): void {
$table_with_suffix = $this->getTable();
$table_name = $this->getOption('name');
$table_prefix = explode($table_name, $table_with_suffix)[0];
// $this->getOption('suffix') 获取不到
$suffix = '_cn'; // 需要从其他地方传入,init时,动态取不到后缀,没有初始化过来。
$table_template = $table_prefix . $table_name;
$table_with_suffix = $table_prefix . $table_name . $suffix;
$result = Db::query("SHOW TABLES LIKE '{$table_with_suffix}'");
if (empty($result)) {
Db::query("create table $table_with_suffix like $table_template");
}
$this->setOption('suffix', $suffix);
}
}二、集合查询方法,单表查询只需要设置suffix即可
/**
*
* 分表查询方法
*
* @author Joe <joe@xcwl.com>
* @version v1.01
* @date 2026-07-17
*
* @param string $table_name 表名 'user'
* @param array $suffix 分表后缀,如['en', 'cn']
* @param array $field 查询字段
* @param array $where 查询条件
* @param int $pagesize 分页大小
* @param int $page 分页页码
* @param array $order 排序条件
* @return array 查询结果
*
**/
function queryTable(string $table_name, array $suffix, array $field = ['*'], array $where = [], int $pagesize = 20, int $page = 1, array $order = []) {
// 查询集合
$queries = collect();
//把最原始表单的数据加入
if ("SHOW TABLES LIKE '{$table_name}'") {
$queries->push(
Db::name($table_name)
// 建议都用field查询字段,SQL尽可能的优化性能
->field($field)
->where($where)
);
}
foreach ($suffix as $item) {
// 组装分表
$table_with_suffix = $table_name . '_' . $item;
if ("SHOW TABLES LIKE '{$table_with_suffix}'") {
$queries->push(
Db::name($table_with_suffix)
// 建议都用field查询字段,SQL尽可能的优化性能
->field($field)
->where($where)
);
}
}
$unionQuery = $queries->shift();
// 循环剩下的表添加union
$queries->each(function ($item, $key) use ($unionQuery) {
$unionQuery->unionAll($item);
});
// 把用 unionAll链接起来的sql 组成一个表
$model = Db::table($table_name)
// 添加临时表
->from(Db::raw("({$unionQuery->fetchSql()}) AS {$table_name}"))
// 合并查询条件
->mergeBindings($unionQuery);
if ($order) {
$model->order($order);
}
$data['total'] = $model->count();
$data['data'] = $model->limit($pagesize)->page($page)->select()->toArray();
return $data;
}
