只今、クラウド基盤「Google App Engine(以下、GAE)」の連載しています。
今回は前回に引き続き、GAEにおける「インサート」の処理についてご紹介です。
put
ではまず、何も考えずにスポッと値を入れるだけの処理を記載します。前回の段階で「モデル」と「DAO」は作成済みですので、これを使ってレコードの登録を行います。
そのソースが以下です。
Shohin shohin = new Shohin(); ShohinDao dao = new ShohinDao(); dao.put(shohin);
これだけです。
put一発で終わり。空っぽですが、1レコード増えています。
実に簡単ですね。
とはいえ、余りにシンプル過ぎるが故に、「これってどういう風にデータの辻褄を合わせているんだろう?」という疑問が沸いて当然。
この為、今回はその辺りについての疑問解決がメインテーマになります。
登録更新の区別が無い
まず第一の特徴は、GAEにおけるデータ保存のやり方は「insert」ではなく「put」なんです。put処理というのは、レコードが存在していたら上書き、無ければ新規保存です。
SQLと違って、「新規登録」と「更新」の区別が無いのです。
これはJavaのMapと全く同じです。
Shohin shohin = new Shohin(); Map map = new HashMap(); map.put("ID_0001",shohin);
これが大量データ処理の秘密の一つなのです。
要はDBがハッシュで管理されているから、レコード数がどれだけ大量に増えても均一の速度を保てているというわけなのです。
(ハッシュを使うと検索速度がレコード数に依存しなくなるという件については、基本情報処理試験等でご理解下さい)
なので、GAEで「新規登録」と「更新」を実現したい場合は、前もって検索して、
- GigTable上に予定レコードが存在していなかった場合、単純にput。
- GigTable上に予定レコードが存在していた場合、まずテーブル上の値を丸ごと取得し、更新したいパラメータだけを差し替えてput。
こういうロジックを組んで対応する必要があります。
ここで一つ、GAEの特徴が垣間見えてきましたね。そう、GAEは基本的にロジック対応で乗り切るモノです。
例えばですね、「商品の値段が100円になっているものを、全部150円に一括で値上げしたい」とかいう要求があるとするじゃないですか。
その場合、SQLだったら「update shohin set price = 150 where price = 100;」みたいな感じに一発で全レコード更新すればOKです。
しかし、GAEの場合は「更新」なんか存在しませんので、まずは「値段が100円である商品」で検索を行い、それから1レコードずつJavaでpriceの値を150に書き換えてputするのです。
GAEは1レコード単位でしか登録、更新、削除出来ない!!
要望は殆ど全部Javaで頑張ってロジックを組んで何とかするのです!!
ちなみに、上記の通り、GAE大量レコードの更新をする場合でも1レコードずつの逐次処理になってしまいますので、「一括更新、一括削除」が主力になるシステムには向かないということです。
こういった検索機能についての向き不向きは追々検証していきたいと思いますので、今回の所は触り程度にご認識頂ければと思います。
主キー
次に疑問に思うのは、「主キー」です。上記にある「無ければ登録、あれば上書き」という挙動は「主キー検索して、ある/無い」という話です。
その「主キー」とはどこにあるかと言いますと、商品モデルの中の「Key」というフィールドです。
/** キー */ @Attribute(primaryKey = true) private Key key;
このKeyはちょっと独特な動きをしまして、「自動モード」と「手動モード」があります。
自動モード
まず、上記でご紹介したように「何もせずにput」を行うと、勝手に上記「key」にシーケンス番号がセットされます。PostgreSql等で「serial」という型を主キーに定義しておくと、空で保存した時に勝手にシーケンス番号で値が入っていきますが、あれとそっくりな動きです。
この「主キーがシリアル」というのは、ちょっとしたDB設計のポリシーが入ってくる部分ですので、ちょっと込み入った話を。
例えば、商品を管理するようにあシステムの場合、「商品毎に商品IDを明示的に決めて、それを主キーにする」という設計になることが多いと思います。
「商品IDで一意」と決まっている以上は、それを主キーにするのが最も合理的ですよね?
しかし、昨今のシステム業界を見ますと、「商品IDは一意キーとして別途制約を入れて、主キーはシリアルにする」という思想が出て来ています。
Ruby On Railsはこの思想です。
このやり方の場合、DB的には冗長になりますが、「プログラミングし易い」「ソース粒度が均質化する」「マッピングし易い」などの利点があるのです。
私もこのやり方に賛同する所がありまして、多少ファイルスペースを無駄遣いしてもシリアルを使わせて貰っちゃったりするのが最近のブームです。
GAEもこれに近い思想で構築されておりまして、「主キーはシリアル」がGAEの標準です。
特に拘りが無ければ、この標準の自動シリアルモードで作って行くのが良いのではないでしょうか?
手動モード
一方で、「主キーは商品IDを明示的にセットする」みたいな手動モードが必要になる場合もあります。その場合は、「KeyFactory.createKey」というツールでキーを生成しなければなりません。
Shohin shohin = new Shohin(); Key key = KeyFactory.createKey("Shohin", "49033011234567"); shohin.setKey(key); ShohinDao dao = new ShohinDao(); dao.put(shohin);
「KeyFactory.createKey("Shohin", "49033011234567");」のうち、「Shohin」がテーブル名を意味して、「49033011234567」が商品IDを意味します。
こんな感じで任意パラメータを主キーにすることが出来るのです。
ただ、やっぱ作りとしては汚くなるという印象がありますね。
やはり基本は自動モードで実装した方が合理的で、もし一意に保ちたいカラムがある場合は、別途「一意制約」を設ける方がシステムとして整合性が取れると思います。
続く
しかしですね、上記に「一意キー」とありますが、実は、GAEに一意キーは無いのです。GAEのDB制約は「主キー制約」しかありませんので、「主キー制約を上手く使って一意制約を入れる」というテクニックが必要になります。
次回はインサート実行後編、「一意制約の作り方」をご紹介します。