「Realmの基礎知識 〜特徴と強みの再認識〜」
「モバイル データベース」で検索すると真っ先に出てくるRealm。
既に広く使われているRealmの基礎と特徴を解説します。
前置き
この記事は アイソルート Advent Calendar 2019 の22日目の記事です。
一昨日と昨日はokawa.mさんによる連投記事でした。
前々日:①Angular ngrx/storeを分かった気になってみる
前日 :②Angular ngrx/entityでよくあるCRUD操作を簡単に書いてみる
イントロ
こんにちは。モバイルソリューショングループのyamazaki.hです。
RDBではPostgreSQLが好きです。深い意味はありません。
そんな私が最近になってモバイル開発に携わり、Realmと出会い、RDBとの違いに困惑した話などを共有し、
Realmというものが一体どういったものなのかを改めてまとめていく記事となっています。
また、この記事ではiOSでの開発を前提として書きます。ご容赦ください。
対象読者
- Realmを使っているがその特徴や基礎を再確認したい方
- Realmとは一体何者だ、と思っている方
目次
Realmの基礎知識
一言で言い表すと「モバイル向けデータベース管理システム」
推奨されるプラットフォームは「スマートフォン」「タブレット」など。
現在はオープンソースであり、数多の開発者によって開発がなされています。
GitHub – Realm
サポートしている言語は以下の通り。
- Objective-C
- Swift
- Java(Androidのみ)
- Kotlin
- C#
- JavaScript
2016年にver1.0リリースとなったRealmですが、
開発された背景として、サーバーサイドのデータベースではいくつものデータベースシステムが開発されてきた中、
モバイルデバイス環境では2000年に登場したSQLite以降何もなかったことが挙げられます。
(画像引用元:https://realm.io/blog/introducing-realm/)
Realmの特徴と強み
非常に高速なデータベースアクセス
公式サイトのベンチマークを見るとわかる通り、非常に高速なアクセスを実現しています。
よくモバイル開発でのデータベースとして利用されるSQLiteと比較しても高速であるとわかります。
なにより驚きなのが、Appleの提供するCore Dataとの圧倒的な差です。
(画像引用元:https://realm.io/blog/introducing-realm/)
実装が容易
Realmの導入は非常に簡単で、プロジェクト自体への導入もCocoaPodsもしくはCarthageでのinstallが可能。
今回は導入方法を割愛します。
ソースコード上でRealmのデータベースを作成し、オブジェクトを保存する一連の流れは以下になります。
// Cat.swift
class Cat: Object {
@objc dynamic var name = ""
@objc dynamic var age = 0
}
// Insert.swift
let cat = Cat()
cat.name = "Tama"
cat.age = 1
let realm = try! Realm()
try! realm.write {
realm.add(cat)
}
これだけでデータベースにオブジェクトが保存できます。
また、データベースから取り出す処理は以下です。
// Select.swift
let kittens = realm.objects(Cat.self).filter("age < 2")
クラスの定義がそのままテーブル定義になるのでマッピングなどの作業が不要になり、実装が非常に容易になります。
内部的には特定のクラス「Object」を継承したクラスのクラス名およびプロパティの名前と型を取得して、
スキーマを生成しデータベースに保存する処理が行われています。
RDBとの操作比較
私がもともとPostgreSQLを触っていたのも影響するのですが、
データベースへのアクセスがRDBの操作とは全く違うことに非常に困惑しました。
そこで、RDBの基本動作と同等の処理がRealmではどのように行われるかを解説します。
CREATE DATABASE
Realmでは「.realm」という拡張子のついたファイルがデータベースとして生成されます。
このファイルはインスタンスの生成時に自動で生成されます。
// CreateDatabase.swift
// デフォルトのデータベース
let realm = try! Realm()
// ファイルを指定したデータベース
let realm = try! Realm(fileURL: YOUR_REALM_FILE_PATH)
// インメモリで使用するようにconfigを適用したデータベース
let configration = Realm.Configuration(inMemoryIdentifier: "メモリ空間名")
let realm = try! Realm(configration: configration)
DROP DATABASE
「.realm」で管理されているので、ファイルをまるまる消します。
ファイルを残して中身を空にもできます。
// DropDatabase.swift
// データベースまるまる削除
NSFileManager.defaultManager().removeItemAtURL(Realm.Configuration.defaultConfiguration.fileURL!)
// ファイルは残すが、中身を空っぽに
try! realm.write {
realm.deleteAll()
}
CREATE TABLE
一般的なRDBで利用するようなTABLE定義はRealmには不要です。
Realmはモデルクラスの定義がそのままテーブル定義となるからです。
例えば以下のようなTABLE定義があるとします。
-- CreateTable.sql
CREATE TABLE cats (
id int PRIMARY KEY,
name varchar(64),
age int
)
これをRealmで定義すると以下のようになります。
//Cat.swift
class Cat: Object {
@objc dynamic var id = ""
@objc dynamic var name = ""
@objc dynamic var age = 0
override class func primaryKey() -> String! {
return "id"
}
}
SELECT
Realmのデータベースインスタンスに対し、「objects()」を呼ぶことでSELECTが可能です。
// Select.swift
// 保存されている全オブジェクトを取得
let allCats = realm.objects(Cat.self)
// 条件に合うオブジェクトを取得
let kittens = realm.objects(Cat.self).filter("age < 2")
INSERT
データベースへの永続化は非常に簡単です。
レコードを操作するためのトランザクション処理は2つの方法があります。
- Transactionメソッドを利用
- writeブロックを利用
// Insert.swift
// Transactionメソッドを利用
realm.beginWriteTransaction()
realm.add(newCat)
realm.commitWriteTransaction()
// writeブロックを利用
try! realm.write {
realm.add(newCat)
}
UPDATE
データベースのインスタンスから取得したオブジェクトに対して、
プロパティを更新するとそのままデータベースに反映されます。
ただし、トランザクション外だと例外が発生します。
// Update.swift
// 更新対象を取得
let cat = realm.objects(Cat.self).filter("id = 1")
// writeブロックを利用
try! realm.write {
cat.name = "mikan"
}
DELETE
データベースのインスタンスから「delete()」を利用します。
こちらもトランザクション外だと例外が発生します。
// Delete.swift
// 削除対象を取得
let cat = realm.objects(Cat.self).filter("name = 'tora'")
// writeブロックを利用
try! realm.write {
realm.delete(cat)
}
まとめ
Realmは他のデータベースと比較して性能の良いデータベース管理システムです。
オープンソースであり、世界中の開発者が開発に携わっています。
プロジェクトへの導入や実際のCRUD操作などが非常に簡単。
あとがき
一般的なRDBしか触ってこなかった私ですが、Realmの概要を知ることができました。
記事作成を通してRealmのソースを少しばかり覗いたのですが、もっと理解するためにもソースの内部まで読み解くのも良いかもしれません。
今回は基礎中の基礎を再確認する内容でした。
この記事がRealm理解への第一歩となれば幸いです。
明日はakahane.tさんの新米エンジニアがGitで失敗して学んだことです。
お楽しみに。