古いバージョンのドキュメントを表示しています。
最新版のドキュメントはこちらからご覧になれます

はじめに

realm-javaは、Androidプロジェクト以外では、サポートされていません。

必要なもの

  • バージョン0.8.6以上のAndroid Studio(Eclipseをお使いの場合は、以下をご覧ください)
  • 最新のAndroid SDK
  • バージョン7以上のJDK

API Level 9(Android2.3 Gingerbread)からのは全てサポートしています。

インストール

Mavenを使うか手動でJarを追加するかでRealmをプロジェクトに追加してください。

Maven

  1. 依存レポジトリのために jcenter を使ってください。(Android Gradleプラグインではデフォルトです。)
  2. compile 'io.realm:realm-android:0.71.0' を追加してください。
  3. Android Studioのメニューから Tools->Android->Sync Project with Gradle Files を選択してください。

Jar

  1. Downloadから最新のパッケージをダウンロードし解凍してください。
  2. Android Studioで新しいプロジェクトを作成します。
  3. realm-VERSION.jarapp/libs にコピーします。
  4. Android Studioのメニューから Tools->Android->Sync Project with Gradle Files を選択してください。
  1. Eclipseのメニューから “Help” -> “Install New Software” を選択し、 “Eclipse Java Development Tools” をインストールします。
  2. realm-java をソースコードをcloneしてきます。
  3. 以下のコマンドを実行してソースコードをビルドします。

    sh ./build-distribution.sh
  4. distribution/eclipse/ からファイルをプロジェクトの libs にコピーしてください。
  5. libs にあるrealmのjarファイルを右クリックし、”Build Path” -> “Add to Build path” を選択してください。
  6. プロジェクトで右クリックをし、”Properties”を選択してください。”Java Compiler” -> “Annotation Processing” を選択し、 “Enable project specific settings” にチェックを入れ “Apply” をクリックしてください。
  7. 次に “Annotation Processing” -> “Factory Path” を選択し、”Enable project specific settings” をチェックします。”Click Add JARs” で、”libs” にあるrealmのjarファイルを選びます。そしてビルドしてください。
  8. アノテーション処理のために、アノテーション @RealmClass をRealmObjectのサブクラスを定義するときに入れておくことをオススメします。

Realm Browser

Realm Browserは、Mac OSX版でのみ対応しております。Windows, Linux版は現在、準備中ですので、もう少しお待ちください。

RealmBrowser は、Realmの中で使われるている .realm ファイルを閲覧、編集するMacアプリです。最新のCocoa版Realmbrowser/ フォルダの中に入っています。 また、Tools > Generate demo database を選択することでサンプルデータを含んだ、テスト用のRealmデータベースを作ることもできます。

サンプル

最新のRealmにあるサンプルをAndroid StudioでImport Projectをし、runで実行してください。

RealmIntroExample は、realm-java APIの使い方を理解するためのサンプルコードです。 サンプルコードを実行し、出力されるログを見るだけで簡単に理解することができます。

RealmGridViewExampleは、GridViewとRealmを組み合わせ方を理解するためのサンプルコードです。 どのようにJSONを使って、データを作成していくのか理解できます。

RealmConcurrencyExampleは、マルチスレッドでのRealmの使い方がわかるサンプルコードです。UIからの書き込み操作は可能でしょう。しかし、一番、面白いことはコードの中にあります。是非自分でコードを読んで、それを探してみてください!

ヘルプ

  • community newsletter に参加することで定期的にRealmに関するのTipsやUseCase, ブログポストやチュートリアルなど、Realmの最新情報がGetできます。
  • 私たちは、あなたの率直な意見をお待ちしております。是非、今後のRealm-javaの改善にご協力ください。質問や、機能追加要望などは、こちらにお願いいたします。
  • Help/debugなどに関しては、Google Groupに投稿してください。バグレポートは、直接、GitHub issuesにお願いいたします。

モデル

Realmで使うモデルクラスは、一般的な Java Bean と同じように定義できます。以下のように RealmObject のサブクラスを作ります。

public class User extends RealmObject {

    private String          name;
    private int             age;

    @Ignore
    private int             sessionId;

    // Standard getters & setters generated by your IDE…
    public String getName() { return name; }
    public void   setName(String name) { this.name = name; }
    public int    getAge() { return age; }
    public void   setAge(int age) { this.age = age; }
    public int    getSessionId() { return sessionId; }
    public void   setSessionId(int sessionId) { this.sessionId = sessionId; }
}

ここで、気を付けることは、ゲッター/セッターメソッドはRealmObjectが作るプロキシクラスによって上書きされることです。 ゲッター/セッターに書かれたロジックは実行されません。 Realm とオブジェクトは強く結びついてるので、realm.createObject()メソッドを使ってインスタンスを作成してください。

