SQLite را برای KMP تنظیم کنید

کتابخانه androidx.sqlite شامل رابط‌های انتزاعی به همراه پیاده‌سازی‌های اولیه است که می‌توانند برای ساخت کتابخانه‌های شخصی شما که به SQLite دسترسی دارند، استفاده شوند. شاید بخواهید از کتابخانه Room استفاده کنید که یک لایه انتزاعی روی SQLite فراهم می‌کند تا دسترسی به پایگاه داده قوی‌تری را فراهم کند و در عین حال از تمام قدرت SQLite بهره ببرد.

وابستگی‌ها را تنظیم کنید

برای راه‌اندازی SQLite در پروژه KMP خود، وابستگی‌های مربوط به مصنوعات را در فایل build.gradle.kts مربوط به ماژول خود اضافه کنید:

[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" }

رابط‌های برنامه‌نویسی درایور SQLite

گروه‌های کتابخانه androidx.sqlite APIهای سطح پایینی را برای ارتباط با کتابخانه SQLite ارائه می‌دهند، چه در کتابخانه هنگام استفاده از androidx.sqlite:sqlite-bundled و چه در پلتفرم میزبان، مانند اندروید یا iOS هنگام استفاده از androidx.sqlite:sqlite-framework . این 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()
}

مشابه API های SQLite C، کاربرد رایج آنها به شرح زیر است:

  • با استفاده از پیاده‌سازی نمونه‌سازی‌شده‌ی SQLiteDriver یک اتصال به پایگاه داده باز کنید.
  • با استفاده از SQLiteConnection.prepare() یک دستور SQL آماده کنید.
  • یک SQLiteStatement را به روش زیر اجرا کنید:
    1. به صورت اختیاری، آرگومان‌ها را با استفاده از توابع bind*() مقید کنید.
    2. با استفاده از تابع step() روی مجموعه نتایج پیمایش (iteration) کنید.
    3. با استفاده از توابع get*() ‎، ستون‌ها را از مجموعه نتایج بخوانید.

پیاده‌سازی درایور

جدول زیر خلاصه‌ای از پیاده‌سازی‌های درایور موجود را نشان می‌دهد:

نام کلاس

مصنوع

پلتفرم‌های پشتیبانی‌شده

AndroidSQLiteDriver androidx.sqlite:sqlite-framework

اندروید

NativeSQLiteDriver androidx.sqlite:sqlite-framework

آی‌او‌اس، مک و لینوکس

BundledSQLiteDriver androidx.sqlite:sqlite-bundled

اندروید، iOS، مک، لینوکس و JVM (دسکتاپ)

پیاده‌سازی پیشنهادی برای استفاده، BundledSQLiteDriver است که در androidx.sqlite:sqlite-bundled موجود است. این شامل کتابخانه SQLite کامپایل شده از منبع است و به‌روزترین نسخه و سازگاری را در تمام پلتفرم‌های KMP پشتیبانی شده ارائه می‌دهد.

درایور و اتاق SQLite

رابط‌های برنامه‌نویسی کاربردی (API) درایور برای تعاملات سطح پایین با پایگاه داده SQLite مفید هستند. برای یک کتابخانه غنی از ویژگی‌ها که دسترسی قوی‌تری به SQLite فراهم می‌کند، Room توصیه می‌شود.

یک RoomDatabase برای انجام عملیات پایگاه داده به SQLiteDriver متکی است و پیاده‌سازی آن باید با استفاده از RoomDatabase.Builder.setDriver() پیکربندی شود. Room برای دسترسی مستقیم‌تر به اتصالات پایگاه داده مدیریت‌شده RoomDatabase.useReaderConnection و RoomDatabase.useWriterConnection را ارائه می‌دهد.

مهاجرت به کاتلین چند پلتفرمی

هرگونه استفاده از اجزای API سطح پایین Support SQLite (مانند رابط SupportSQLiteDatabase ) باید به اجزای معادل SQLite Driver منتقل شود.

کاتلین چندسکویی

انجام تراکنش با استفاده از 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
  }
}

فقط اندروید

انجام تراکنش با استفاده از 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
  }
}