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

Laravel+MySQL中删除发票后自动补全缺失编号的实现方案

方案可行性及实现方法

你的方案完全可行,把业务用的发票编号和数据库主键id分离,用独立的numbering字段管理发票编号,是解决这类“填补缺失编号”需求的合理思路——既避开了主键自增无法回补的特性,也能灵活适配业务对编号连续性的要求。

具体实现步骤

1. 新增numbering字段

首先生成数据库迁移,给invoices表添加numbering字段,同时加上唯一索引避免重复编号:

php artisan make:migration add_numbering_to_invoices_table

打开生成的迁移文件,修改内容:

public function up()
{
    Schema::table('invoices', function (Blueprint $table) {
        $table->unsignedInteger('numbering')->unique()->nullable();
    });
}

public function down()
{
    Schema::table('invoices', function (Blueprint $table) {
        $table->dropColumn('numbering');
    });
}

执行迁移:

php artisan migrate

2. 实现自动分配首个缺失编号的逻辑

可以把编号查询逻辑封装到Invoice模型里(更符合MVC架构),也可以直接在控制器内处理。

封装到模型(推荐)

在App\Models\Invoice中添加静态方法:

public static function getNextAvailableNumber()
{
    // 从1开始找第一个不存在的编号(小数据量适用)
    $nextNumber = 1;
    while (self::where('numbering', $nextNumber)->exists()) {
        $nextNumber++;
    }
    return $nextNumber;
}

// 数据量大时用更高效的数据库查询
public static function getNextAvailableNumber()
{
    $result = DB::selectOne("
        SELECT MIN(n.number) AS next_number
        FROM (
            SELECT 1 AS number
            UNION ALL
            SELECT numbering + 1 AS number
            FROM invoices
            WHERE numbering + 1 NOT IN (SELECT numbering FROM invoices)
        ) n
        WHERE n.number NOT IN (SELECT numbering FROM invoices)
    ");

    return $result->next_number ?? 1;
}

3. 修改创建发票的代码

给新发票自动赋值numbering字段:

$invoice = new \App\Models\Invoice();
$invoice->provider_id = $request->input('provider-select');
$invoice->number = $request->input('document-number');
$invoice->document_date = $request->input('document-date');
$invoice->due_date = $request->input('due-date');
$invoice->discount_procent = $request->input('discount-procent');
$invoice->discount_value = $request->input('discount-value');
$invoice->total = $request->input('total-value');
$invoice->insertion_date = $request->input('insertion-date');
// 新增:自动分配首个缺失的编号
$invoice->numbering = \App\Models\Invoice::getNextAvailableNumber();
$invoice->save();

4. 调整查询排序逻辑

后续查询发票列表时,用numbering字段替代id排序:

// 示例:按发票编号升序查询
$invoices = \App\Models\Invoice::orderBy('numbering', 'asc')->get();

5. 处理并发冲突(重要)

如果有多用户同时创建发票,可能出现重复分配编号的情况,用数据库事务+锁确保原子性:

DB::transaction(function () use ($request) {
    // 锁定invoices表直到事务结束,避免并发冲突
    DB::table('invoices')->lockForUpdate()->get();
    
    $nextNumber = \App\Models\Invoice::getNextAvailableNumber();
    
    $invoice = new \App\Models\Invoice();
    $invoice->provider_id = $request->input('provider-select');
    $invoice->number = $request->input('document-number');
    $invoice->document_date = $request->input('document-date');
    $invoice->due_date = $request->input('due-date');
    $invoice->discount_procent = $request->input('discount-procent');
    $invoice->discount_value = $request->input('discount-value');
    $invoice->total = $request->input('total-value');
    $invoice->insertion_date = $request->input('insertion-date');
    $invoice->numbering = $nextNumber;
    
    $invoice->save();
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 17:27:34