移动开发中的SQLite:它是什么以及如何工作

作者: IT Sectr 发布日期: 2026-03-11 阅读时间: 10 分钟

SQLite 是一种嵌入式关系数据库,无需单独的服务器进程即可运行,并将整个数据库存储在设备上的单个文件中。凭借零配置、小巧的库体积和完整的 SQL 支持,SQLite 已成为移动应用中本地数据存储的标准。根据 SQLite Consortium (2025) 的数据,该 DBMS 用于超过 40 亿台设备,包括每部 iOS 和 Android 智能手机。

要点

  • SQLite — 嵌入式关系型 DBMS,零配置,数据存储在单个文件中。
  • ACID 事务 — 即使在电源故障或应用崩溃时也能保证数据完整性。
  • 数据类型 — 动态:SQLite 在创建表时不需要严格指定列类型。
  • Room — Android 的 ORM 库,通过 DAO 和注解简化 SQLite 操作。
  • CoreData 可以在 iOS 上使用 SQLite 作为持久化存储,但增加了对象管理层。

什么是 SQLite?

SQLite 是一个用 C 语言编写的库,实现了无专用服务器的关系型 DBMS。它直接嵌入到应用程序中,读取和写入设备文件系统上的普通文件。库的大小约为 600 KB,使 SQLite 成为最轻量级的全功能 SQL 数据库。

SQLite 支持 SQL:1999 标准的大部分功能,包括 JOIN、子查询、触发器、视图、索引和窗口函数。限制涉及 ALTER TABLE(有限支持)和完整的 RIGHT/FULL OUTER JOIN。不过对于移动应用来说,SQLite 的功能在 99% 的本地存储场景中已经足够。

根据 Stack Overflow (2025) 的开发者调查,SQLite 是嵌入式解决方案中最流行的数据库,在所有 DBMS 中排名第三,仅次于 MySQL 和 PostgreSQL。在移动开发中,每个应用都直接或通过封装库使用 SQLite。

SQLite 的关键特性

零配置 — SQLite 无需安装、权限配置、创建用户或启动服务。库连接到项目后只需调用一个函数即可创建数据库。与需要安装服务器、配置端口和设置用户的客户端-服务器 DBMS 相比,这极大地简化了部署。

SQLite 数据库文件是一个普通的跨平台文件,可以复制、分析、通过网络发送或从备份中恢复。文件格式在 API 级别上是稳定的:2004 年创建的 SQLite 3 文件可以用当前版本的库打开,确保了数据的长期兼容性。

SQLite 的架构和存储方式

SQLite 的架构由八个虚拟机构成:Tokenizer、Parser、Code Generator、VM、B-Tree、Pager、OS Interface 和 Utilities。SQL 查询经过 Tokenizer(词法分析)、Parser(构建 AST)、Code Generator(转换为字节码),然后在虚拟机上执行,通过 B-Tree 和 Pager 读取数据页。

SQLite 使用 B-Tree 存储表和索引。每个表存储为一个单独的 B-Tree,叶节点包含数据行。索引也存储为 B-Tree,但叶节点中为键值。Pager 管理从文件到内存的页面加载(默认 4096 字节),通过日志或 WAL 确保 ACID 事务。

日志模式

WAL(预写日志) — 推荐用于移动应用的模式。更改首先写入单独的 WAL 文件,然后定期迁移到主数据库。WAL 允许同时从数据库读取(旧数据)和写入(通过 WAL),从而提高了多线程应用的性能。标准日志(回滚日志)在写入时阻止读取。

参数Rollback JournalWAL(预写日志)
读取时写入被阻止允许(读取旧数据)
写入性能中等高(WAL 顺序写入)
磁盘消耗较少(仅回滚日志)较多(WAL + 主数据库)
故障恢复回滚到最近检查点从 WAL 恢复(数据不丢失)
推荐适用于单线程场景适用于典型移动应用

模式切换通过一个 SQL 查询完成:PRAGMA journal_mode=WAL。对于具有后台同步和同时读取数据的 UI 线程的移动应用,WAL 提供了更好的性能且不会阻塞界面。

SQLite 对比移动开发中的其他数据库

SQLite 不是本地数据存储的唯一选择,但却是最通用的。Realm 提供更快的直接内存对象访问速度,但使用专有的 NoSQL 格式且库体积更大。iOS 上的 Core Data 是构建在 SQLite 之上的 ORM 层,增加了对象图管理和操作撤销功能。

