Room kalıcılık kitaplığı, SQLite'in tüm gücünden yararlanırken daha sağlam veritabanı erişimine olanak tanımak için SQLite üzerinde bir soyutlama katmanı sağlar. Bu sayfada, Kotlin Multiplatform (KMP) projelerinde Room'un kullanımı ele alınmaktadır. Room'u kullanma hakkında daha fazla bilgi için Room'u kullanarak verileri yerel veritabanına kaydetme başlıklı makaleyi veya resmi örneklerimizi inceleyin.
Bağımlılıkları ayarlama
KMP projenizde Room'u ayarlamak için KMP modülünüzün build.gradle.kts dosyasındaki yapılarla ilgili bağımlılıkları ekleyin.
Bağımlılıkları libs.versions.toml dosyasında tanımlayın:
[versions]
room3 = "3.0.1"
sqlite = "2.7.0"
ksp = "<kotlinCompatibleKspVersion>"
[libraries]
androidx-sqlite-bundled = { module = "androidx.sqlite:sqlite-bundled", version.ref = "sqlite" }
androidx-room3-runtime = { module = "androidx.room3:room3-runtime", version.ref = "room3" }
androidx-room3-compiler = { module = "androidx.room3:room3-compiler", version.ref = "room3" }
# Optional SQLite Wrapper
androidx-room3-sqlite-wrapper = { module = "androidx.room3:room3-sqlite-wrapper", version.ref = "room3" }
[plugins]
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
androidx-room3 = { id = "androidx.room3", version.ref = "room3" }
Room şemalarını ve KSP eklentisini yapılandırmak için Room Gradle eklentisini ekleyin.
plugins {
alias(libs.plugins.ksp)
alias(libs.plugins.androidx.room3)
}
Room çalışma zamanı bağımlılığını ve paketlenmiş SQLite kitaplığını ekleyin:
commonMain.dependencies {
implementation(libs.androidx.room3.runtime)
implementation(libs.androidx.sqlite.bundled)
}
// Optional when using Room SQLite Wrapper
androidMain.dependencies {
implementation(libs.androidx.room3.sqlite.wrapper)
}
KSP bağımlılıklarını kök dependencies bloğuna ekleyin. Uygulamanızın kullandığı tüm hedefleri eklemeniz gerekir. Daha fazla bilgi için Kotlin Multiplatform ile KSP başlıklı makaleyi inceleyin.
dependencies {
add("kspAndroid", libs.androidx.room3.compiler)
add("kspIosSimulatorArm64", libs.androidx.room3.compiler)
add("kspIosX64", libs.androidx.room3.compiler)
add("kspIosArm64", libs.androidx.room3.compiler)
// Add any other platform target you use in your project, for example kspDesktop
}
Oda şeması dizinini tanımlayın. Daha fazla bilgi için Room Gradle eklentisini kullanarak şema konumunu ayarlama başlıklı makaleyi inceleyin.
room {
schemaDirectory("$projectDir/schemas")
}
Veritabanı sınıflarını tanımlama
Paylaşılan KMP modülünüzün ortak kaynak grubunda DAO'lar ve öğelerle birlikte @Database ile açıklama eklenmiş bir veritabanı sınıfı oluşturmanız gerekir. Bu sınıfları ortak kaynaklara yerleştirmek, tüm hedef platformlarda paylaşılmalarını sağlar.
// shared/src/commonMain/kotlin/Database.kt
@Database(entities = [TodoEntity::class], version = 1)
@ConstructedBy(AppDatabaseConstructor::class)
abstract class AppDatabase : RoomDatabase() {
abstract fun getDao(): TodoDao
}
// The Room compiler generates the `actual` implementations.
@Suppress("KotlinNoActualForExpect")
expect object AppDatabaseConstructor : RoomDatabaseConstructor<AppDatabase> {
override fun initialize(): AppDatabase
}
expect nesnesini RoomDatabaseConstructor arayüzüyle bildirdiğinizde Room derleyicisi actual uygulamalarını oluşturur. Android Studio aşağıdaki uyarıyı verebilir. Bu uyarıyı @Suppress("KotlinNoActualForExpect") ile bastırabilirsiniz:
Expected object 'AppDatabaseConstructor' has no actual declaration in module`
Ardından, yeni bir DAO arayüzü tanımlayın veya mevcut bir arayüzü commonMain'ye taşıyın:
// shared/src/commonMain/kotlin/TodoDao.kt
@Dao
interface TodoDao {
@Insert
suspend fun insert(item: TodoEntity)
@Query("SELECT count(*) FROM TodoEntity")
suspend fun count(): Int
@Query("SELECT * FROM TodoEntity")
fun getAllAsFlow(): Flow<List<TodoEntity>>
}
Varlıklarınızı commonMain konumuna tanımlayın veya taşıyın:
// shared/src/commonMain/kotlin/TodoEntity.kt
@Entity
data class TodoEntity(
@PrimaryKey(autoGenerate = true) val id: Long = 0,
val title: String,
val content: String
)
Platforma özel veritabanı oluşturucular oluşturma
Her platformda Room'u başlatmak için bir veritabanı oluşturucu tanımlamanız gerekir. Dosya sistemi API'lerindeki farklılıklar nedeniyle, API'nin yalnızca bu bölümünü platforma özgü kaynak kümelerinde tanımlamanız gerekir.
Android
Android'de, veritabanı konumunu genellikle Context.getDatabasePath API'sini kullanarak elde edersiniz. Veritabanı örneğini oluşturmak için bir
Context ve veritabanı yolunu belirtin.
// shared/src/androidMain/kotlin/Database.android.kt
fun getDatabaseBuilder(context: Context): RoomDatabase.Builder<AppDatabase> {
val appContext = context.applicationContext
val dbFile = appContext.getDatabasePath("my_room.db")
return Room.databaseBuilder<AppDatabase>(
context = appContext,
name = dbFile.absolutePath
)
}
iOS
iOS'te veritabanı örneğini oluşturmak için NSFileManager kullanarak bir veritabanı yolu sağlayın. Bu yol genellikle NSDocumentDirectory içinde bulunur.
// shared/src/iosMain/kotlin/Database.ios.kt
fun getDatabaseBuilder(): RoomDatabase.Builder<AppDatabase> {
val dbFilePath = documentDirectory() + "/my_room.db"
return Room.databaseBuilder<AppDatabase>(
name = dbFilePath,
)
}
private fun documentDirectory(): String {
val documentDirectory = NSFileManager.defaultManager.URLForDirectory(
directory = NSDocumentDirectory,
inDomain = NSUserDomainMask,
appropriateForURL = null,
create = false,
error = null,
)
return requireNotNull(documentDirectory?.path)
}
JVM masaüstü
Veritabanı örneğini oluşturmak için Java veya Kotlin API'lerini kullanarak bir veritabanı yolu sağlayın.
// shared/src/jvmMain/kotlin/Database.desktop.kt
fun getDatabaseBuilder(): RoomDatabase.Builder<AppDatabase> {
val dbFile = File(System.getProperty("java.io.tmpdir"), "my_room.db")
return Room.databaseBuilder<AppDatabase>(
name = dbFile.absolutePath,
)
}
Veritabanını başlatma
Platforma özgü oluşturuculardan birinden RoomDatabase.Builder elde ettikten sonra, Oda veritabanının geri kalanını ortak kodda gerçek veritabanı örneği oluşturma işlemiyle birlikte yapılandırabilirsiniz.
// shared/src/commonMain/kotlin/Database.kt
fun getRoomDatabase(
builder: RoomDatabase.Builder<AppDatabase>
): AppDatabase {
return builder
.setDriver(BundledSQLiteDriver())
.setQueryCoroutineContext(Dispatchers.IO)
.build()
}
SQLite sürücüsü seçme
Önceki kod snippet'i, Room veritabanının hangi SQLite sürücüsünü kullanması gerektiğini tanımlamak için setDriver oluşturucu işlevini çağırır. Bu sürücüler hedef platforma göre farklılık gösterir. Önceki kod snippet'lerinde BundledSQLiteDriver kullanılıyordu.
Bu sürücü, kaynaktan derlenmiş SQLite'ı içerir ve tüm platformlarda en tutarlı ve güncel SQLite sürümünü sağlar. Bu nedenle, kullanılması önerilen sürücüdür.
İşletim sistemi tarafından sağlanan SQLite'ı kullanmak istiyorsanız platforma özgü bir sürücüyü belirten platforma özgü kaynak kümelerinde setDriver API'sini kullanın. Kullanılabilir sürücü uygulamalarının açıklamaları için Sürücü uygulamaları bölümüne bakın. Aşağıdakilerden birini kullanabilirsiniz:
androidMainalt bölgesindeAndroidSQLiteDriveriosMainalt bölgesindeNativeSQLiteDriver
NativeSQLiteDriver kullanmak için iOS uygulamasının sistem SQLite ile dinamik olarak bağlanması amacıyla bir bağlayıcı seçeneği -lsqlite3 sağlamanız gerekir.
// shared/build.gradle.kts
kotlin {
listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
).forEach { iosTarget ->
iosTarget.binaries.framework {
baseName = "TodoApp"
isStatic = true
// Required when using NativeSQLiteDriver
linkerOpts.add("-lsqlite3")
}
}
}
Coroutine bağlamı ayarlama
Android'deki bir RoomDatabase nesnesi, isteğe bağlı olarak RoomDatabase.Builder.setQueryExecutor kullanılarak paylaşılan uygulama yürütücüleriyle yapılandırılabilir. Bu sayede veritabanı işlemleri gerçekleştirilebilir.
Yürütücüler KMP ile uyumlu olmadığından Room'un setQueryExecutor API'si commonMain içinde kullanılamaz. Bunun yerine, RoomDatabase nesnesi CoroutineContext ile yapılandırılmalıdır. Bu nesneyi RoomDatabase.Builder.setCoroutineContext kullanarak ayarlayabilirsiniz. Bağlam ayarlamazsanız RoomDatabase nesnesi varsayılan olarak Dispatchers.IO olur.
Sadeleştirme ve karartma
Proje küçültülmüş veya karartılmışsa Room'un veritabanı tanımının oluşturulan uygulamasını bulabilmesi için aşağıdaki ProGuard kuralını eklemeniz gerekir:
-keep class * extends androidx.room3.RoomDatabase { <init>(); }
Kotlin Multiplatform'a taşıma
Room, başlangıçta bir Android kitaplığı olarak geliştirilmiş ve daha sonra API uyumluluğu odaklı bir şekilde KMP'ye taşınmıştır. Room'un KMP sürümü, platformlar arasında ve Android'e özel sürümden biraz farklıdır. Bu farklılıklar aşağıda listelenmiş ve açıklanmıştır.
Support SQLite'den SQLite sürücüsüne taşıma
androidx.sqlite.db içindeki SupportSQLiteDatabase ve diğer API'lerin tüm kullanımları, SQLite Driver API'leri ile yeniden düzenlenmelidir. Bunun nedeni, androidx.sqlite.db içindeki API'lerin yalnızca Android'e özel olmasıdır (KMP paketinden farklı bir paket olduğunu unutmayın).
Geriye dönük uyumluluk için ve RoomDatabase, SupportSQLiteOpenHelper.Factory ile yapılandırıldığı sürece (örneğin, SQLiteDriver ayarlanmamışsa) Room, hem Support SQLite hem de SQLite Driver API'lerinin beklendiği gibi çalıştığı "uyumluluk modunda" çalışır. Bu, artımlı taşımaları etkinleştirir. Böylece, tüm Support SQLite kullanımlarınızı tek bir değişiklikle SQLite sürücüsüne dönüştürmeniz gerekmez.
Room SQLite sarmalayıcısını kullanma
androidx.room3:room3-sqlite-wrapper yapısı, taşıma sırasında SQLiteDriver ile SupportSQLiteDatabase arasında köprü kurmak için API'ler sağlar.
SQLiteDriver ile yapılandırılmış bir RoomDatabase'den SupportSQLiteDatabase almak için yeni uzantı işlevi RoomDatabase.getSupportWrapper'yi kullanın. Bu uyumluluk sarmalayıcısı, SupportSQLiteDatabase'nın mevcut kullanımlarını korumaya yardımcı olur. SupportSQLiteDatabase'yı genellikle RoomDatabase.openHelper.writableDatabase'den elde edersiniz. Bu sarmalayıcı, özellikle BundledSQLiteDriver kullanmak isteyen ve kapsamlı SupportSQLite API kullanımlarına sahip kod tabanları için SQLiteDriver'nın benimsenmesini sağlar.
Taşıma alt sınıflarını dönüştürme
Taşıma alt sınıflarının SQLite sürücüsü karşılıklarına taşınması gerekir:
Kotlin Multiplatform
Taşıma alt sınıfları
object Migration_1_2 : Migration(1, 2) {
override fun migrate(connection: SQLiteConnection) {
// …
}
}
Otomatik taşıma spesifikasyonu alt sınıfları
class AutoMigrationSpec_1_2 : AutoMigrationSpec {
override fun onPostMigrate(connection: SQLiteConnection) {
// …
}
}
Yalnızca Android
Taşıma alt sınıfları
object Migration_1_2 : Migration(1, 2) {
override fun migrate(db: SupportSQLiteDatabase) {
// …
}
}
Otomatik taşıma spesifikasyonu alt sınıfları
class AutoMigrationSpec_1_2 : AutoMigrationSpec {
override fun onPostMigrate(db: SupportSQLiteDatabase) {
// …
}
}
Veritabanı geri çağırmasını dönüştürme
Veritabanı geri çağırmalarının SQLite sürücüsü karşılıklarına taşınması gerekir:
Kotlin Multiplatform
object MyRoomCallback : RoomDatabase.Callback() {
override fun onCreate(connection: SQLiteConnection) {
// …
}
override fun onDestructiveMigration(connection: SQLiteConnection) {
// …
}
override fun onOpen(connection: SQLiteConnection) {
// …
}
}
Yalnızca Android
object MyRoomCallback : RoomDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
// …
}
override fun onDestructiveMigration(db: SupportSQLiteDatabase) {
// …
}
override fun onOpen(db: SupportSQLiteDatabase) {
// …
}
}
@RawQuery DAO işlevlerini dönüştürme
Android dışı platformlar için derlenen @RawQuery ile açıklama eklenmiş işlevlerin, SupportSQLiteQuery yerine RoomRawQuery türünde bir parametre bildirmesi gerekir.
Kotlin Multiplatform
Ham sorguyu tanımlama
@Dao
interface TodoDao {
@RawQuery
suspend fun getTodos(query: RoomRawQuery): List<TodoEntity>
}
Daha sonra, çalışma zamanında sorgu oluşturmak için RoomRawQuery kullanılabilir:
suspend fun AppDatabase.getTodosWithLowercaseTitle(title: String): List<TodoEntity> {
val query = RoomRawQuery(
sql = "SELECT * FROM TodoEntity WHERE title = ?",
onBindStatement = {
it.bindText(1, title.lowercase())
}
)
return todoDao().getTodos(query)
}
Yalnızca Android
Ham sorguyu tanımlama
@Dao
interface TodoDao {
@RawQuery
suspend fun getTodos(query: SupportSQLiteQuery): List<TodoEntity>
}
Daha sonra, çalışma zamanında sorgu oluşturmak için SimpleSQLiteQuery kullanılabilir:
suspend fun AndroidOnlyDao.getTodosWithLowercaseTitle(title: String): List<TodoEntity> {
val query = SimpleSQLiteQuery(
query = "SELECT * FROM TodoEntity WHERE title = ?",
bindArgs = arrayOf(title.lowercase())
)
return getTodos(query)
}
Engelleme DAO işlevlerini dönüştürme
Room, Kotlin'in birden fazla platform için sunduğu özellik açısından zengin asenkron kotlinx.coroutines kitaplığından yararlanır. Optimum işlevsellik için, mevcut kod tabanıyla geriye dönük uyumluluğu korumak üzere androidMain içinde uygulanan DAO'lar hariç olmak üzere, KMP projesinde derlenen DAO'lar için suspend işlevleri zorunlu kılınır. Room for KMP kullanılırken Android dışı platformlar için derlenen tüm DAO işlevlerinin suspend işlevi olması gerekir.
Kotlin Multiplatform
Sorguları askıya alma
@Query("SELECT * FROM Todo")
suspend fun getAllTodos(): List<Todo>
İşlemleri askıya alma
@Transaction
suspend fun transaction() { … }
Yalnızca Android
Sorguları engelleme
@Query("SELECT * FROM Todo")
fun getAllTodos(): List<Todo>
İşlemleri engelleme
@Transaction
fun blockingTransaction() { … }
Reaktif türleri Flow'a dönüştürme
Tüm DAO işlevlerinin askıya alma işlevi olması gerekmez. LiveData veya RxJava'nın Flowable gibi reaktif türler döndüren DAO işlevleri, askıya alma işlevlerine dönüştürülmemelidir. Ancak LiveData gibi bazı türler KMP ile uyumlu değildir. Reaktif dönüş türlerine sahip DAO işlevleri, coroutine akışlarına taşınmalıdır.
Kotlin Multiplatform
Reactive türleri Flows
@Query("SELECT * FROM Todo")
fun getTodosFlow(): Flow<List<Todo>>
Yalnızca Android
LiveData veya RxJava'nın Flowable gibi reaktif türleri
@Query("SELECT * FROM Todo")
fun getTodosLiveData(): LiveData<List<Todo>>
Convert Transaction API'leri
Room KMP için veritabanı işlemi API'leri, yazma (useWriterConnection) ve okuma (useReaderConnection) işlemleri arasında ayrım yapabilir.
Kotlin Multiplatform
val database: RoomDatabase = …
database.useWriterConnection { transactor ->
transactor.immediateTransaction {
// perform database operations in transaction
}
}
Yalnızca Android
val database: RoomDatabase = …
database.withTransaction {
// perform database operations in transaction
}
Yazma işlemleri
Birden fazla sorgunun verileri atomik olarak yazmasını sağlamak için yazma işlemlerini kullanın. Böylece okuyucular verilere tutarlı bir şekilde erişebilir. Bu işlemi, üç işlem türünden herhangi biriyle useWriterConnection kullanarak yapabilirsiniz:
immediateTransaction: Önceden Yazma Günlüğü (WAL) modunda (varsayılan) bu tür işlemler başladığında kilitlenir ancak okuyucular okumaya devam edebilir. Çoğu durumda bu tercih edilen seçenektir.deferredTransaction: İşlem, ilk yazma ifadesine kadar kilitlenmez. İşlem içinde yazma işlemi gerekip gerekmeyeceğinden emin olmadığınız durumlarda bu tür işlemleri optimizasyon olarak kullanın. Örneğin, yalnızca şarkı listesinin adı verilmiş bir şarkı listesinden şarkı silme işlemi başlatırsanız ve şarkı listesi mevcut değilse yazma (silme) işlemi gerekmez.exclusiveTransaction: Bu mod, WAL modundaimmediateTransactionile aynı şekilde çalışır. Diğer günlük kaydı modlarında, işlem devam ederken diğer veritabanı bağlantılarının veritabanını okumasını engeller.
İşlemleri okuma
Veritabanından birden çok kez tutarlı bir şekilde okumak için okuma işlemlerini kullanın. Örneğin, iki veya daha fazla ayrı sorgunuz olduğunda ve JOIN tümcesini kullanmadığınızda. Okuyucu bağlantılarında yalnızca ertelenmiş işlemlere izin verilir. Okuyucu bağlantısında anında veya özel bir işlem başlatmaya çalışmak, bunlar 'yazma' işlemleri olarak kabul edildiğinden bir istisna oluşturur.
val database: RoomDatabase = …
database.useReaderConnection { transactor ->
transactor.deferredTransaction {
// perform database operations in transaction
}
}
Kotlin Multiplatform'da kullanılamaz
Android'de kullanılabilen bazı API'ler Kotlin Multiplatform'da kullanılamaz.
Sorgu geri araması
Sorgu geri çağırmalarını yapılandırmak için aşağıdaki API'ler common'da kullanılamaz ve bu nedenle Android dışındaki platformlarda da kullanılamaz.
RoomDatabase.Builder.setQueryCallbackRoomDatabase.QueryCallback
Room'un gelecekteki bir sürümünde sorgu geri çağırma desteği eklemeyi planlıyoruz.
Geri çağırma arayüzü RoomDatabase.QueryCallback ile birlikte sorgu geri çağırması RoomDatabase yapılandırmak için kullanılan API, ortak olarak kullanılamadığından Android dışındaki diğer platformlarda da kullanılamaz.RoomDatabase.Builder.setQueryCallback
Otomatik kapanan veritabanı
Zaman aşımından sonra otomatik kapatmayı etkinleştiren API (RoomDatabase.Builder.setAutoCloseTimeout) yalnızca Android'de kullanılabilir ve diğer platformlarda kullanılamaz.
Önceden paketlenmiş veritabanı
Mevcut bir veritabanını (ör. önceden paketlenmiş bir veritabanı) kullanarak RoomDatabase oluşturmak için aşağıdaki API'ler genel olarak kullanılamaz ve bu nedenle Android dışındaki diğer platformlarda da kullanılamaz. Bu API'ler şunlardır:
RoomDatabase.Builder.createFromAssetRoomDatabase.Builder.createFromFileRoomDatabase.Builder.createFromInputStreamRoomDatabase.PrepackagedDatabaseCallback
Room'un gelecekteki bir sürümünde önceden paketlenmiş veritabanları için destek eklemeyi planlıyoruz.
Aynı anda çalışan birden çok kopya için geçersiz kılma
Aynı anda çalışan birden çok kopyanın geçersiz kılınmasını etkinleştirmek için kullanılan API,
RoomDatabase.Builder.enableMultiInstanceInvalidation yalnızca Android'de kullanılabilir ve yaygın veya diğer platformlarda kullanılamaz.
Sizin için önerilenler
- Not: JavaScript kapalıyken bağlantı metni gösterilir.
- Mevcut uygulamaları Room KMP'ye taşıma Codelab'i
- KMP Codelab'i Kullanmaya Başlama
- Verileri Room ile yerel veritabanına kaydetme