フィールドの型

Realmでは、以下の型がサポートされています。 boolean, short, int, long, float, double, String, Date, byte[] Realmでは、short, int, long 型が全て long 型として扱われます。また、 RealmObject のサブクラスと RealmList<? extends RealmObject> が関連付けのために使用されます。

無視されるプロパティ

アノテーション @Ignore を付けて宣言したフィールドは、ディスクに保存するときに除外されます。インプットされるデータが余分で使わないフィールドを含んでいる時に、そのフィールドを除外するときに有効となります。

検索インデックス

アノテーション @Index を付けると、検索インデックスを作成することができます。これを作ることで、データが挿入される時は遅く、データファイルは大きくなりますが、クエリ実行時により速く取得することができます。クエリを速く実行する必要があるところでのみ使うことをオススメします。 現在、string型でのみ(他の型のサポートは近々追加する予定です)使用可能です。検索インデックスは削除することはできません。

書き込み

読み込み処理は、どこからでもクエリを投げることができ、いつでもデータにアクセスできます。 しかし、書き込み(追加、変更、削除)処理は、必ずトランザクションの中で行わなければいけません。 Writeトランザクションは、コミットしたり途中でキャンセルすることが可能です。 コミットされるとディスクにデータが書き込まれ、全てのデータが保存されるとコミット処理が成功となります。 Writeトランザクションをキャンセルした場合、全ての変更は破棄されます。 Writeトランザクションを使用することで、データの整合性が保たれます。

Writeトランザクションは、スレッドセーフにするために使用します。

// Obtain a Realm instance
Realm realm = Realm.getInstance(this);

realm.beginTransaction();

//... add or update objects here ...

realm.commitTransaction();

Realmとオブジェクトは強く結びついてるので、Realmを使ってインスタンスを作成するべきです。

realm.beginTransaction();
User user = realm.createObject(User.class); // Create a new object
user.setName("John");
user.setEmail("[email protected]");
realm.commitTransaction();

Realmに新しくデータを追加する前に、途中までデータを作り、消したい場合があるとしましょう。 それらをコミットすることをやめ、変更を削除する場合、以下のように簡単にキャンセルすることができます。

realm.beginWriteTransaction();
User user = realm.createObject(User.class);

//  ... 

realm.cancelTransaction();

書き込み処理が行われている間は、他の処理をブロックしていることになります。 RealmはMVCCアーキテクチャーであるため、Writeトランザクションが開始されている状態でも、読み込み処理は正しくできます。 同時に複数のスレッドから書き込みする場合でない限り、長めのWriteトランザクションを使うことをオススメします。 Realmに書き込み処理をコミットしたとき、全てのRealmインスタンスは通知を受け、Readトランザクションは自動的に更新されます。 RealmのRead, Writeトランザクションは ACID に対応しています。

クエリ

Realmでのフェッチ(クエリを含む)は全て遅延評価です。また、内部で使われるデータはコピーされません。

Realmのクエリの仕組みは複数の条件を指定できるようにFluent interfaceを使っています。 nameの値が JohnPeter である全てのオブジェクトを取得の仕方は以下の通りです。

// Build the query looking at all users:
RealmQuery<User> query = realm.where(User.class);

// Add query conditions:
query.equalTo("name", "John");
query.or().equalTo("name", "Peter");

// Execute the query:
RealmResults<User> result1 = query.findAll();

// Or alternatively do the same all at once (the "Fluent interface"):
RealmResults<User> result2 = realm.where(User.class)
                                  .equalTo("name", "John")
                                  .or()
                                  .equalTo("name", "Peter")
                                  .findAll();

この例では、nameの値が JohnPeter であるデータが RealmResults として返ってきます。この時、データはコピーされません。 該当するオブジェクトのリストの参照を取得することができ、クエリで取得できるオブジェクトを直接、操作することができます。

RealmResults の値を変更、削除したりする場合は、Writeトランザクション内で行わなければいけません。 読み込み処理の場合は上手く機能し、遅延なしにデータにアクセスできます。

条件文

以下の条件文がサポートされています。

  • between, greaterThan(), lessThan(), greaterThanOrEqualTo() & lessThanOrEqualTo()
  • equalTo() & notEqualTo()
  • contains(), beginsWith() & endsWith()

ただし、全てのデータタイプに対応しているわけではありません。 詳しくは、RealmQuery をご覧ください。

論理式

すべての条件文は論理積です。論理和を使う場合は or() を使用します。 グループを特定するためにグループ挿入句を使用します。以下のように beginGroup()で始め、endGroup()で終わります。

