Laravel 数据表按月份水平分表,表不存在,自动创建生成
说明:创建表的时候需要进行判断,如果表存在,则不需要创建。这个代码会被多次使用并可以重复使用,选择写成trait,实现分表后的增删改查操作和分表前一样,但默认是对当前月份进行增删改查。
trait:
<?php
namespace App\Models\Traits;
use Carbon\Carbon;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
trait SplitTableTrait
{
/**
* 是否分表,默认false,即不分表
* @var bool
*/
protected $isSplitTable = true;
/**
* 最终生成表
* @var
*/
protected $endTable;
/**
* 后缀参数
* @var null
*/
protected $suffix = null;
/**
* 初始化
* @param array $attributes
* @param $suffix
* @return void
*/
public function init(array $attributes = [], $suffix = null)
{
$this->endTable = $this->table;
// isSplitTable参数为true时进行分表,否则不分表
if ($this->isSplitTable) {
// 初始化后缀,未传则默认年月分表
$this->suffix = $suffix ?: Carbon::now()->format('Ym');
}
//初始化分表表名并创建
$this->setSuffix($suffix);
}
/**
* 设置表后缀, 如果设置分表后缀,可在service层调用生成自定义后缀表名,
* 但每次操作表之前都需要调用该方法以保证数据表的准确性
* @param $suffix
* @return void
*/
public function setSuffix($suffix = null)
{
// isSplitTable参数为true时进行分表,否则不分表
if ($this->isSplitTable) {
//初始化后缀,未传则默认年月分表
$this->suffix = $suffix ?: Carbon::now()->format('Ym');
}
if ($this->suffix !== null) {
// 最终表替换模型中声明的表作为分表使用的表
$this->table = $this->endTable.'_'.$this->suffix;
}
// 调用时,创建分表,格式为 table_{$suffix}
// 未传自定义后缀情况下,,默认按年月分表格式为:orders_202205
// 无论使用时是否自定义分表名,都会创建默认的分表,除非关闭该调用
$this->createTable();
}
/**
* 提供一个静态方法设置表后缀
* @param $suffix
* @return mixed
*/
public static function suffix($suffix = null)
{
$instance = new static;
$instance->setSuffix($suffix);
return $instance->newQuery();
}
/**
* 创建新的"table_{$suffix}"的模型实例并返回
* @param array $attributes
* @return object $model
*/
public function newInstance($attributes = [], $exists = false): object
{
$model = parent::newInstance($attributes, $exists);
$model->setSuffix($this->suffix);
return $model;
}
/**
* 创建分表,没有则创建,有则不处理
* @return void
*/
protected function createTable()
{
$connectName = $this->getConnectionName();
// 初始化分表,,按年月分表格式为:orders_202205
if (!Schema::connection($connectName)->hasTable($this->table)) {
Schema::connection($connectName)->create($this->table, function (Blueprint $table) {
$table->id();
$table->dateTime('pay_at')->comment('交易时间');
$table->string('appid')->comment('公众账号ID');
$table->string('mch_id')->comment('商户号');
$table->string('sub_mch_id')->nullable()->comment('特约商户号');
$table->string('device_info')->nullable()->comment('设备号');
$table->string('transaction_id')->comment('微信订单号');
$table->string('out_trade_no')->comment('商户订单号');
$table->string('openid')->comment('用户标识');
$table->string('trade_type')->comment('交易类型');
$table->string('pay_status')->comment('交易状态');
$table->string('bank_type')->comment('付款银行');
$table->string('fee_type')->comment('货币种类');
$table->decimal('settlement_total_fee', 10, 2)->comment('应结订单金额');
$table->decimal('coupon_fee', 10, 2)->comment('代金券金额');
$table->string('refund_id')->comment('微信退款单号');
$table->string('out_refund_no')->comment('商户退款单号');
$table->decimal('refund_fee', 10, 2)->comment('退款金额');
$table->decimal('coupon_refund_fee', 10, 2)->comment('充值券退款金额');
$table->string('refund_type')->nullable()->comment('退款类型');
$table->string('refund_status')->nullable()->comment('退款状态');
$table->string('body')->comment('商品名称');
$table->string('attach', 1000)->nullable()->comment('商户数据包');
$table->decimal('service_charge', 10, 2)->comment('手续费');
$table->string('rate')->comment('费率');
$table->decimal('total_fee', 10, 2)->comment('订单金额');
$table->decimal('apply_refund_fee', 10, 2)->comment('申请退款金额');
$table->string('rate_remark')->nullable()->comment('费率备注');
$table->timestamps();
});
}
}
}
模型使用trait:(任何模型都可使用这个trait进行按月分表)
<?php
namespace App\Models;
use App\Models\Traits\SplitTableTrait;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class WechatBill extends Model
{
use HasFactory;
use SplitTableTrait;
protected $table = 'wechat_bill';
protected $guarded = [];
public function __construct(array $attributes = [], $suffix = null)
{
// 初始化分表处理
$this->init($attributes, $suffix);
parent::__construct($attributes);
}
}
效果:
分表查询示例
$wechatBill = new WechatBill();
$wechatBill->setSuffix(202303);
return $wechatBill->newQuery()->get();
分表写入
return (new WechatBill([], 202303))->newInstance()->create([]);
本作品采用《CC 协议》,转载必须注明作者和本文链接
建表这种操作,最好还是放到任务计划里面去,提前创建。这样直接在查询中,如果遇到刚好有事务,DDL 操作直接把事务给你自动提交了,就麻烦了。
如果查询条件里面没有日期,或查整年的数据,想听听你是如何处理的。