KMP के लिए SQLite सेट अप करना

androidx.sqlite लाइब्रेरी में ऐब्स्ट्रैक्ट इंटरफ़ेस के साथ-साथ बुनियादी तौर पर लागू करने की सुविधा भी होती है. इसका इस्तेमाल, SQLite को ऐक्सेस करने वाली अपनी लाइब्रेरी बनाने के लिए किया जा सकता है. आपको Room लाइब्रेरी का इस्तेमाल करना चाहिए. यह SQLite को लेकर एक ऐब्स्ट्रैक्शन लेयर उपलब्ध कराती है, ताकि डेटाबेस को ज़्यादा अच्छे से ऐक्सेस किया जा सके.

डिपेंडेंसी सेट अप करना

अपने 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 Driver API

androidx.sqlite लाइब्रेरी ग्रुप, SQLite लाइब्रेरी से कम्यूनिकेट करने के लिए लो-लेवल एपीआई उपलब्ध कराते हैं. androidx.sqlite:sqlite-bundled का इस्तेमाल करते समय, लाइब्रेरी में शामिल SQLite लाइब्रेरी या androidx.sqlite:sqlite-framework का इस्तेमाल करते समय, Android या iOS जैसे होस्ट प्लैटफ़ॉर्म में शामिल SQLite लाइब्रेरी से कम्यूनिकेट करने के लिए लो-लेवल एपीआई उपलब्ध कराते हैं. ये एपीआई, SQLite C API की मुख्य सुविधाओं के हिसाब से काम करते हैं.

इसके तीन मुख्य इंटरफ़ेस हैं:

  • SQLiteDriver: यह SQLite का एंट्री पॉइंट है. इसका इस्तेमाल डेटाबेस कनेक्शन खोलने के लिए किया जाता है.
  • SQLiteConnection: यह sqlite3 ऑब्जेक्ट के बारे में बताता है.
  • SQLiteStatement: यह sqlite3_stmt ऑब्जेक्ट के बारे में बताता है.

यहां दिए गए उदाहरण में, मुख्य एपीआई दिखाए गए हैं:

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 का इस्तेमाल करके, एसक्यूएल स्टेटमेंट तैयार करें.
  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)

इस्तेमाल करने के लिए, BundledSQLiteDriver को लागू करने का सुझाव दिया जाता है. यह androidx.sqlite:sqlite-bundled में उपलब्ध है. इसमें सोर्स से कंपाइल की गई SQLite लाइब्रेरी शामिल है. इससे, KMP के साथ काम करने वाले सभी प्लैटफ़ॉर्म पर, सबसे नया वर्शन और एक जैसा अनुभव मिलता है.

SQLite ड्राइवर और Room

ड्राइवर एपीआई, SQLite डेटाबेस के साथ लो-लेवल इंटरैक्शन के लिए काम के होते हैं. अगर आपको ऐसी लाइब्रेरी चाहिए जिसमें कई सुविधाएं हों और जो SQLite को ज़्यादा अच्छे से ऐक्सेस कर सके, तो हम Room का इस्तेमाल करने का सुझाव देते हैं.

डेटाबेस से जुड़ी कार्रवाइयां करने के लिए, RoomDatabase को SQLiteDriver पर निर्भर रहना पड़ता है. साथ ही, आपको RoomDatabase.Builder.setDriver का इस्तेमाल करके, इसे लागू करने की सुविधा कॉन्फ़िगर करनी होगी. रूम, मैनेज किए गए डेटाबेस कनेक्शन को सीधे तौर पर ऐक्सेस करने के लिए RoomDatabase.useReaderConnection और RoomDatabase.useWriterConnection उपलब्ध कराता है.

Kotlin Multiplatform पर माइग्रेट करना

आपको Support SQLite API के लो-लेवल कॉम्पोनेंट के इस्तेमाल को, SQLite Driver के बराबर के कॉम्पोनेंट पर माइग्रेट करना होगा. जैसे, SupportSQLiteDatabase इंटरफ़ेस.

Kotlin Multiplatform

कम लेवल वाले 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
  }
}