SQLite (Multiplatform Kotlin)

Library androidx.sqlite berisi antarmuka abstrak beserta implementasi dasar yang dapat digunakan untuk membuat library Anda sendiri yang mengakses SQLite. Sebaiknya Anda menggunakan library Room, yang menyediakan lapisan abstraksi di atas SQLite untuk memungkinkan akses database yang lebih andal sekaligus memanfaatkan kekuatan penuh SQLite.

Menyiapkan dependensi

Untuk menyiapkan SQLite di project KMP, tambahkan dependensi untuk artefak dalam file build.gradle.kts untuk modul Anda:

[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 Driver API

Grup library androidx.sqlite menawarkan API tingkat rendah untuk berkomunikasi dengan library SQLite yang disertakan dalam library saat menggunakan androidx.sqlite:sqlite-bundled atau di platform host, seperti Android atau iOS saat menggunakan androidx.sqlite:sqlite-framework. API ini mengikuti fungsi inti SQLite C API.

Ada 3 antarmuka utama:

  • SQLiteDriver - Ini adalah titik entri untuk menggunakan SQLite dan bertanggung jawab untuk membuka koneksi database.
  • SQLiteConnection - Adalah representasi objek sqlite3.
  • SQLiteStatement - Adalah representasi objek sqlite3_stmt.

Contoh berikut menunjukkan API inti:

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()
}

Serupa dengan SQLite C API, penggunaan umumnya adalah:

  • Buka koneksi database menggunakan penerapan SQLiteDriver yang di-instansiasi.
  • Siapkan pernyataan SQL menggunakan SQLiteConnection.prepare()
  • Jalankan SQLiteStatement dengan cara berikut:
    1. Opsional, ikat argumen menggunakan fungsi bind*().
    2. Lakukan iterasi pada set hasil menggunakan fungsi step().
    3. Baca kolom dari set hasil menggunakan fungsi get*().

Implementasi Driver

Tabel berikut merangkum penerapan driver yang tersedia:

Nama Kelas

Artefak

Platform yang Didukung

AndroidSQLiteDriver androidx.sqlite:sqlite-framework

Android

NativeSQLiteDriver androidx.sqlite:sqlite-framework

iOS, Mac, dan Linux

BundledSQLiteDriver androidx.sqlite:sqlite-bundled

Android, iOS, Mac, Linux, dan JVM (Desktop)

Penerapan yang direkomendasikan untuk digunakan adalah BundledSQLiteDriver yang tersedia di androidx.sqlite:sqlite-bundled. Library ini mencakup library SQLite yang dikompilasi dari sumber, yang menawarkan versi terbaru dan konsistensi di semua platform KMP yang didukung.

Driver SQLite dan Room

API driver berguna untuk interaksi tingkat rendah dengan database SQLite. Untuk library kaya fitur yang menyediakan akses SQLite yang lebih andal, sebaiknya gunakan Room.

RoomDatabase mengandalkan SQLiteDriver untuk melakukan operasi database dan implementasi harus dikonfigurasi menggunakan RoomDatabase.Builder.setDriver(). Room menyediakan RoomDatabase.useReaderConnection dan RoomDatabase.useWriterConnection untuk akses yang lebih langsung ke koneksi database yang dikelola.

Bermigrasi ke Multiplatform Kotlin

Penggunaan panggilan SQLite tingkat rendah harus dimigrasikan ke rekanan Driver SQLite-nya.

Multiplatform Kotlin

Melakukan transaksi menggunakan SQLiteConnection tingkat rendah

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")
}

Menjalankan kueri tanpa hasil

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

Menjalankan kueri dengan hasil, tetapi tanpa argumen

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

Menjalankan kueri dengan hasil dan argumen

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

Khusus Android

Melakukan transaksi menggunakan SupportSQLiteDatabase

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

Menjalankan kueri tanpa hasil

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

Menjalankan kueri dengan hasil, tetapi tanpa argumen

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

Menjalankan kueri dengan hasil dan argumen

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