Настройка SQLite базы данных в мобильном приложении

TRUETECH занимается разработкой, поддержкой и обслуживанием мобильных приложений iOS, Android, PWA. Имеем большой опыт и экспертизу для публикации мобильных приложений в популярные маркеты Google Play, App Store, Amazon, AppGallery и другие.

Разработка и поддержка любых видов мобильных приложений:

Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

Это лишь некоторые из типы мобильных приложений, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента.

Услуги, которые мы предлагаем
Показано 1 из 1Все 1735 услуг
Настройка SQLite базы данных в мобильном приложении
Средний
от 1 дня до 3 дней
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    792
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    671
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1097
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    969
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    914
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    495

Настройка SQLite базы данных в мобильном приложении

SQLite встроен в iOS и Android на уровне ОС. Вопрос не в том, подключить ли его — он уже есть. Вопрос в том, как с ним работать так, чтобы через полгода не переписывать всё с нуля из-за запутанных raw-запросов или падений с SQLiteDatabaseLockedException на Android.

Выбор ORM/абстракции

Работать с SQLite напрямую через android.database.sqlite.SQLiteDatabase или sqlite3 на iOS — вариант для минимальных сценариев. В реальных проектах используют ORM:

Платформа Библиотека Подход
Android Room (Jetpack) аннотации + DAO
iOS GRDB.swift typesafe запросы на Swift
Flutter sqflite + drift codegen + reactive
React Native react-native-sqlite-storage / op-sqlite raw SQL или TypeORM
Multiplatform SQLDelight shared SQL схема для iOS+Android

Room — стандарт для Android, за него голосует Google. GRDB.swift на iOS даёт типобезопасные запросы без лишней магии. SQLDelight интересен для KMM-проектов: один .sq файл с SQL, генерирует Kotlin и Swift код.

Room на Android: правильная архитектура

@Entity(tableName = "products",
    indices = [Index(value = ["category_id"]), Index(value = ["sku"], unique = true)]
)
data class ProductEntity(
    @PrimaryKey val id: String,
    @ColumnInfo(name = "category_id") val categoryId: String,
    val sku: String,
    val title: String,
    @ColumnInfo(name = "price_cents") val priceCents: Int,
    @ColumnInfo(name = "updated_at") val updatedAt: Long,
    @ColumnInfo(name = "is_deleted") val isDeleted: Boolean = false
)

@Dao
interface ProductDao {
    @Query("SELECT * FROM products WHERE category_id = :categoryId AND is_deleted = 0 ORDER BY title ASC")
    fun observeByCategory(categoryId: String): Flow<List<ProductEntity>>

    @Upsert
    suspend fun upsert(products: List<ProductEntity>)

    @Query("UPDATE products SET is_deleted = 1, updated_at = :timestamp WHERE id = :id")
    suspend fun softDelete(id: String, timestamp: Long)
}

@Upsert появился в Room 2.5 — до этого нужно было @Insert(onConflict = OnConflictStrategy.REPLACE). Soft delete через флаг is_deleted — стандартная практика для синхронизируемых баз, чтобы не потерять запись до подтверждения удаления с сервера.

Миграции — самое болезненное место

Room проверяет exportedSchema при изменении схемы. Если fallbackToDestructiveMigration() — база пересоздаётся при каждом изменении схемы. Это нормально для debug, недопустимо для production.

val db = Room.databaseBuilder(context, AppDatabase::class.java, "app.db")
    .addMigrations(MIGRATION_1_2, MIGRATION_2_3)
    .build()

val MIGRATION_2_3 = object : Migration(2, 3) {
    override fun migrate(db: SupportSQLiteDatabase) {
        db.execSQL("ALTER TABLE products ADD COLUMN tags TEXT NOT NULL DEFAULT ''")
        db.execSQL("CREATE INDEX IF NOT EXISTS index_products_updated_at ON products(updated_at)")
    }
}

Экспортируйте схему в JSON (room.schemaLocation в build.gradle) и храните в git. При code review сразу видно, что изменилось в схеме. Room может автоматически сгенерировать миграцию через AutoMigration для простых случаев (добавление колонки), но переименование таблиц и колонок требует @RenameTable/@RenameColumn аннотаций.

GRDB.swift на iOS

// Открытие и настройка
let dbQueue = try DatabaseQueue(path: dbPath)

try dbQueue.write { db in
    try db.create(table: "products", ifNotExists: true) { t in
        t.primaryKey("id", .text)
        t.column("category_id", .text).notNull().indexed()
        t.column("sku", .text).unique()
        t.column("title", .text).notNull()
        t.column("price_cents", .integer).notNull()
        t.column("updated_at", .integer).notNull()
    }
}

// Реактивное наблюдение через ValueObservation
let observation = ValueObservation.tracking { db in
    try Product.filter(Column("categoryId") == categoryId).fetchAll(db)
}
let cancellable = observation.start(in: dbQueue,
    onError: { error in print(error) },
    onChange: { products in self.updateUI(products) }
)

ValueObservation — аналог Room's Flow: автоматически перезапускает запрос при изменении затронутых таблиц.

WAL-режим и производительность

По умолчанию SQLite работает в journal mode. Для мобильных приложений WAL (Write-Ahead Logging) лучше: читатели не блокируют писателей. Room включает WAL автоматически. В GRDB: dbQueue.configuration.journalMode = .wal.

Типичная проблема — N+1 запрос в RecyclerView. SELECT * FROM orders возвращает 200 строк, потом для каждой SELECT * FROM order_items WHERE order_id = ?. 200 запросов в UI thread — ANR через 5 секунд на реальном устройстве. Решение: JOIN или отдельный batch-запрос WHERE order_id IN (...).

Настройка SQLite с Room или GRDB, миграционная стратегия, индексы: 1 неделя на одну платформу. Стоимость рассчитывается индивидуально.