2014年9月3日水曜日

【GAE】初級実装編 インサート実行2 一意制約

株式会社ジェニシス 技術開発事業部の遠藤 太志郎(Tacy)です。

只今、クラウド基盤「Google App Engine(以下、GAE)」の連載しています。

さて、前回ではGAEの最大の特徴である「BigTable」へのデータ登録をご紹介しました。

今回はそのデータ登録についての、ちょっと込み入った話、「一意制約」についてご紹介します。

GAEは主キーだけ

Oracle、postgreSQL、MySQLなどメジャー所のデータベースには、大概はDB独自の「制約」を設ける機能があります。


  • 主キー制約
  • 一意制約
  • 外部キー制約
  • null禁止制約


この辺りがよく使う制約だと思いますが、しかし、GAEには一意制約しか存在しないのです!!

何と不便な!!

要するに、GAEみたいなクラウド基盤は分散処理かつ大量データを取り扱っている都合上、負荷軽減とか仕様の問題で細かいチェックを行うことが出来ないのです。
このうち、外部キー制約とnull禁止制約はロジックで頑張れば対処出来ます。

  • 外部キー制約:親テーブルが無くて子テーブルだけある、みたいなことにならないように、トランザクション等も駆使してキッチリJavaのロジックを組む。
  • null禁止制約:登録、更新時にそのカラムがnullにならないようにJavaロジックを組む。

つまるところ、「バグが無いようにきっちり作れッ!!」という話で済むのです。

しかし、「一意制約」ばかりはそうはいかない。
もちろん、DB上でカラムが重複してはいけないようにJavaのチェック機能を入れるのはアリですれども、
Webシステムでの運用という都合上、「同タイミングの二重アクセス」という宿命からは逃れられません。

一意制約だけは、どれだけキッチリJavaロジックを組んでも担保出来ないのです。

しかしながら、GAE専用ライブラリであるSlim3には、主キー制約を上手く使って一意制約を実現してくれる機能があります。
今回はそれをご紹介します。

実装方法

さて、上記のようにGAEには一意制約が無く、主キー制約しかありません。
そこで、Slim3では「一意制約チェック専用のテーブルを作って主キーチェックを利用する」という機能が備わっています。

メソッドは「Datastore.putUniqueValue」。

例えば、ソース的には以下みたいな漢字に組めば良いというわけです。

public Key insert(Shohin model) throws Exception {

  Transaction tx = Datastore.beginTransaction();

  try {

   tx = Datastore.beginTransaction();

   Key key = null;

   if (Datastore.putUniqueValue(Shohin.UNIQUE_SHOHIN_NAME, model.getShohinName())) {
    key = super.put(model);
   } else {
    throw new BusinessCheckException("対象の商品名は既に登録されています。");
   }

   /*
    * 商品IDのあいまい検索用にIDを文字列化して再保存する。
    */
   model.setShohinId(Long.toString(model.getKey().getId()));
   put(model);
   tx.rollback();

   return key;

  } catch (Exception e) {

   tx.rollback();
   throw e;

  }

 }

こうすると、ほら。
下の図みたいに、一意キーチェックを行う為だけのテーブルが作成されます。
こうやって二つのテーブルを駆使することで一意制約を実現するわけですね。



登録する時が、「Datastore.putUniqueValue」。
削除する時が、「Datastore.deleteUniqueValue」。


つまり、


  • 新規登録時は、putするだけ。
  • 更新時は、先にputして後でdelete。
  • 削除時は、deleteするだけ。


こんな漢字にトランザクションを活用しつつロジックを組むことで、一意制約が実現出来るわけですね。
流石はSlim3。
良い機能が備わっています。

注意点

しかしですね、上記の通り、一意制約の度に新しいテーブルが作られてしまいますので、リソース的にも処理速度的にも、一意制約を多用するのは避けた方が良いと思います。

上記は例として「同じ商品名は登録出来ない」という仕様にしましたけれども、ケースによっては「普通のJavaチェックだけで十分。万が一被った場合は消せば良い」程度で済んでしまう程度の重要度であることも十分考えられますよね。
同時アクセスなんて滅多に無いですから、Javaチェックだけで99.9%はブロック出来ますもの。

そういう場合は一意制約はあえて入れないで、万が一問題が起きた時だけ運用回避する、という方針で十分かと思います。

しかし、逆に「絶対に何が何でも、死んでも重複して貰っては困る!!」なんて場合もあるでしょう。
例えば「メールアドレスは一意」などがそうです。
ログインIDの代わりにメールアドレスを使っているサイトなのに、メールアドレスが重複して入ってしまっていたら、これは大問題ですよね!!
万が一にもこんなバグは許されません。

このように、本気の本気で一意制約が必要な重用機能だけチェックを入れて、それ以外はJavaによるチェックのみで楽観的に済ませる。
これくらいの方針が良いでしょう。

終わりに

流石、Slim3は便利な機能が揃っています。事実上の標準フレームワークたるシェアを占めているだけのことはあります。

次回も引き続き、DBへのインサート処理の特記事項をご紹介します。

0 件のコメント:

コメントを投稿