对于大多数应用,SQLite 由于其可预测的性能、零供应商锁定和久经考验的稳定性仍然是最优选择。Realm 和 Core Data 适用于具有复杂对象图、响应式查询或需要设备间同步的项目。

特性SQLiteRealmCore Data
数据库类型关系型 (SQL)NoSQL(对象型)ORM(基于 SQLite)
库大小~600 KB~4 MB内置于 Apple SDK
性能中等高(内存对象)中等(ORM 开销)
平台iOS、Android、Web、DesktopiOS、Android、Node.jsiOS、macOS
供应商锁定无(开放标准)中等(专有格式)高(仅 Apple)

选择 SQLite、Realm 或 Core Data 取决于平台、对象模型要求和同步策略。对于跨平台项目(KMP、Flutter),SQLite 仍然是唯一通用的选择,可在所有目标平台上无需更改数据模型即可运行。

Android 上的 SQLite:Room 和 SQLiteOpenHelper

Room 是 Android Jetpack 中的库,提供基于 SQLite 的 ORM 层。Room 从带注解的 DAO 接口自动生成 SQL 查询,在编译时检查查询的正确性,并在模式更改时支持数据库迁移。Room 是 Android 上使用 SQLite 的推荐方式。

SQLiteOpenHelper 是用于直接管理 SQLite 的低级 API,无需 ORM。该类管理数据库的创建、打开和更新。SQLiteOpenHelper 适用于简单 SQL 查询的项目,或需要完全控制 SQL 逻辑而不需要 Room 抽象的项目。

Room 的实体和 DAO 示例

Room 中的实体使用 @Entity 注解,DAO 使用 @Dao 注解。Room 将注解方法转换为 SQL 查询:@Insert 生成 INSERT,@Query 生成带有指定 SQL 的 SELECT。迁移通过 Migration 类添加,指定旧版本和新版本模式。Room 在编译时检查 SQL,从而避免生产环境中的语法错误。

kotlin
@Entity
data class User(
    @PrimaryKey val id: Long,
    val name: String,
    @ColumnInfo(name = "created_at")
    val createdAt: Long
)

@Dao
interface UserDao {
    @Query("SELECT * FROM user ORDER BY name ASC")
    suspend fun getAllUsers(): List<User>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertUser(user: User)

    @Query("DELETE FROM user WHERE id = :id")
    suspend fun deleteUser(id: Long)
}

Room 自动生成 UserDao_Impl 实现,其中包含通过内部 RoomDatabase 对 SQLite 的运行时查询。由于协程 (suspend) 的支持,DAO 方法在后台线程上异步执行,不会阻塞 UI。@Query 中的 Flow 返回类型在表更改时自动更新结果。

iOS 上的 SQLite:FMDB 和 GRDB

FMDB 是 SQLite C API 的 Objective-C 封装,是历史上第一个流行的 iOS 库。提供 FMDatabase 和 FMResultSet 对象来执行查询和获取结果。FMDB 简单而简约,但不支持 Swift 特定构造,如可选值、Codable、async/await。

GRDB 是现代 Swift 库,用于 SQLite 操作。提供 type-safe API、Codable 支持、Combine Publishers、async/await、迁移和实时变更观察。由于与 Swift Concurrency 的完全集成和更好的代码可读性,GRDB 是新 Swift 项目的首选。

Swift 上的 GRDB 示例

GRDB 通过符合 FetchableRecordTableRecord 协议的 Record 类定义表。查询使用 type-safe 语法在 Swift 中编写,而不是原始 SQL。GRDB 还支持用于模式版本控制和应用版本之间迁移的 DatabaseMigrator

swift
struct User: Codable, FetchableRecord, TableRecord {
    var id: Int64
    var name: String
    var createdAt: Date
}

let dbPool = try DatabasePool(path: dbPath)
var migrator = DatabaseMigrator()
migrator.registerMigration("v1") { db in
    try db.create(table: "user") { t in
        t.autoIncrementedPrimaryKey("id")
        t.column("name", .text).notNull()
        t.column("createdAt", .datetime).notNull()
    }
}

let users = try await dbPool.read { db in
    try User.order(Column("name")).fetchAll(db)
}

DatabasePool 使用 SQLite 的 WAL 模式实现并发读取。多个读取器可以同时访问数据库,而一个写入器通过 WAL 更新数据。GRDB 自动管理连接和事务,确保从任何线程对数据库的线程安全访问,无需手动同步。

SQLite 性能优化

