前言
我们在本项目中一直强调“逻辑共享”。那么,作为应用数据的核心——SQL 定义,能不能也共享?
答案是:SQLDelight。
SQLDelight 不是传统的 ORM,它能根据你的 SQL 语句生成对应的类型安全 Kotlin 代码。最黑科技的是,这套 SQL 可以在 Android、iOS 甚至 Ktor Server 后端完全复用。
一、 为什么在后端也用 SQLDelight?
虽然 Exposed 在后端很强大,但在 KMP 全栈项目中,SQLDelight 有其不可替代的优势:
- 契约优先:SQL 语句就是前后端的共同契约。
- 绝对的模型同步:同一个
.sq文件,生成的 Data Class 在 App 和 Server 端一模一样。 - 响应式支持:自带的
asFlow().mapToList()能让你轻松实现从数据库到 UI 的全链路响应式刷新。
二、 实战:跨模块的 SQL 定义
在项目的 shared 或 core 模块中创建 .sq 文件:
-- src/commonMain/sqldelight/com/yangcyzhang/database/User.sq
CREATE TABLE UserInfo (
id INTEGER NOT NULL PRIMARY KEY,
name TEXT NOT NULL,
email TEXT NOT NULL
);
selectAll:
SELECT * FROM UserInfo;
insertUser:
INSERT INTO UserInfo(id, name, email)
VALUES (?, ?, ?);
三、 在 Ktor 后端接入
后端需要配置适配 JDBC 的驱动:
val driver = JdbcSqliteDriver(JdbcSqliteDriver.IN_MEMORY)
val database = MyDatabase(driver)
// 初始化表结构
MyDatabase.Schema.create(driver)
// 业务调用
post("/user") {
val user = call.receive<User>()
database.userQueries.insertUser(user.id, user.name, user.email)
call.respond(HttpStatusCode.Created)
}
四、 “离线优先”全栈同步原型
利用 SQLDelight,你可以实现一套极其丝滑的同步逻辑:
- App 侧:用户操作 -> 写入本地 SQLDelight -> 标记为 "pending"。
- 网络侧:后台协程将 "pending" 的 SQLDelight 数据发给后端。
- 后端侧:接收请求 -> 写入后端同样的 SQLDelight 表结构。
- 一致性:由于两端代码都是根据同一个
.sq生成的,逻辑冲突的可能性被降到了最低。
五、架构建议
- 驱动抽象:在
commonMain定义一个DatabaseDriverFactory。在 Android 传AndroidSqliteDriver,在 iOS 传NativeSqliteDriver,在 Server 传JdbcSqliteDriver。 - 性能权衡:对于极大规模的后端数据(千万级以上),Exposed 配合传统数据库(PostgreSQL/MySQL)依然是首选;但对于中小型闭环 App 或边缘计算场景,SQLDelight 能极大地提升开发效率。
结语
SQLDelight 是 KMP 全栈开发的最后一块拼图。它让数据层也实现了“一处编写,全端同步”。
下一篇,我们将进入安全核心 —— 认证与授权 (Auth):JWT 登录全流程实战。