SQLite (Kotlin 멀티플랫폼)

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

종속 항목 설정

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 사용 시 라이브러리에 포함되거나 androidx.sqlite:sqlite-framework 사용 시 Android 또는 iOS와 같은 호스트 플랫폼에 포함된 SQLite 라이브러리와 통신하기 위한 하위 수준 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
  }
}