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
相关产品推荐
相关产品推荐

