Laravelで採番テーブルの作成

Laravelで一意の番号を発番する採番テーブルを作成します。
こちらのサイトを参考に作成させて頂きました。

採番テーブルとは

データを登録する際にIDなどを一意の番号を連番で発番するテーブルです。
一般的にはDBの設定で自動でカウントアップしていきますが、今回の方法はプログラムで番号の発番とカウントアップを行います。

テーブルの作成

まずマイグレーションでsequencesテーブルを作ります。

php artisan make:model Sequence -m

マイグレーションファイルは番号だけ保持してます。

Schema::create('sequences', function (Blueprint $table) {
 $table->id();
 $table->integer('sequence')->unsigned();
 $table->timestamps(); 
});

※IDだと番号が変わってしまう可能性があるのでキーとかの方がいいかもしれません。


モデルの作成

Sequenceモデルを以下のように実装します。

class Sequence extends Model
{
 const DB_CONNECTION = 'mysql_sequence';
 protected $connection = self::DB_CONNECTION;


 protected static function boot()
 {
  parent::boot();
  config([
   'database.connections.' . self::DB_CONNECTION =>
   config('database.connections.' . config('database.default')),
   ]);

 }

 public static function getNewNo()
 {
   $sequence = Sequence::lockForUpdate()->find(1);
  if (!empty($sequence)) {
   $sequence->sequence++;
  } else {
   $sequence = new Sequence();
    $sequence->sequence = 1;
   }
   sequence->save();
   return $sequence->sequence;
 }
}

実装のポイントは2つです。

1.DBコネクションのコピーを作り別のトランザクションで更新を行う
例えば大量のデータの保存処理を行う場合、1件ずつコミットはせず最後にコミットし、途中でエラーになった場合はロールバックするということを行うかと思います。
同じトランザクションで採番テーブルの保存処理も行うと途中でロールバックすると番号が戻ってしまう問題が起きます。
2.lockForUpdateでロックする
ほぼ同時に採番が行われた際に番号が重複しないように先に採番したデータが保存されるまで後続の採番処理をロックしておきます。

採番方法

プログラムで使うときは以下のように使います。

$no = Sequence::getNewNo();