(開発中アプリなんで、利用には承認が必要です)
2010-06-19
Slim3でのデータの取扱い
後でプロジェクトページに書く内容をメモ
http://code.google.com/p/mlmchuchu/
(追記)
あ、なんかコード中の一部が化けてる(汗
はてな記法やwiki構文を無効化にするタグがあるんだろうけど・・・
ちょっと見てみるかな。
とりあえずGoogleCodeの方に反映させました。そっちは大丈夫。
(追記2)
「入力したコードやはてな記法をそのまま表示する(スーパーpre記法)」に書き換え。
これでこっちも大丈夫になったはず。
////////////////////////////////////////////////
本ページでは、Slim3におけるデータの取扱いについて記述しています。
目次は以下のとおりです。
・準備運動
・データの持たせ方を考える
・ユーザIDを元にしてデータの読み書きを行う
・グローバルトランザクションを使う
・楽観的ロックの失敗時にリトライする
・実際の処理を想定したコードを書いてみる
・(追記)運用を見据えた設計
・(追記)Blobで保存してみる
【【【準備運動】】】
まずはSlim3のスタートガイドを一通りやりましょう。
必要なソフトの入手法や、設定方法、モデルの作り方、データの基本的な保存と取得についてはこちらに書かれています。
http://sites.google.com/site/slim3appengine/getting-started
http://sites.google.com/site/slim3documentja/getting-started
それを踏まえたうえで、実際のアプリで必要な処理をいろいろ解説していきたいと思います。
では、まず最初に単純な例をお見せします。
//データを保存
Datastore.put(newCharacter);
//データを取得
ChuchuCharacter chuchuCharacter = Datastore.getOrNull(ChuchuCharacter.class, key);
一応は、これだけでデータの保存と取得を行うことができます。
(キーの生成方法やモデルの作成方法については後述します)
実際に稼働するアプリを創る際には、トランザクションやリトライのためのコードが必要になるので、
ほとんどの場合はもっと複雑なコードになりますが、
テストケースの記述等、これだけで十分な場合も多々あります。
ではさっそく、実際に動作するコードとして以下のことを検証してみましょう。
・キャラクター情報を作成し、データを書き込んでみる
・書き込んだデータを取得してみる
手順はこんな感じ。
【モデルとサービスを作成】
ここで単純に「Character」という名前のモデルにしてしまうと、
java.lang.characterと名前がかぶって面倒なことになるので、ここでは必ず「ChuchuCharacter」にすること!
【テストケースを記述】
通常はChuchuServiceにコードを記述して、それをテストケースから呼び出すことになりますが、
今回のようにちょっとした検証を行いたい場合など、テストケースに直接書いて済ませるという手もあります。
【JUnit実行】
実行してグリーンになる(場合によってはレッドになる)ことが確認できればOK。
コードは以下の通りとなります。
//【モデル】
package slim3.model;
import java.io.Serializable;
import com.google.appengine.api.datastore.Key;
import org.slim3.datastore.Attribute;
import org.slim3.datastore.Model;
@Model(schemaVersion = 1)
public class ChuchuCharacter implements Serializable {
private static final long serialVersionUID = 1L;
@Attribute(primaryKey = true)
private Key key;
@Attribute(version = true)
private Long version;
/**
* 名前
*/
private String name;
/**
* 経験値
*/
private int exp;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getExp() {
return exp;
}
public void setExp(int exp) {
this.exp = exp;
}
/**
* Returns the key.
*
* @return the key
*/
public Key getKey() {
return key;
}
/**
* Sets the key.
*
* @param key
* the key
*/
public void setKey(Key key) {
this.key = key;
}
/**
* Returns the version.
*
* @return the version
*/
public Long getVersion() {
return version;
}
/**
* Sets the version.
*
* @param version
* the version
*/
public void setVersion(Long version) {
this.version = version;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((key == null) ? 0 : key.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
ChuchuCharacter other = (ChuchuCharacter) obj;
if (key == null) {
if (other.key != null) {
return false;
}
} else if (!key.equals(other.key)) {
return false;
}
return true;
}
}
//【サービス】
package slim3.service;
public class SampleService {
}
//【サービスのテストケース】
package slim3.service;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;
import org.junit.Test;
import org.slim3.datastore.Datastore;
import org.slim3.tester.AppEngineTestCase;
import slim3.model.ChuchuCharacter;
import com.google.appengine.api.datastore.Key;
public class SampleServiceTest extends AppEngineTestCase {
private SampleService service = new SampleService();
@Test
public void test() throws Exception {
//キーの元となる値
//実際は、Controllerで取得した値を引数として渡すようにすることが多い
String opensocialId = "testid";
//モデルクラスと、キーの元となる値を引数にして、キーを生成する
Key key = Datastore.createKey(ChuchuCharacter.class, opensocialId);
//とりあえず取得してみる
//まだデータを作成していないので、nullになる
ChuchuCharacter nullCharacter = Datastore.getOrNull(ChuchuCharacter.class, key);
assertThat(nullCharacter, is(nullValue()));
//ちなみにDatastore.get#getメソッドもある
//こちらはデータが存在しない場合にEntityNotFoundRuntimeExceptionを投げてくる
//ChuchuCharacter nullCharacter2 = Datastore.get(ChuchuCharacter.class, key);
//登録するキャラクター情報を作成
//ここでキーをセットしなかった場合、put時に自動でキーが設定される
//例えば、メッセージや掲示板への書き込み等は自動採番にするのが良い
ChuchuCharacter newCharacter = new ChuchuCharacter();
newCharacter.setKey(key);
newCharacter.setName("チューチューレッド");
newCharacter.setExp(300);
//保存する
Datastore.put(newCharacter);
//保存した値を取得し、値を検証する
ChuchuCharacter chuchuCharacter = Datastore.getOrNull(ChuchuCharacter.class, key);
assertThat(chuchuCharacter, is(notNullValue()));
assertThat(chuchuCharacter.getName(), is("チューチューレッド"));
assertThat(chuchuCharacter.getExp(), is(300));
}
}
今回の場合、JUnitを実行してみて、バーがグリーンになればOKです。
無事、保存と取得ができましたね。
ちなみにデータが存在しなければ初回のputで保存され、
存在していれば更新(上書き)となります。
うっかり同一キーを発行してしまった場合などは古いデータは上書きされますので注意しましょう。
とりあえず、これで準備運動は終了です。
それでは次回、【データの持たせ方を考える】に入っていきましょう。
- 5 http://www.google.co.jp/search?hl=ja&lr=lang_ja&tbs=lr:lang_1ja&q=mixi+アプリ+一瞬スクロールバーが表示される&aq=f&aqi=&aql=&oq=
- 4 http://d.hatena.ne.jp/keyword/slim3
- 3 http://www.google.co.jp/search?hl=ja&source=hp&q=mixi+公開鍵&aq=f&aqi=g1&aql=&oq=&gs_rfai=
- 3 http://www.google.co.jp/search?sourceid=navclient&hl=ja&ie=UTF-8&rlz=1T4ADRA_jaJP347JP347&q=Invalid+byte+1+of+1-byte+UTF-8+sequence
- 2 http://fieldnotes.sytes.net/slim3-dev/view/detail_mobile.html?itemId=656
- 2 http://pipes.yahoo.com/pipes/pipe.info?_id=VPw6npu13RGKo15vBRNMsA
- 2 http://reader.livedoor.com/reader/
- 2 http://search.minakoe.jp/rsss/rsss.asp?qry=java¬wit=1&twit=0&multi=1
- 2 http://www.google.co.jp/search?q=Invalid+byte+1+of+1-byte+UTF-8+sequence&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:ja:official&hl=ja&client=firefox-a
- 2 http://www.google.co.jp/search?q=slim3 データ更新&sourceid=ie7&rls=com.microsoft:en-US&ie=utf8&oe=utf8&rlz=1I7GGLD_ja&redir_esc=&ei=Z2sgTJj2DJGvcLi9-Vk








