Ktorm 3.0 不兼容更新
时隔几个月,我们终于迎来了 Ktorm 的第二次大版本更新(Ktorm 3.0),此次更新包含了多项优化,其中也有一些不兼容的变更,特此说明。
如果这些不兼容的更新对您的项目产生了影响,我们表示十分抱歉,但这是为了确保框架长期迭代必须作出的取舍,请对照更新文档进行简单修改即可,这只会花费您几分钟的时间。
ktorm-global
Ktorm 2.7 版本废弃了 Database.global 全局变量以及与之相关的一系列 API,从此以后,我们每次操作数据的时候,都需要显式地指定一个 Database 对象,而不是隐式地使用 Database.global。关于上个版本的更多信息,请参考关于废弃 Database.global 对象的说明。
使用全局变量是糟糕的设计模式, 这样写出来的代码会与全局的状态耦合,不方便扩展,这就是我们要废弃 Database.global 的原因。然而,全局变量也有它不可替代之处,它可以让某些 API 的设计更加简洁,帮助我们写出更简短的代码。比如 Employees.findAll(),在 Ktorm 2.7 以后,我们不得不写成 database.sequenceOf(Employees).toList(),看起来啰嗦好多。
Ktorm 3.0 已经完全删除了Database.global 相关的 API,但是,为了让大家有更多的选择,我们额外提供了一个 ktorm-global 模块,这个模块重新实现了原来的那套全局变量 API,大家可以按需使用。
要使用 ktorm-global,首先应该添加一个 Maven 依赖:
1 | <dependency> |
或者 Gradle:
1 | compile "org.ktorm:ktorm-global:${ktorm.version}" |
然后,使用 Database.connectGlobally 函数连接到数据库:
1 | Database.connectGlobally("jdbc:mysql://localhost:3306/ktorm", user = "root", password = "***") |
这个方法会创建一个 Database 对象并返回,如果你需要的话,可以定义一个变量来保存这个返回值。但是通常来说,你没必要这么做,因为 ktorm-global 会自动记录最近创建的 Database 对象,在需要的时候,使用 Database.global 获取这个对象进行操作。
1 | Database.global.useConnection { conn -> |
有了全局对象,我们的很多代码都可以变得更简短,比如,直接使用 Table.select 扩展函数就可以创建一个查询:
1 | for (row in Employees.select()) { |
使用 Table.findList 扩展函数就可以获取表中符合条件的实体对象:
1 | val employees = Employees.findList { it.departmentId eq 1 } |
使用 Table.sumBy 就可以对表中的某个字段求和:
1 | val total = Employees.sumBy { it.salary } |
更多便捷用法请自己探索,也可以参照 Ktorm 2.7 版本的修改点,那些被废弃的函数,几乎全部都在 ktorm-global 中重新亮相。
使用 = 定义列,不再使用属性代理 by
在之前,我们定义一个表对象的时候,需要使用 by 关键字,利用属性代理来定义它的列,就像这样:
1 | // Ktorm 3.0 之前 |
现在,我们不再需要属性代理,直接使用等号 = 即可:
1 | // Ktorm 3.0 |
使用等号 = 更加简单直接,也避免了编译器为属性代理生成的额外字段。但是,这个改动会导致你的项目在升级到新版本之后产生许多编译错误,不用担心,你只需要找到你的所有表对象,把里面的 by 关键字批量替换成等号 = 即可。
Query 类不再实现 Iterable 接口
在之前,为了能方便地获取查询结果,我们决定让 Query 类直接实现 Iterable 接口,这样我们就能直接使用 for-each 循环对查询结果进行遍历,也可以使用 map、flatMap 等函数对结果集进行各种各样的处理,比如:
1 | data class Emp(val id: Int?, val name: String?, val salary: Long?) |
但是这也给我们带来了许多问题,因为 Iterable 的许多扩展函数的名称与 Query 的函数类似,甚至还可能存在名称冲突,这会让用户产生许多误解,比如 #124、#125。
因此,我们决定在 Ktorm 3.0 中,Query 类不再实现 Iterable 接口,为了确保原来的 DSL 代码不变,我们还提供了与 Iterable 相同的扩展函数。升级之后你会发现,尽管可能会产生一些编译错误,但是你的代码几乎是不用改的,唯一需要的可能是增加一行 import 语句,把原来对 Iterable.map 函数的调用,改成 Query.map:
1 | import org.ktorm.dsl.* |
支持复合主键
在 Ktorm 3.0 中,我们还支持为一个表设置复合主键,复合主键由多个字段组成,这些字段共同决定主键的唯一性。使用方法很简单,只需要在定义表对象时,为每个主键字段调用 primaryKey 函数即可:
1 | object Departments : Table<Nothing>("t_department") { |
这看起来只是一个简单的功能增强,但这里也存在与之前版本不兼容的地方。BaseTable 类中的 val primaryKey: Column<*> 属性被删除,改为了 val primaryKeys: List<Column<*>>,用于获取组成主键的所有字段。
其他更新
除了上述的不兼容变更,Ktorm 3.0 中还有不少来自开源社区热心人的更新,感谢他们的贡献:
- MySQL
bulkInsert函数支持on duplcate key update,感谢 @hangingman - PostgreSQL
hstore数据类型及其一系列运算符,感谢 @arustleund - ktorm-jackson 模块支持简单的 Jackson 注解,如
@JsonProperty、@JsonAlias、@JsonIgnore,感谢 @onXoot

