SQLite(Kotlin マルチプラットフォーム)

androidx.sqlite ライブラリには抽象的なインターフェースとともに基本的な実装が含まれており、これを使用して SQLite にアクセスする独自のライブラリを構築できます。Room ライブラリの使用を検討することをおすすめします。このライブラリは、SQLite の抽象レイヤを提供しており、SQLite の全機能を活用できると同時に、より強固なデータベース アクセスが可能です。

依存関係を設定する

KMP プロジェクトで SQLite を設定するには、モジュールの build.gradle.kts ファイルにアーティファクトの依存関係を追加します。

[versions]
sqlite = "2.5.2"

[libraries]
# The SQLite Driver interfaces
androidx-sqlite = { module = "androidx.sqlite:sqlite", version.ref = "sqlite" }

# The bundled SQLite driver implementation
androidx-sqlite-bundled = { module = "androidx.sqlite:sqlite-bundled", version.ref = "sqlite" }

[plugins]
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }

SQLite ドライバ API

androidx.sqlite ライブラリ グループは、androidx.sqlite:sqlite-bundled を使用する場合はライブラリに含まれる SQLite ライブラリ、androidx.sqlite:sqlite-framework を使用する場合は Android や iOS などのホスト プラットフォームと通信するための低レベル API を提供します。API は SQLite C API のコア機能に密接に沿っています。

主なインターフェースは次の 3 つです。

  • SQLiteDriver - SQLite を使用するためのエントリ ポイントであり、データベース接続のオープンを担当します。
  • SQLiteConnection - sqlite3 オブジェクトの表現です。
  • SQLiteStatement - sqlite3_stmt オブジェクトの表現です。

次の例は、コア API を示しています。

fun main() {
  val databaseConnection = BundledSQLiteDriver().open("todos.db")
  databaseConnection.execSQL(
    "CREATE TABLE IF NOT EXISTS Todo (id INTEGER PRIMARY KEY, content TEXT)"
  )
  databaseConnection.prepare(
    "INSERT OR IGNORE INTO Todo (id, content) VALUES (? ,?)"
  ).use { stmt ->
    stmt.bindInt(index = 1, value = 1)
    stmt.bindText(index = 2, value = "Try Room in the KMP project.")
    stmt.step()
  }
  databaseConnection.prepare("SELECT content FROM Todo").use { stmt ->
    while (stmt.step()) {
      println("Action item: ${stmt.getText(0)}")
    }
  }
  databaseConnection.close()
}

SQLite C API と同様に、一般的な使用方法は次のとおりです。

  • インスタンス化された SQLiteDriver 実装を使用してデータベース接続を開きます。
  • SQLiteConnection.prepare() を使用して SQL ステートメントを準備する
  • 次のように SQLiteStatement を実行します。
    1. 必要に応じて、bind*() 関数を使用して引数をバインドします。
    2. step() 関数を使用して結果セットを反復処理します。
    3. get*() 関数を使用して、結果セットから列を読み取ります。

ドライバの実装

次の表に、利用可能なドライバ実装の概要を示します。

クラス名

アーティファクト

対応プラットフォーム

AndroidSQLiteDriver androidx.sqlite:sqlite-framework

Android

NativeSQLiteDriver androidx.sqlite:sqlite-framework

iOS、Mac、Linux

BundledSQLiteDriver androidx.sqlite:sqlite-bundled

Android、iOS、Mac、Linux、JVM(デスクトップ)

使用するおすすめの実装は、androidx.sqlite:sqlite-bundled で利用可能な BundledSQLiteDriver です。これには、ソースからコンパイルされた SQLite ライブラリが含まれており、サポートされているすべての KMP プラットフォームで最新バージョンと一貫性が提供されます。

SQLite ドライバと Room

ドライバ API は、SQLite データベースとの低レベルのやり取りに役立ちます。SQLite へのより堅牢なアクセスを提供する機能豊富なライブラリには、Room をおすすめします。

RoomDatabaseSQLiteDriver に依存してデータベース オペレーションを実行します。実装は RoomDatabase.Builder.setDriver() を使用して構成する必要があります。Room は、マネージド データベース接続へのより直接的なアクセスを実現する RoomDatabase.useReaderConnectionRoomDatabase.useWriterConnection を提供します。

Kotlin マルチプラットフォームに移行する

低レベルの SQLite 呼び出しは、SQLite ドライバの対応する呼び出しに移行する必要があります。

Kotlin マルチプラットフォーム

低レベルの SQLiteConnection を使用してトランザクションを実行する

val connection: SQLiteConnection = ...
connection.execSQL("BEGIN IMMEDIATE TRANSACTION")
try {
  // perform database operations in transaction
  connection.execSQL("END TRANSACTION")
} catch(t: Throwable) {
  connection.execSQL("ROLLBACK TRANSACTION")
}

結果のないクエリを実行する

val connection: SQLiteConnection = ...
connection.execSQL("ALTER TABLE ...")

結果はあるが引数がないクエリを実行する

val connection: SQLiteConnection = ...
connection.prepare("SELECT * FROM Pet").use { statement ->
  while (statement.step()) {
    // read columns
    statement.getInt(0)
    statement.getText(1)
  }
}

結果と引数を使用してクエリを実行する

connection.prepare("SELECT * FROM Pet WHERE id = ?").use { statement ->
  statement.bindInt(1, id)
  if (statement.step()) {
    // row found, read columns
  } else {
    // row not found
  }
}

Android のみ

SupportSQLiteDatabase を使用してトランザクションを実行する

val database: SupportSQLiteDatabase = ...
database.beginTransaction()
try {
  // perform database operations in transaction
  database.setTransactionSuccessful()
} finally {
  database.endTransaction()
}

結果のないクエリを実行する

val database: SupportSQLiteDatabase = ...
database.execSQL("ALTER TABLE ...")

結果はあるが引数がないクエリを実行する

val database: SupportSQLiteDatabase = ...
database.query("SELECT * FROM Pet").use { cursor ->
  while (cusor.moveToNext()) {
    // read columns
    cursor.getInt(0)
    cursor.getString(1)
  }
}

結果と引数を使用してクエリを実行する

database.query("SELECT * FROM Pet WHERE id = ?", id).use { cursor ->
  if (cursor.moveToNext()) {
    // row found, read columns
  } else {
    // row not found
  }
}