概要
Android で SQLite を使う方法です。 サンプルにはデータの参照、挿入、トランザクションを含みます。
参考情報
サンプルコード
解説
- Database.kt
- Database : SQLiteOpenHelper を実装して汎用的な処理を行うクラス
- SQLiteDatabaseExtensions.kt : update, insert メソッドの引数を省略できるようにするための拡張関数
- SampleDB.kt
- SampleDB : サンプルデータベースの定義
- SampleDB.Dao : サンプルデータベースが持つ DAO の一覧
- SampleTableDao.kt
- SampleTableDao : DAO (Data Access Object)
- Client.kt
- Client : 上記のクラスを使用して処理を行うクラス
Android で SQLite を使うには SQLiteOpenHelper を使用する。 Database にて SQLiteOpenHelper を使用している。 データベースファイルが存在しない場合には onCreate メソッドが呼ばれるため、onCreate メソッドが呼ばれたらテーブルを作成する。 テーブルの作成は SampleDB.Dao に処理を委譲して実現している。 SampleDB.Dao は SampleTableDao に処理を委譲する。 複数の DAO がある場合には、複数の DAO に処理を委譲する。 データベースのバージョンが変更された場合には onUpgrade メソッドが呼ばれるが、今回のサンプルでは未実装。
// Database private val helper = object : SQLiteOpenHelper(context, def.name, def.cursorFactory, def.version) { override fun onCreate(db: SQLiteDatabase) { def.create(db).onCreate() } override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {} }
CRUD 操作は、SQLiteOpenHelper から readableDatabase と writableDatabase を取得して行う。 readableDatabase と writableDatabase は共に SQLiteDatabase のインスタンス。 SQLiteDatabase は query メソッドや insert メソッドを持つ。 query メソッドや insert メソッドの呼び出しは、SampleTableDao の仕事。 query メソッドと insert メソッドは多くの引数を持ち、全ての引数を指定する必要のない場合がある。 引数を省略できるようにするために SQLiteDatabaseExtensions.kt で拡張関数を定義している。
// Database helper.readableDatabase.use { ... } // use 関数により readableDatabase は close() される helper.writableDatabase.use { ... } // use 関数により writableDatabase は close() される
// SampleTableDao fun insert(seqId: Int, time: Int, type: Int) { val values = ContentValues().apply { put("seq_id", seqId) put("time", time) put("type", type) } db.insert(TABLE_NAME, values) // SQLiteDatabaseExtensions.kt で定義された拡張関数 }
Client では CRUD 操作を行う関数を定義し、Database の update メソッドに渡す。 関数のブロックがトランザクションに対応する。 例外を発生させることなく関数を終えた場合にはコミットされ、例外が発生した場合にはロールバックされる。 トランザクション管理は Database で行っている。 update メソッドでは、関数実行前に beginTransaction() を実行、実行後に endTransaction() を実行している。 例外が発生しなかった場合には setTransactionSuccessful() を実行してコミットされるようにする。
// Database // it は SQLiteDatabase のインスタンス it.beginTransaction() try { val result = procedure(def.create(it)) it.setTransactionSuccessful() return result } finally { it.endTransaction() }
update メソッドが受け取る関数では、引数に SampleDB.Dao を受け取る。 SampleDB.Dao が保持する SampleTableDao に処理を委譲することで CRUD 操作が行われる。 テーブルが増えた場合には SampleDB.Dao に各テーブルの DAO を加える。
// Client db.update { // トランザクション開始 // it は SampleDB.Dao のインスタンス val seqId = it.sampleTable.nextSeqId() it.sampleTable.insert(seqId, time, type) } // トランザクション終了 (例外が発生しなければコミットされる)
Kotlin 補足
Kotlin は全く知らないという方のための補足。
use 関数
下記のコードは同じこと。
// Kotlin
helper.writableDatabase.use {
it.beginTransaction()
...
}
// Java try (SQLiteDatabase it = helper.getWritableDatabase()) { it.beginTransaction() ... }