You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel实现每日重置的带日期自增编码方案求助

Laravel实现按日期重置的自增编码方案

问题分析

你之前的方案基于全局id生成序号,属于全局递增逻辑,无法实现次日重置计数的需求。要解决这个问题,核心是按日期分组维护当日的自增序号,下面给出两种可行的实现方案。


方案一:新增字段存储日期与当日序号(推荐,高效且稳定)

1. 修改迁移文件

添加存储记录日期和当日序号的字段,并添加联合唯一索引避免重复:

public function up()
{
    Schema::create('records', function (Blueprint $table) {
        $table->id();
        $table->date('record_date'); // 存储记录所属的日期
        $table->unsignedInteger('daily_sequence'); // 当日的自增序号
        // 其他业务字段...
        
        // 联合唯一索引:确保同一日期下序号不重复
        $table->unique(['record_date', 'daily_sequence']);
    });
}

执行迁移:php artisan migrate

2. 模型中自动填充序号与日期

在Record模型的启动方法中,监听创建事件,自动计算并填充当日序号:

use Carbon\Carbon;
use Illuminate\Support\Facades\DB;

class Record extends Model
{
    protected $fillable = ['record_date', 'daily_sequence', ...]; // 补充你的业务字段

    protected static function boot()
    {
        parent::boot();

        // 创建记录时自动计算当日序号
        static::creating(function ($model) {
            DB::transaction(function () use ($model) {
                $today = Carbon::today()->toDateString();
                // 加锁查询当日最后一条记录的序号,避免并发冲突
                $lastSequence = static::where('record_date', $today)->lockForUpdate()->max('daily_sequence');
                $model->daily_sequence = $lastSequence ? $lastSequence + 1 : 1;
                $model->record_date = $today;
            });
        });

        // 定义全局查询作用域,自动拼接编码
        static::addGlobalScope('withCode', function ($query) {
            $query->select('*', DB::raw("CONCAT('Z', DATE_FORMAT(record_date, '%m%d'), '-', LPAD(daily_sequence, 5, '0')) as CODE"));
        });
    }
}

通过全局查询作用域自动拼接编码,无需在控制器中循环处理。

3. 控制器中直接使用

public function get_records(Request $request){
    $records = Record::get();
    return $records;
    // 返回结果中自动包含CODE字段,格式如:Z0331-00001、Z0401-00001
}

方案二:无新增字段,动态计算序号(适合小数据量场景)

如果不想修改表结构,可以在创建记录时动态计算当日序号,但需注意并发冲突问题:

1. 模型中添加生成编码的方法

use Carbon\Carbon;
use Illuminate\Support\Facades\DB;

class Record extends Model
{
    // 生成当日新编码
    public static function generateTodayCode()
    {
        $today = Carbon::today();
        $dateStr = $today->format('md');
        
        DB::transaction(function () use (&$sequence) {
            // 查询当日最后一条记录的编码,提取序号
            $lastRecord = static::whereDate('created_at', $today)->lockForUpdate()->latest()->first();
            $sequence = $lastRecord ? intval(substr($lastRecord->code, 6)) + 1 : 1;
        });
        
        $sequenceStr = str_pad($sequence, 5, '0', STR_PAD_LEFT);
        return "Z{$dateStr}-{$sequenceStr}";
    }

    // 访问器获取已存在记录的编码
    public function getCodeAttribute()
    {
        $dateStr = Carbon::parse($this->created_at)->format('md');
        // 计算该记录是当日的第几条
        $sequence = static::whereDate('created_at', $this->created_at)->where('id', '<=', $this->id)->count();
        $sequenceStr = str_pad($sequence, 5, '0', STR_PAD_LEFT);
        return "Z{$dateStr}-{$sequenceStr}";
    }
}

2. 创建记录时使用

public function store(Request $request)
{
    $code = Record::generateTodayCode();
    Record::create([
        'code' => $code,
        // 其他业务字段...
    ]);
}

注意:此方案在数据量大时性能较差,且如果删除当日记录,后续生成的序号会出现断层。


注意事项

  • 方案一的lockForUpdate和事务是为了避免高并发场景下的序号重复问题;
  • 如果使用方案一,不需要在数据库中存储最终编码,通过访问器或查询拼接即可,节省存储;
  • 若需要修改历史记录的编码,只需调整record_date和daily_sequence字段,编码会自动更新。

内容的提问来源于stack exchange,提问作者Keyboard Corporation

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 12:03:24