KMP용 SQLite 설정

androidx.sqlite 라이브러리에는 SQLite에 액세스하는 자체 라이브러리를 빌드하는 데 사용할 수 있는 기본 구현과 함께 추상 인터페이스가 포함되어 있습니다. 개발자는 SQLite를 완벽히 활용하면서 강력한 데이터베이스 액세스를 지원하는 SQLite의 추상화 레이어를 제공하는 Room 라이브러리 사용을 고려할 수 있습니다.

종속 항목 설정

KMP 프로젝트에서 SQLite를 설정하려면 모듈의 build.gradle.kts 파일에 아티팩트의 종속 항목을 추가합니다.

[versions]
sqlite = "2.7.0"

[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을 사용할 때 라이브러리에 포함되거나 Android 또는 iOS와 같은 호스트 플랫폼에 androidx.sqlite:sqlite-framework을 사용할 때 포함된 SQLite 라이브러리와 통신하기 위한 하위 수준 API를 제공합니다. API는 SQLite C API의 핵심 기능을 긴밀하게 따릅니다.

세 가지 기본 인터페이스가 있습니다.

다음 예는 핵심 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와 마찬가지로 일반적인 사용 패턴은 다음 단계로 구성됩니다.

  1. 인스턴스화된 SQLiteDriver 구현을 사용하여 데이터베이스 연결을 엽니다.
  2. SQLiteConnection.prepare를 사용하여 SQL 문을 준비합니다.
  3. 다음을 실행하여 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 (데스크톱)

WebWorkerSQLiteDriver androidx.sqlite:sqlite-web

JavaScript 및 WebAssembly (WasmJS)

사용하는 것이 좋은 구현은 androidx.sqlite:sqlite-bundled에서 사용할 수 있는 BundledSQLiteDriver입니다. 여기에는 소스에서 컴파일된 SQLite 라이브러리가 포함되어 있으며 지원되는 모든 KMP 플랫폼에서 최신 버전과 일관성을 제공합니다.

SQLite 드라이버 및 Room

드라이버 API는 SQLite 데이터베이스와의 하위 수준 상호작용에 유용합니다. SQLite에 더 강력한 액세스를 제공하는 다양한 기능이 포함된 라이브러리의 경우 Room을 사용하는 것이 좋습니다.

A RoomDatabase는 데이터베이스 작업을 실행하기 위해 SQLiteDriver에 의존하며 RoomDatabase.Builder.setDriver를 사용하여 구현을 구성해야 합니다. Room은 관리되는 데이터베이스 연결에 더 직접적으로 액세스할 수 있도록 RoomDatabase.useReaderConnectionRoomDatabase.useWriterConnection을 제공합니다.

Kotlin 멀티플랫폼으로 이전

SupportSQLiteDatabase 인터페이스와 같은 하위 수준 지원 SQLite API 구성요소의 모든 사용을 상응하는 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 (cursor.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
  }
}