RealmResults<User> r = realm.where(User.class)
                            .greaterThan("age", 10)  //implicit AND
                            .beginGroup()
                                .equalTo("name", "Peter")
                                .or()
                                .contains("name", "Jo")
                            .endGroup()
                            .findAll();

ソート

クエリの実行後は、以下のように結果をソートすることができます。

RealmResults<User> result = realm.where(User.class).findAll();
RealmResults<User> sortedAscending  = result.sort("age");
RealmResults<User> sortedDescending = result.sort("age", RealmResults.SORT_ORDER_DECENDING);

連続したクエリの実行

連続してクエリを実行することで、データをフィルタしていくことができます。

RealmResults<Person> teenagers = realm.where(Person.class).between("age", 13, 20).findAll();
Person firstJohn = teenagers.where().equalTo("name", "John").findFirst();

集約

RealmResults は様々な集約をすることができます。

RealmResults<User> results = realm.where(User.class).findAll();
long   sum     = results.sum("age").longValue();
long   min     = results.min("age").longValue();
long   max     = results.max("age").longValue();
double average = results.average("age");

long   matches = results.size();

反復処理

RealmResults は、イテレーションのために Iterable インターフェイスを持っています。

RealmResults<User> results = realm.where(User.class).findAll();
for (User u : results) {
    // ... do something with the object ...
}

もちろん、以下のような for ループも使用できます。

RealmResults<User> results = realm.where(User.class).findAll();
for (int i = 0; i < results.size(); i++) {
    User u = results.get(i);
    // ... do something with the object ...
}

削除

クエリの結果を使ってRealmからデータを削除することができます。

// All changes to data must happen in a transaction
realm.beginTransaction();

// remove single match
result.remove(0);
result.removeLast();

// Delete all matches
result.clear();

realm.commitTransaction()

Realms

Realmは、データベースと同等のもので、異なるオブジェクトを含んでおり、これらは一つのファイルに保存されています。

デフォルトRealm

Realm.getInstance(this) を呼び出すことで、realm変数を初期化してることをもうお気づきでしょう。 このシングルトンメソッドは、インスタンスを返します。これは、プロジェクトフォルダのルートにある、Fileフォルダの中にある default.realm のものです。

その他のRealm

場合によっては、複数のRealmを使いたい時があります。たとえば、機能ごとに異なるグループ分けされたデータベースがある場合などです。

Realm realm = Realm.getInstance(this, "allmymovies.realm");

スレッド間での実行

スレッド間での使用方法として覚えておく必要があることは、Realm, RealmObject, RealmResultsインスタンスは、スレッド間での受け渡しはできません。複数のスレッドで同じデータにアクセスしたい場合は、それぞれのスレッドで別々のRealmインスタンスを( Realm.getInstance(this) や似たようなメソッドを使って)作成する必要があります。それを通してRealmQueryを取得する必要があります。 別々のスレッドから同じRealmファイルにアクセスすることができ、それぞれのスレッドで読み書きができます。

関連

RealmObject は、お互いに関連付けを行うことができます。

public class Email extends RealmObject {
    private String address;
    private boolean active;
    // ... setters and getters left out
}

public class Contact extends RealmObject {
    private String name;
    private Email email;
    // ... setters and getters left out
}

リレーションシップは、スピードの観点からいうと特にオーバーヘッドなく素早く動きます。また、メモリの消費量の点でも効率的に機能します。

多対一

モデル間で多対一や一対一の関連性を持たせたい場合は、RLMObjectモデルクラスのフィールドを宣言します。

public class Contact extends RealmObject {
    private Email email;
    // Other fields…
}

これで、Contact インスタンスでは、Email インスタンスと関連付けを行うことができます。Realmにおいて、複数の Contact インスタンスから一つの Email インスタンスの関連を持つこともできます。このモデルでは、多対一の関連付けも行うことができますが、たいてい一対一の関連付けで使われると思います。

多対多

RealmList<T> フィールドを追加することで対多の関連を持たせることができます。

public class Contact extends RealmObject {
    private RealmList<Email> emails;
    // Other fields…
}

RealmListクラスは、基本的にRealmObjectのコンテナクラスです。振る舞いは、JavaのListクラスと似ています。異なるRealmListから一つのオブジェクトへの関連付けを行うことはできます。特に制約はありません。 また、これらは一対多、多対多で使うことができます。ゲッター/セッターを関連付けのフィールドのために追加することができます。

realm.beginTransaction();
Contact contact = realm.createObject(Contact.class);
contact.setName("John Doe");

Email email1 = realm.createObject(Email.class);
email1.setAddress("[email protected]");
email1.setActive(true);
contact.getEmails().add(email1);

