QA@IT

UNIQUE制約が付いたカラムに安全に値を追加する方法を教えてください

2850 PV

MySQL 5.6を使っています。

こんなテーブルがあります。

CREATE TABLE tb_user (
  user_id INT NOT NULL AUTO_INCREMENT,
  email VARCHAR(100) NOT NULL COMMENT 'メールアドレス',
  PRIMARY KEY (user_id),
  UNIQUE (email)
) ENGINE=InnoDB CHARACTER SET utf8;

このテーブルに安全にメールアドレスを追加するには、このようにするのでしょうか。

BEGIN;

SELECT user_id FROM tb_user FOR UPDATE;

SELECT user_id FROM tb_user WHERE email = 'hoge@hoge.com';

-- レコードがあれば

ROLLBACK;

-- レコードがなければ

INSERT INTO tb_user (email) VALUES ('hoge@hoge.com');

COMMIT;

この場合、SELECT user_id FROM tb_user FOR UPDATE;で全レコードに専有ロックをかけているのが気になりますが、仕方ないのでしょうか。

  • 一意制約に任せるとなにか都合が悪いんですか? -
  • 重複するとエラーになりますよね。個人的にエラーハンドリングが難しいのと面倒くさいというのがあります。 -
  • ちなみに [ SELECT user_id FROM tb_user FOR UPDATE; ] では insert を防げないのですよ。(選択範囲をロックする) -
  • こちらではロックされますね。トランザクション分離レベルはREPEATABLE READです。そちらではロックされないですか? -
  • MySQLでは表ロック相当になります。回答が適当過ぎ。 -

回答

もう答えがコメントで書かれていますが、一意制約があるのですからそれに任せるとよいです。
最初からいきなりINSERTを実行してください。
すでに同様のメールアドレスでの登録があればMySQLは一意制約違反のエラーを返します。
なければ正常に登録が完了します。

フロント側のアプリケーションは何らかのフレームワークなりO/RマッパーなりDB仮想化レイヤなりを使っていると思います。
MySQLから返された一意制約違反を受けて例外をスローするなど、適切に扱う仕組みがもうあると思います。
開発中のアプリケーションではそういった例外なりを受けて、ヴァリデーションエラーなりなんなりの業務エラーや業務例外を実装することになります。
ユーザ登録とかそういう機能なのかな、と思いますがその場合はヴァリデーションエラーとかになりますかね。

編集 履歴 (0)
  • 了解しました。やってみて、またコメントします。 -
  • できました。正しい方法を教えていただきありがとうございました。 -
ウォッチ

この質問への回答やコメントをメールでお知らせします。