Die androidx.sqlite
-Bibliothek enthält abstrakte Schnittstellen sowie grundlegende Implementierungen, mit denen Sie eigene Bibliotheken erstellen können, die auf SQLite zugreifen. Sie sollten die Room-Bibliothek in Betracht ziehen, die eine Abstraktionsebene für SQLite bietet, um einen robusteren Datenbankzugriff zu ermöglichen und gleichzeitig die volle Leistungsfähigkeit von SQLite zu nutzen.
Abhängigkeiten einrichten
Wenn Sie SQLite in Ihrem KMP-Projekt einrichten möchten, fügen Sie die Abhängigkeiten für die Artefakte in die Datei build.gradle.kts
für Ihr Modul ein:
[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-Treiber-APIs
Die androidx.sqlite
-Bibliotheksgruppen bieten APIs auf niedriger Ebene für die Kommunikation mit der SQLite-Bibliothek, die entweder in der Bibliothek enthalten ist, wenn androidx.sqlite:sqlite-bundled
verwendet wird, oder auf der Hostplattform, z. B. Android oder iOS, wenn androidx.sqlite:sqlite-framework
verwendet wird. Die APIs orientieren sich eng an den Kernfunktionen der SQLite C-API.
Es gibt drei Hauptschnittstellen:
SQLiteDriver
: Dies ist der Einstiegspunkt für die Verwendung von SQLite und für das Öffnen von Datenbankverbindungen zuständig.SQLiteConnection
: die Darstellung dessqlite3
-Objekts.SQLiteStatement
: die Darstellung dessqlite3_stmt
-Objekts.
Im folgenden Beispiel werden die wichtigsten APIs vorgestellt:
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()
}
Ähnlich wie bei den SQLite C-APIs wird in der Regel so vorgegangen:
- Öffnen Sie eine Datenbankverbindung mit der instanziierten
SQLiteDriver
-Implementierung. - SQL-Anweisung mit
SQLiteConnection.prepare()
vorbereiten - So führen Sie eine
SQLiteStatement
aus:- Optional können Sie Argumente mit den
bind*()
-Funktionen binden. - Iterieren Sie mit der Funktion
step()
über das Ergebnis-Set. - Spalten aus dem Ergebnis-Set mit den
get*()
-Funktionen lesen.
- Optional können Sie Argumente mit den
Treiberimplementierungen
In der folgenden Tabelle sind die verfügbaren Treiberimplementierungen zusammengefasst:
Kursname |
Artefakt |
Unterstützte Plattformen |
AndroidSQLiteDriver |
androidx.sqlite:sqlite-framework |
Android |
NativeSQLiteDriver |
androidx.sqlite:sqlite-framework |
iOS, Mac und Linux |
BundledSQLiteDriver |
androidx.sqlite:sqlite-bundled |
Android, iOS, Mac, Linux und JVM (Desktop) |
Die empfohlene Implementierung ist BundledSQLiteDriver
, die in androidx.sqlite:sqlite-bundled
verfügbar ist. Sie enthält die aus dem Quellcode kompilierte SQLite-Bibliothek, die die aktuellste Version und Konsistenz auf allen unterstützten KMP-Plattformen bietet.
SQLite-Treiber und Room
Die Treiber-APIs sind nützlich für Low-Level-Interaktionen mit einer SQLite-Datenbank. Wenn Sie eine funktionsreiche Bibliothek benötigen, die einen robusteren Zugriff auf SQLite bietet, ist Room die richtige Wahl.
Für einen RoomDatabase
ist ein SQLiteDriver
erforderlich, um Datenbankvorgänge auszuführen. Eine Implementierung muss mit RoomDatabase.Builder.setDriver()
konfiguriert werden. Room bietet RoomDatabase.useReaderConnection
und RoomDatabase.useWriterConnection
für einen direkteren Zugriff auf die verwalteten Datenbankverbindungen.
Zu Kotlin Multiplatform migrieren
Alle Verwendungen von SQLite-Aufrufen auf niedriger Ebene müssen zu den entsprechenden SQLite-Treiber-Aufrufen migriert werden.
Transaktion mit Low-Level-SQLiteConnection
ausführen
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")
}
Abfrage ohne Ergebnis ausführen
val connection: SQLiteConnection = ...
connection.execSQL("ALTER TABLE ...")
Eine Abfrage mit Ergebnis, aber ohne Argumente ausführen
val connection: SQLiteConnection = ...
connection.prepare("SELECT * FROM Pet").use { statement ->
while (statement.step()) {
// read columns
statement.getInt(0)
statement.getText(1)
}
}
Abfrage mit Ergebnis und Argumenten ausführen
connection.prepare("SELECT * FROM Pet WHERE id = ?").use { statement ->
statement.bindInt(1, id)
if (statement.step()) {
// row found, read columns
} else {
// row not found
}
}
Transaktion mit SupportSQLiteDatabase
durchführen
val database: SupportSQLiteDatabase = ...
database.beginTransaction()
try {
// perform database operations in transaction
database.setTransactionSuccessful()
} finally {
database.endTransaction()
}
Abfrage ohne Ergebnis ausführen
val database: SupportSQLiteDatabase = ...
database.execSQL("ALTER TABLE ...")
Eine Abfrage mit Ergebnis, aber ohne Argumente ausführen
val database: SupportSQLiteDatabase = ...
database.query("SELECT * FROM Pet").use { cursor ->
while (cusor.moveToNext()) {
// read columns
cursor.getInt(0)
cursor.getString(1)
}
}
Abfrage mit Ergebnis und Argumenten ausführen
database.query("SELECT * FROM Pet WHERE id = ?", id).use { cursor ->
if (cursor.moveToNext()) {
// row found, read columns
} else {
// row not found
}
}