索引是加速 SQLite 查询的最有效方式。索引创建在 WHERE、JOIN 和 ORDER BY 中涉及的列上。对于有 100,000 条记录的表,通过索引列搜索只需毫秒而不是秒。但是索引会降低 INSERT 和 UPDATE 的速度,因此索引数量应与写入频率保持平衡。

批量插入在单个事务中大幅加速数据批量加载。逐条插入 1000 条记录的开销约为 1 秒。而同样的 1000 条记录在单个事务中只需约 5-10 毫秒。差异在于每条单独的 INSERT 都会创建一个新事务并同步写入磁盘。

性能 PRAGMA

PRAGMA 是用于配置库行为的 SQLite 命令。关键优化 PRAGMA 包括:PRAGMA synchronous=NORMAL(降低 fsync 频率)、PRAGMA cache_size=-8000(分配 8 MB 缓存)、PRAGMA temp_store=MEMORY(内存中的临时表)。对于大数据量的移动应用,这些 PRAGMA 的组合可将查询速度提升 2-3 倍。

另一个重要优化是 SQL 查询的预编译(预编译语句)。如果查询多次执行(例如插入 10000 行),则编译一次 SQL 然后重复使用语句可将 CPU 负载降低 30-50%。Room 和 GRDB 自动缓存预编译语句,但在直接使用 SQLite C API 时需要手动执行编译。

kotlin
class UserRepository(private val db: RoomDatabase) {

    suspend fun insertBatch(users: List<User>) {
        db.withTransaction {
            users.chunked(500).forEach { batch ->
                batch.forEach { user ->
                    insertUser(user)
                }
            }
        }
    }
}

使用 withTransaction 进行批量插入确保所有 INSERT 在单个事务中执行。拆分为子批次 (chunked) 可防止单个事务过大,以免长时间阻塞其他线程。对于后台同步,500 条记录的子批次大小在速度和 UI 响应性之间提供了最佳平衡。

常见问题

可以在多个线程上使用 SQLite 吗?

是的,SQLite 在 WAL 模式下支持多线程访问。多个线程可以同时读取数据,但只有一个可以写入。Room 和 GRDB 自动管理同步。在回滚日志模式(默认)下,数据库在任何写入时都会完全锁定。

移动设备上 SQLite 数据库的最大大小是多少?

限制为 281 TB(理论最大值)。实际上,数据库大小受设备可用内存限制。对于移动应用,舒适大小为 1-2 GB。超过 2 GB 的数据库会减慢备份、App Store 更新并增加 RAM 消耗。

SQLite 中的数据安全吗?

SQLite 默认不加密数据,任何有权访问文件的进程都可以读取。对于加密,请使用 SQLCipher(带 AES-256 的扩展)、带 EncryptedDatabase 的 Room(Android)或 iOS 上的 Encrypted Core Data。加密会增加 5-15% 的读写开销。

SQLite 和 MySQL 有什么区别?

SQLite 是嵌入式库,不需要服务器进程。MySQL 是客户端-服务器 DBMS,具有单独的服务器、用户、访问权限和网络协议。SQLite 将数据库存储在单个文件中,MySQL 存储在由服务器管理的多个文件中。SQLite 更简单更轻量,MySQL 更强大且更具可扩展性。

如何在不丢失数据的情况下更新 SQLite 模式?

对于迁移,使用 ALTER TABLE(添加列)或创建新表并迁移数据然后删除旧表。Room 通过 Migration 类自动处理此过程:指定 startVersion、endVersion 和用于更改模式的 SQL 查询。GRDB 和 FMDB 提供类似的 DatabaseMigrator。

总结

  • SQLite — 零配置的嵌入式关系型 DBMS,用于每个 iOS 和 Android 移动应用中的本地数据存储。
  • ACID 事务和 WAL 模式确保数据完整性和来自多个应用线程的并发访问。
  • Room(Android)和 GRDB(iOS)是 SQLite 的现代封装,通过 type-safe API 和自动迁移简化了数据库操作。
  • B-Tree 架构提供高效的索引搜索,批量事务和预编译语句提供高写入性能。
  • SQLite 在通用性(所有平台)、库大小和无供应商锁定方面优于 Realm 和 Core Data。
  • 通过索引、WAL 模式和 PRAGMA 设置的优化可在典型移动负载下将查询速度提升 2-3 倍。
  • 建议 — 通过 Android 上的 Room 和 iOS 上的 GRDB,将 SQLite 作为移动应用本地数据的主要存储。

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读