Email email2 = realm.createObject(Email.class);
email2.setNumber("[email protected]");
email2.setActive(false);
contact.getEmails().add(email2);

realm.commitTransaction();

再帰的な関連付けの定義もできます。

public class Person extends RealmObject {
    private String name;
    private RealmLink<Person> friends;
    // Other fields…
}

現在、Realmでは循環された関連を見つける仕組みはまだありませんので、簡単に無限ループを発生しかねます。 使用される場合は十分、ご注意ください。

関連付いてるオブジェクトに対してクエリを実行することも可能です。以下のモデルを考えて下さい。 emailactive=trueContactインスタンスだけを取得したい場合はこのようにします。

RealmResults<Contact> contacts = realm.where(Contact.class).equalTo("emails.active", true).findAll();

まず、equalsTo を使ってフィールドの状態を調べていることが分かると思います。

上記のクエリは、「少なくとも一つはactiveフィールドがtrueなmailインスタンスを持ったContactインスタンスを取得してください」という意味になります。 ここでは、取得されるContactインスタンスの、全てのEmailオブジェクトがactive=trueではないことを理解することが重要です。

通知

バックグランド処理など他のスレッドやプロセスでRealmの状態に変更があった時に、Listenerを追加しておくことで、通知を受け取ることができます。

realm.addChangeListener(new RealmChangeListener() {
    @Override
    public void onChange() {
        // ... do something with the updates (UI, etc.) ...
    }
});

また、Listenersを簡単に削除することができます。

realm.removeAllChangeListeners();

マイグレーション

データベースを使ってる場合、時間が経つにつれ、データモデルというのは変更されていくものです。 Realmでのデータモデルは、一般的なクラスの定義と同じで、Realmモデルクラスに変更を加えるだけで、簡単にデータモデルを変えられます。

まだ古いスキーマのデータがディスクに保存されていないなら、変更を加えても問題なく動きます。しかし、古いスキーマのデータがディスクに保存されている場合、ディスクに保存されているスキーマとRealmモデルクラスとして定義されてるスキーマでミスマッチが起こり、例外が投げられます。

Migrationのための用意されてるメソッドを使って、ディスクにあるデータを新しいスキーマに適応させます。 詳しくは、migration sample app をご覧ください。

暗号化

暗号化サポートは、まだ実験段階の機能です。現在、より使いやすくするために機能改善中です。

Realm.create()の呼び出し時に、256ビット長の暗号鍵を使って、Realmファイルを暗号化してディスクに保存することができます。

byte[] key = new byte[32];
new SecureRandom().nextBytes(key);
Realm realm = Realm.create(this, key);

// ... use the Realm as normal ...

これでAES256を使って、暗号化し保存することができます。 Realmファイルが作成された時に使用された暗号化キーと同じものを毎回、使われなければいけません。

詳しくは、examples/encryptionExample をご覧ください。 ただし、他のアプリケーションからは、このファイルを読み込むことはできません。

暗号化を使用するにはソースコードからRealmをビルドする必要があります。

  1. ビルド手順に従ってビルドしてください。ただし、./gradlew assemble を実行する前に local.propertiesファイルに encryption=true を一行追加してください。
  2. ビルド後は、プロジェクト内にある、realm-<VERSION>.aarrealm/build/outputs/aar/realm-<VERSION>.aar にあるものを置き換えてください。

次のステップ

Realmをより深く理解する、次のステップとして、サンプルコードを用意しています。 HAPPY HACKING!! Google グループ Realm で、あなたはいつでもRealmデベロッパーと議論ができます。

FAQ

Realmをプロダクション環境で使うことはできますか?

Realmは、2012年から商業利用がされています。 ご利用される場合は、RealmのJAVA APIが、頻繁に変わるものだとお考えの上、Community Feedback を確認しながらお使いください。 機能追加、バグ修正も同様にお考えください。

Relamを使うのにお金を払わないといけませんか?

いいえ、Realmは、完全に無料です。商業利用も可能です。

どのようなビジネスプランなのですか?

すでにエンタープライズ向けの商品の販売や、周辺サービスによって収益を得ています。もし現在リリースされているものやrealm-javaで更に必要なものがあれば、いつでもメールで、お気軽にご連絡ください。また私たちのビジネスとは関係なく、realm-javaはオープンに開発をつづけていき、Apache License 2.0の元にオープンソースで公開し続けます。

“tightdb” や “core” という文字をコードの中で見たのですが、これは何ですか?

TightDBというのは、C++で実装されたストレージエンジンの名前です。現在、オープンソースではありませんが、Apache License 2.0として公開することを検討中です。 バイナリリリースは、Realm Core (TightDB) Binary License として利用可能です。