Biblioteka androidx.sqlite zawiera abstrakcyjne interfejsy oraz podstawowe implementacje, których można używać do tworzenia własnych bibliotek, które mają dostęp do SQLite. Warto rozważyć użycie biblioteki Room, która zapewnia
warstwę abstrakcji nad SQLite, aby umożliwić bardziej niezawodny dostęp do bazy danych przy
jednoczesnym wykorzystaniu pełnej mocy SQLite.
Konfigurowanie zależności
Aby skonfigurować SQLite w projekcie KMP, dodaj zależności artefaktów w pliku build.gradle.kts modułu:
[versions]
sqlite = "2.6.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" }
Interfejsy API sterownika SQLite
Biblioteka androidx.sqlite grupuje interfejsy API niskiego poziomu do komunikacji z
biblioteką SQLite, która jest dołączona do biblioteki w przypadku używania
androidx.sqlite:sqlite-bundled lub na platformie hosta, np. Androida lub iOS,
w przypadku używania androidx.sqlite:sqlite-framework. Interfejsy API ściśle odpowiadają podstawowym funkcjom interfejsu SQLite C API.
Dostępne są 3 główne interfejsy:
SQLiteDriver– punkt wejścia do korzystania z SQLite, który odpowiada za otwieranie połączeń z bazą danych.SQLiteConnection– reprezentacja obiektusqlite3.SQLiteStatement– reprezentacja obiektusqlite3_stmt.
Ten przykład pokazuje podstawowe interfejsy 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()
}
Podobnie jak w przypadku interfejsów SQLite C API typowe użycie polega na:
- otwieraniu połączenia z bazą danych za pomocą utworzonej implementacji
SQLiteDriver. - przygotowywaniu instrukcji SQL za pomocą
SQLiteConnection.prepare() - wykonywaniu
SQLiteStatementw ten sposób:- Opcjonalnie powiąż argumenty za pomocą funkcji
bind*(). - Iteruj po zbiorze wyników za pomocą funkcji
step(). - Odczytuj kolumny ze zbioru wyników za pomocą funkcji
get*().
- Opcjonalnie powiąż argumenty za pomocą funkcji
Implementacje sterowników
W tabeli poniżej znajdziesz podsumowanie dostępnych implementacji sterowników:
Nazwa zajęć |
Artefakt |
Obsługiwane platformy |
AndroidSQLiteDriver |
androidx.sqlite:sqlite-framework |
Android |
NativeSQLiteDriver |
androidx.sqlite:sqlite-framework |
iOS, Mac i Linux |
BundledSQLiteDriver |
androidx.sqlite:sqlite-bundled |
Android, iOS, Mac, Linux i JVM (komputer) |
Zalecana implementacja to BundledSQLiteDriver dostępna w androidx.sqlite:sqlite-bundled. Zawiera ona bibliotekę SQLite skompilowaną ze źródła, dzięki czemu zapewnia najbardziej aktualną wersję i spójność na wszystkich obsługiwanych platformach KMP.
Sterownik SQLite i Room
Interfejsy API sterowników są przydatne do interakcji niskiego poziomu z bazą danych SQLite. Jeśli potrzebujesz biblioteki z wieloma funkcjami, która zapewnia bardziej niezawodny dostęp do SQLite, zalecamy użycie Room.
A RoomDatabase korzysta z SQLiteDriver do wykonywania operacji na bazie danych i
implementację należy skonfigurować za pomocą
RoomDatabase.Builder.setDriver(). Room udostępnia
RoomDatabase.useReaderConnection i
RoomDatabase.useWriterConnection do bardziej bezpośredniego dostępu do zarządzanych
połączeń z bazą danych.
Migracja do Kotlin Multiplatform
Każde użycie komponentów interfejsu Support SQLite API niskiego poziomu (np. interfejsu SupportSQLiteDatabase) należy przenieść na równoważne komponenty sterownika SQLite.
Kotlin Multiplatform
Wykonaj transakcję za pomocą SQLiteConnection niskiego poziomu
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")
}
Wykonaj zapytanie bez wyniku
val connection: SQLiteConnection = ...
connection.execSQL("ALTER TABLE ...")
Wykonaj zapytanie z wynikiem, ale bez argumentów
val connection: SQLiteConnection = ...
connection.prepare("SELECT * FROM Pet").use { statement ->
while (statement.step()) {
// read columns
statement.getInt(0)
statement.getText(1)
}
}
Wykonaj zapytanie z wynikiem i argumentami
connection.prepare("SELECT * FROM Pet WHERE id = ?").use { statement ->
statement.bindInt(1, id)
if (statement.step()) {
// row found, read columns
} else {
// row not found
}
}
Tylko Android
Wykonaj transakcję za pomocą SupportSQLiteDatabase
val database: SupportSQLiteDatabase = ...
database.beginTransaction()
try {
// perform database operations in transaction
database.setTransactionSuccessful()
} finally {
database.endTransaction()
}
Wykonaj zapytanie bez wyniku
val database: SupportSQLiteDatabase = ...
database.execSQL("ALTER TABLE ...")
Wykonaj zapytanie z wynikiem, ale bez argumentów
val database: SupportSQLiteDatabase = ...
database.query("SELECT * FROM Pet").use { cursor ->
while (cusor.moveToNext()) {
// read columns
cursor.getInt(0)
cursor.getString(1)
}
}
Wykonaj zapytanie z wynikiem i argumentami
database.query("SELECT * FROM Pet WHERE id = ?", id).use { cursor ->
if (cursor.moveToNext()) {
// row found, read columns
} else {
// row not found
}
}