SQLite 是一种嵌入式关系数据库,无需单独的服务器进程即可运行,并将整个数据库存储在设备上的单个文件中。凭借零配置、小巧的库体积和完整的 SQL 支持,SQLite 已成为移动应用中本地数据存储的标准。根据 SQLite Consortium (2025) 的数据,该 DBMS 用于超过 40 亿台设备,包括每部 iOS 和 Android 智能手机。
要点
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 无需安装、权限配置、创建用户或启动服务。库连接到项目后只需调用一个函数即可创建数据库。与需要安装服务器、配置端口和设置用户的客户端-服务器 DBMS 相比,这极大地简化了部署。
SQLite 数据库文件是一个普通的跨平台文件,可以复制、分析、通过网络发送或从备份中恢复。文件格式在 API 级别上是稳定的:2004 年创建的 SQLite 3 文件可以用当前版本的库打开,确保了数据的长期兼容性。
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 Journal | WAL(预写日志) |
|---|---|---|
| 读取时写入 | 被阻止 | 允许(读取旧数据) |
| 写入性能 | 中等 | 高(WAL 顺序写入) |
| 磁盘消耗 | 较少(仅回滚日志) | 较多(WAL + 主数据库) |
| 故障恢复 | 回滚到最近检查点 | 从 WAL 恢复(数据不丢失) |
| 推荐 | 适用于单线程场景 | 适用于典型移动应用 |
模式切换通过一个 SQL 查询完成:PRAGMA journal_mode=WAL。对于具有后台同步和同时读取数据的 UI 线程的移动应用,WAL 提供了更好的性能且不会阻塞界面。
SQLite 不是本地数据存储的唯一选择,但却是最通用的。Realm 提供更快的直接内存对象访问速度,但使用专有的 NoSQL 格式且库体积更大。iOS 上的 Core Data 是构建在 SQLite 之上的 ORM 层,增加了对象图管理和操作撤销功能。
对于大多数应用,SQLite 由于其可预测的性能、零供应商锁定和久经考验的稳定性仍然是最优选择。Realm 和 Core Data 适用于具有复杂对象图、响应式查询或需要设备间同步的项目。
| 特性 | SQLite | Realm | Core Data |
|---|---|---|---|
| 数据库类型 | 关系型 (SQL) | NoSQL(对象型) | ORM(基于 SQLite) |
| 库大小 | ~600 KB | ~4 MB | 内置于 Apple SDK |
| 性能 | 中等 | 高(内存对象) | 中等(ORM 开销) |
| 平台 | iOS、Android、Web、Desktop | iOS、Android、Node.js | iOS、macOS |
| 供应商锁定 | 无(开放标准) | 中等(专有格式) | 高(仅 Apple) |
选择 SQLite、Realm 或 Core Data 取决于平台、对象模型要求和同步策略。对于跨平台项目(KMP、Flutter),SQLite 仍然是唯一通用的选择,可在所有目标平台上无需更改数据模型即可运行。
Room 是 Android Jetpack 中的库,提供基于 SQLite 的 ORM 层。Room 从带注解的 DAO 接口自动生成 SQL 查询,在编译时检查查询的正确性,并在模式更改时支持数据库迁移。Room 是 Android 上使用 SQLite 的推荐方式。
SQLiteOpenHelper 是用于直接管理 SQLite 的低级 API,无需 ORM。该类管理数据库的创建、打开和更新。SQLiteOpenHelper 适用于简单 SQL 查询的项目,或需要完全控制 SQL 逻辑而不需要 Room 抽象的项目。
Room 中的实体使用 @Entity 注解,DAO 使用 @Dao 注解。Room 将注解方法转换为 SQL 查询:@Insert 生成 INSERT,@Query 生成带有指定 SQL 的 SELECT。迁移通过 Migration 类添加,指定旧版本和新版本模式。Room 在编译时检查 SQL,从而避免生产环境中的语法错误。
@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 返回类型在表更改时自动更新结果。
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 项目的首选。
GRDB 通过符合 FetchableRecord 和 TableRecord 协议的 Record 类定义表。查询使用 type-safe 语法在 Swift 中编写,而不是原始 SQL。GRDB 还支持用于模式版本控制和应用版本之间迁移的 DatabaseMigrator。
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 查询的最有效方式。索引创建在 WHERE、JOIN 和 ORDER BY 中涉及的列上。对于有 100,000 条记录的表,通过索引列搜索只需毫秒而不是秒。但是索引会降低 INSERT 和 UPDATE 的速度,因此索引数量应与写入频率保持平衡。
批量插入在单个事务中大幅加速数据批量加载。逐条插入 1000 条记录的开销约为 1 秒。而同样的 1000 条记录在单个事务中只需约 5-10 毫秒。差异在于每条单独的 INSERT 都会创建一个新事务并同步写入磁盘。
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 时需要手动执行编译。
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 在 WAL 模式下支持多线程访问。多个线程可以同时读取数据,但只有一个可以写入。Room 和 GRDB 自动管理同步。在回滚日志模式(默认)下,数据库在任何写入时都会完全锁定。
限制为 281 TB(理论最大值)。实际上,数据库大小受设备可用内存限制。对于移动应用,舒适大小为 1-2 GB。超过 2 GB 的数据库会减慢备份、App Store 更新并增加 RAM 消耗。
SQLite 默认不加密数据,任何有权访问文件的进程都可以读取。对于加密,请使用 SQLCipher(带 AES-256 的扩展)、带 EncryptedDatabase 的 Room(Android)或 iOS 上的 Encrypted Core Data。加密会增加 5-15% 的读写开销。
SQLite 是嵌入式库,不需要服务器进程。MySQL 是客户端-服务器 DBMS,具有单独的服务器、用户、访问权限和网络协议。SQLite 将数据库存储在单个文件中,MySQL 存储在由服务器管理的多个文件中。SQLite 更简单更轻量,MySQL 更强大且更具可扩展性。
对于迁移,使用 ALTER TABLE(添加列)或创建新表并迁移数据然后删除旧表。Room 通过 Migration 类自动处理此过程:指定 startVersion、endVersion 和用于更改模式的 SQL 查询。GRDB 和 FMDB 提供类似的 DatabaseMigrator。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。