You are here
Home > !Laravel > 重複回避 – DB重複エラーを利用

重複回避 – DB重複エラーを利用

前回においては入力バリデーションでの重複回避を紹介しました。

小規模なサイトではこれだけで重複回避は十分かもしれません。しかし、以下の状況では、どうなるでしょう?

ユーザーAさんとBさんがいたとして、どちらも、ほとんど同時にtest@gmail.comのログインで登録を試みます。もちろんそんなことは滅多に起こらないのですが、たまたまBさんは間違って自分のEメールアドレスをAさんと同じものとタイプしたとします。それから、test@gmail.comでの会員はまだDBには存在しないという仮定です。

Aさんは、

10時20分00秒:入力完了して送信(登録ボタンを押す)
10時20分05秒:入力バリデーション無事通過!
10時20分15秒:無事にDBに登録成功!

Bさんも、5秒遅れて、

10時20分05秒:入力完了して送信(登録ボタンを押す)
10時20分10秒:入力バリデーション無事通過! 

(もちろん実際はこんなに遅く物事は進行しませんが、経過を理解してもらうために)

あれあれ、まだAさんのレコードはDBにないから、入力バリデーション効きませんね。

このままだと重複のレコードになってしまいますね。どうしましょう?

通常、会員の登録のDBテーブルでは、同じID、ここではEメールの重複はないよ、ということで、プライマリーキーあるいはユニークキーというものを設定します。

例えば、以下はmysqlでのDB設定ですが、「Unique Key `member_unique` (`email)」がDBに重複のレコードが作成されるのを防ぎます。

CREATE TABLE `member` (
  `member_id` int(11) NOT NULL AUTO_INCREMENT,
  `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `email` varchar(100) NOT NULL DEFAULT '',
  `password` varchar(255) NOT NULL DEFAULT '',
  PRIMARY KEY (`member_id`),
  UNIQUE KEY `member_unique` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

このDBの設定のおかげで、

10時20分15秒:DBの重複エラーとなり、Bさんのレコードは作成されず重複のレコードの作成は回避されます。

ここの部分、プログラムでは前回の入力バリデーションと合わせて以下のようになります。

public function postSignup(Request $request)
{
    $rules = [
      'email'      => 'required|email|unique:member,email',
      'password'   => 'required|min:6|max:20|confirmed',
      'first_name' => 'required',
      'last_name'  => 'required'
    ];

    $messages = [
      'email.unique' => "Eメールアドレスはすでに使用されています"
    ];

    $this->validate($request, $rules, $messages);

    try 
    {
      $member = Member::create($request->all());
    }
    catch(IlluminateDatabaseQueryException $e)
    {
      $errorCode = $e->errorInfo[1];

      if($errorCode == 1062) //重複エラーをここでキャッチ
      {
        return back()->withInput()->withErrors(['email' => "Eメールアドレスはすでに使用されています"]);
      }
    }

  return "登録完了";
}  

これで重複は完全に回避されます。

これなら、入力バリデーションの重複はチェックはもう要らないのでは?

それを削除をしてもOKと思います。しかし、ルールの記述としてプログラムに残るのは良いかもしれません。将来はDBレベルの重複エラーもフレームワークが面倒みてくれるかもしれません。

Leave a Reply

Top