在KMP跨平台实现时,目前主流的数据库方案有两个,Room 和 SqlDelight。
Room
Room是 Google 官方的 Android 数据库,通过注解 (@Entity, @Dao) 在 Kotlin 代码中定义数据模型和操作,框架在编译时生成实现代码;自 2.7.0 版本起也开始正式支持 KMP。
// 定义一张表
@Entity
data class User(
@PrimaryKey val uid: Int,
@ColumnInfo(name = "first_name") val firstName: String?,
@ColumnInfo(name = "last_name") val lastName: String?
)
// 定义操作方法
@Dao
interface UserDao {
@Query("SELECT * FROM user")
fun getAll(): List<User>
@Query("SELECT * FROM user WHERE uid IN (:userIds)")
fun loadAllByIds(userIds: IntArray): List<User>
@Query("SELECT * FROM user WHERE first_name LIKE :first AND " +
"last_name LIKE :last LIMIT 1")
fun findByName(first: String, last: String): User
@Insert
fun insertAll(vararg users: User)
@Delete
fun delete(user: User)
}
// 启动
@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
Room将常规操作通过注解的方式声明出来,在编译阶段由编译器自动实现具体操作的API。
虽然官方已支持,但起步晚,成熟度、社区案例和踩坑经验相比 SQLDelight 仍有差距。更稳妥的方案还是SQLDelight。
SQLDelight
SQLDelight 由 Square (现 Cash App) 开发,从一开始就为 KMP 设计。SQLDelight并不是MySql、SQLite这类的数据库,它其实是应用和数据库之间的一个"翻译",或叫"传话人"。Android上有SQLite数据库,服务器上有MySql数据库、Orcal数据库等,ios上有sqlite3数据库,不同的数据库之间必然就存在一些使用上的差异,但KMP的目标是要跨平台,它力求写出的代码适用于各类平台上,这就需要有一个方案------业务层写一遍代码,但代码可以自动适配各类平台,SQLDelight就是这个方案,它负责把业务层写的代码翻译成对应平台的数据库调用,形成
业务代码 <--> SQLDelight <--> 数据库driver <--> 平台数据库
的调用关系。
无论是Room还是SQLDelight,它们其实都不是数据库,它们最终都需要依赖真正的数据库,它们都是为了让开发者更方便、更简洁地使用数据库而开发出的一套API。两者都是通过编译阶段生成的新代码来间接调用数据库。
数据库Driver是什么?
如果做过服务端开发,想必对数据库的driver程序不会陌生。它在各种数据库框架(如 SQLDelight、Room、JDBC)中频繁出现,本质上是一个**实现了特定接口的"翻译官"。**MySQL、SQLite等是真正的数据库引擎,它们负责真正的数据存储和查询,但是不同的数据库引擎其实现方式是不一样的,如果想直接跟这些数据库打交道来,就必须明白它们的原理、学习它们的API、设计足够安全的调用方案等,很显然这是一项很耗精力的工程,但是咱们实际开发过程中并没有如此麻烦,绝大多数时候最麻烦的场景无非也就是写一些标准的SQL语句去和这些数据库打交道,这其实就是Driver的功劳!很多数据库厂商都会提供对应的driver程序,比如MySql的com.mysql.cj.jdbc.Driver、Oracle的oracle.jdbc.OracleDriver。通过这些Driver,咱们就可以使用标准(或少数特定)的SQL语句来使用数据库,而不必关心数据库实现和调用的诸多细节。
Android、ios开发中感受不到driver,是因为系统做了封装,APP层面向的API其实就是封装驱动后的结果。