Hatena::ブログ(Diary)

bufferings

2010-06-09

Slim3 Datastoreのputを読む

| 04:06 |

org.slim3.datastore.Datastore


put

Key put(Entity entity)
Key put(Object model)

エンティティやモデルをデータストアに保存する。

カレントTx*1があればそのTx内で実行される。

Keyが返される。


List<Key> put(Iterable<?> models)
List<Key> put(Object... models)

batch put。複数のモデルやエンティティを一度の呼び出しで保存する。

一つずつputするよりもbatch putをする方が効率がいい。

カレントTxがあればそのTx内で実行される。


このmodelsパラメータにはモデルとエンティティが混在していてもOK。


batch putで注意したいのは、Tx外で実行して書き込みエラーが発生したりタイムアウトになったりしても途中までのエンティティはデータストアに保存されているということ。


Key put(Transaction tx, Entity entity)
Key put(Transaction tx, Object model)
List<Key> put(Transaction tx, Iterable<?> models)
List<Key> put(Transaction tx, Object... models)

Tx指定を行うput。

Tx内では単一EG(エンティティグループ)のエンティティしか扱うことができないので、batch putを使用する場合には注意が必要。


このtxパラメータにnullを指定するとTx外で実行される。

put(Object model)のようにTx指定のないputを使用すると、カレントTxがあればそちらが使用されてしまうので、明示的にTxを示すためにもこちらのメソッドを使用した方がいいと思う。


また、Slim3には次のような便利メソッドも用意されている。

Key putWithoutTx(Entity entity)
Key putWithoutTx(Object model)
List<Key> putWithoutTx(Iterable<?> models)
List<Key> putWithoutTx(Object... models)

こちらはTx外で実行するメソッド。

中身は先程のputメソッドのtxパラメータにnullを指定して呼び出している。


コードの可読性のためにもTx外であればputWithoutTxを使用して、Txを使用する場合はput(tx,model)を使用すると良いだろう。


キーの自動生成

put時にキーの自動生成をすることができるが、お勧めしない。

データストアへの書き込みは失敗する可能性がある。


putに失敗して例外が発生した場合でも、実際にはデータストアに書き込まれている場合があるのだ。

キーの自動生成をしていると再putでまたキーが自動生成されて同じエンティティ(モデル)が二つ登録されてしまう。


またTx外batch putの場合で、あるエンティティ(モデル)が書き込みに失敗した場合

そこまでのエンティティ(モデル)は既にデータストアに保存されている。

その場合キーの自動生成をしていると、既に保存されたデータは二重登録になってしまう。


ではどうするかというとallocateId(s)を使用して先にキーを生成しておく。

前もって生成しておいたキーを、エンティティ(モデル)に設定する。

そしてputするとキーは自動生成されず、再put時には上書きされるので二重登録されることはない。


ということなのだが。そこはSlim3

実はSlim3 Datastoreのput(Object model)を使用した場合は、putする前にallocateIdでキーを取得して設定してくれるのだ。

つまり、キーの自動生成はLow-level APIを直接使用している人は注意する必要があるが、Slim3を使用している人は気にしなくて良いてこと。


リトライ

Slim3が実装してくれている重要な機能にリトライ機能がある。

先程も言ったがGAEのデータストアはputに失敗する場合がある。


その際に発生する例外は2つある。一つはDatastoreTimeoutException。

データストアが忙しくて処理がタイムアウトしてしまった場合。タブレットの分割やマージの際に発生するようだ。


この場合は、すぐにリトライしても忙しいままだろうから少し待ってからリトライする。

それでも忙しければ、もうちょっと長く待ってからリトライする。というのをSlim3は10回リトライしてくれる。

それでもダメな場合に初めてSlim3はDatastoreTimeoutExceptionを投げる。


もう一つはConcurrentModificationException。こちらは同時更新時に発生。

普通はTxを使用している場合に発生するものだと思うのだが。Tx使用していなくても発生する場合があるらしい。


Txの更新競合が原因の場合はTxを再度始めないといけないのでリトライは開発者が行う必要があるが。

Txを使用していなくて発生した場合のことを考慮してリトライしてくれる。


これは待っても仕方がないのですぐにリトライする。

で、10回リトライしてダメだったらConcurrentModificationExceptionを投げる。


2010-06-11追記ココカラ

※補足:ここで言うリトライSlim3リトライのことではなく、失敗時にGAE側でリトライしてくれる機能のこと(v1.3.1で追加された)。

2010-06-11追記ココマデ


自動分割

batch putには2つの制限がある。

  1. 同時putできるのは500エンティティまで。
  2. 一度に実行できるのはプロトコルバッファで1MBまで。

だが。Slim3のbatch putには500個以上のエンティティを渡しても大丈夫だし。

合計1MBを超える数のエンティティを渡しても大丈夫。


なんとSlim3が計算して分割してくれるのだ。

素敵仕様。


Versionプロパティ

モデルのput時には@Attribute(version=true)のついたプロパティの値がインクリメントされる。

これは楽観的ロック用。


もうひとつ

putと名のつくメソッドがある。

boolean putUniqueValue(String uniqueIndexName, String value)

これはuniqueIndexNameというKindでvalueというKeyNameのキーを持つエンティティをTx内でputすることで

その一意性を保証するというメソッド。


勉強になった

ためになったね〜。ためになったよ〜。

*1:アクティブなTx(トランザクション)の中で一番最後に開始されたもの