创建工程
初始的集成库选择
Ktorm集成方式
请参照Ktorm官方的开发文档进行集成
传送门: Ktorm开发文档
数据库选择及安装
本问选用Postgre数据库,具体的安装流程请站内搜索还是很简单的,需要说明的是,postgre安装完成后,考虑到多数据源的使用场景(一个项目中需要访问多个数据库,具体的创建流程请自行通过pgAdmin创建,这个过程基本都是可视化的操作及其简单,而且也没啥坑,就不多加说明了),我们创建两个数据库user和order(名字自己命名吧)
连接数据库
Ktorm提供了两种连接数据库的方式,分别为Database.connect和Database.connectWithSpringSupport,为了能使用到对spring的支持以及事务管理以及对多数据源的管理,本专栏使用的是第二种方式。但由于官方文档对于DataSource创建并没有详细的步骤说明,这里还是踩坑了很久的。在具体连接数据库之前我们先来选用一个管理连接数据库的工具-连接池
连接池
数据库的连接在后台开发中是很重要的资源开销,所以Ktorm也推荐使用连接池来管理数据库的连接,这里我们选用阿里的Druid连接池
传送门: Druid
连接池的配置
我们通过在application.properties配置文件中对数据库连接进行配置(这里的配置包含了Ktorm的数据源连接方式以及Druid连接池),需要注意的是,这里的配置仅仅只是为Ktorm提供DataSource而不是Ktorm直接去管理数据库的连接,Ktorm开发文档中也详细说明了DataSource 的创建并不是 Ktorm 的职责,而且使用连接池对大多数场景都是适用的而且高效的,Ktorm也强烈建议使用连接池来管理数据库连接。Druid具体的配置见传送门: Druid+Spring Boot多数据源配置
需要注意的一点是:
第一个数据源的url配置为
spring.datasource.druid.user.url=jdbc:postgresql://localhost:5432/user
第二个数据源的话就变成了
spring.datasource.druid.order.url=jdbc:postgresql://localhost:5432/order
等号前面的是固定的写法,user与order只是代表两个不同的数据源,后面的user,order就是代表的前面我们创建的user,order数据库
建立对象 - 关系映射
准备工作
这个部分其实就是ORM框架的核心部分,关于为什么要有ORM框架,ORM框架能带来什么好处,什么是阻抗失配,这些内容可以站内搜索,很多博主已经讲的非常的详细,这里就不在赘述。不过在建立对象-关系映射之前,我们还有一部分的依赖需要添加进我们的工程中。至于为什么添加,大家可以自行搜索每一个依赖的具体作用,结合kotlin与java环境下Spring开发的异同以及ORM框架Ktorm集成文档,基本就能理解完全了。
在build.gradle.kts中的plugins里添加
//JPA持久化
kotlin("plugin.jpa") version "1.6.21"
//allOpen全开放编译插件
kotlin("plugin.allopen") version "1.6.21"
在dependencies中添加
//Postgre数据库
runtimeOnly("org.postgresql:postgresql")
//ORM框架ktorm(解决实体类与数据库的匹配)
implementation ("org.ktorm:ktorm-core:3.5.0")
implementation("org.ktorm:ktorm-jackson:3.5.0")
implementation("org.ktorm:ktorm-support-postgresql:3.5.0")
//jdbc(ktorm对spring支持所需)
implementation("org.springframework.boot:spring-boot-starter-jdbc")
//数据库连接池duid
implementation("com.alibaba:druid-spring-boot-starter:1.2.13")
在最外层添加
//allOpen全开放编译插件
allOpen {
annotation("javax.persistence.Entity")
annotation("javax.persistence.Embeddable")
annotation("javax.persistence.MappedSuperclass")
}
Ktorm使用多数据源的DataSource
在配置好连接池后我们就需要从连接的数据库中获取数据源,并交给Ktorm来做处理,这里我们需要先创建一个KtormConfiguration,来把连接池的配置获取并生成DataSource并交给Ktorm,Ktorm根据DataSource来创建的Database以实现对数据库的操作。实例代码中有很多的注解关键词,大家可以站内搜索一下每个关键词的具体作用,加深理解。
@Configuration
class KtormConfiguration {
@Bean
fun databaseUser(): Database {
return Database.connectWithSpringSupport(getDataSourceUser())
}
@Bean
fun databaseOrder(): Database {
return Database.connectWithSpringSupport(getDataSourceOrder())
}
/**
* 多数据源配置
*/
@Primary
@Bean
@ConfigurationProperties("spring.datasource.druid.user")
fun getDataSourceUser(): DataSource {
return DruidDataSourceBuilder.create().build()
}
/**
* 多数据源配置
*/
@Bean
@ConfigurationProperties("spring.datasource.druid.order")
fun getDataSourceOrder(): DataSource {
return DruidDataSourceBuilder.create().build()
}
/**
* 将 Ktorm 的 Jackson 扩展注册到 Spring 的容器中,
* 以便我们可以序列化和序列化 Ktorm 实体。
*/
@Bean
fun ktormModule(): Module {
return KtormModule()
}
}
实体类与数据库表列的绑定
首先我们通过数据库可视化工具pgadmin4或者Navicat往user和order两个数据库中添加两张表user_info和order_info并设定相关的字段及属性。创建完表后回到工程创建两个kotlin.file文件UserTable.kt和OrderTable.kt并参照Ktorm开发文档中的实体类与列绑定的相关规则把实体类与我们的数据库表对应起来
//order_info数据库表与实体类的绑定
object OrderInfos: Table<OrderInfo>("order_info"){
val id = int("id").primaryKey().bindTo { it.id }
val orderId = varchar("orderId").bindTo { it.orderId }
}
interface OrderInfo: Entity<OrderInfo> {
companion object : Entity.Factory<OrderInfo>()
val id : Int
val orderId : String
}
序列API
结合Ktorm开发文档中有关实体类API章节中的说明来做增删改查的实现,这里额外注意的是@Qualifier(“databaseOrder”)这个注解。还记得我们之前的学习过程中有讲述过所数据源的部分吗?这个注解就是代表我们使用的是哪个数据源
abstract class OrderBaseDao<E : Entity<E>, T : Table<E>>(private val tableObject: T) {
@Qualifier("databaseOrder")
@Autowired
protected lateinit var database: Database
/**
* 插入
*/
open fun add(entity: E): Int {
return database.sequenceOf(tableObject).add(entity)
}
/**
* 更新
*/
open fun update(entity: E): Int {
return database.sequenceOf(tableObject).update(entity)
}
/**
* 删除
*/
open fun deleteIf(predicate: (T) -> ColumnDeclaring<Boolean>): Int {
return database.sequenceOf(tableObject).removeIf(predicate)
}
/**
* 返回所有符合的查询条件
*/
open fun allMatched(predicate: (T) -> ColumnDeclaring<Boolean>): Boolean {
return database.sequenceOf(tableObject).all(predicate)
}
/**
* 如果至少一条记录与给定的条件匹配,则返回 true。
*/
open fun anyMatched(predicate: (T) -> ColumnDeclaring<Boolean>): Boolean {
return database.sequenceOf(tableObject).any(predicate)
}
/**
* 如果没有记录与给定的条件匹配,则返回 true。
*/
open fun noneMatched(predicate: (T) -> ColumnDeclaring<Boolean>): Boolean {
return database.sequenceOf(tableObject).none(predicate)
}
/**
* 返回表中的记录数
*/
open fun count(): Int {
return database.sequenceOf(tableObject).count()
}
/**
* 返回与表中给定条件匹配的记录数。
*/
open fun count(predicate: (T) -> ColumnDeclaring<Boolean>): Int {
return database.sequenceOf(tableObject).count(predicate)
}
/**
* 返回与给定条件匹配的实体对象。
*/
open fun findOne(predicate: (T) -> ColumnDeclaring<Boolean>): E? {
return database.sequenceOf(tableObject).find(predicate)
}
/**
* 返回与给定条件匹配的实体列表。
*/
open fun findList(predicate: (T) -> ColumnDeclaring<Boolean>): List<E> {
return database.sequenceOf(tableObject).filter(predicate).toList()
}
/**
* 返回表中的所有实体
*/
open fun findAll(): List<E> {
return database.sequenceOf(tableObject).toList()
}
}
此时我们的数据库操作有了,对象与关系的映射对照也有了,接下来就是把两者结合起来,以实现我们能基于实体操作数据库的功能了
@Component
class OrderDao:OrderBaseDao<OrderInfo, OrderInfos>(OrderInfos)
至此我们的ORM框架的集成及使用就基本完成了。至于Ktorm更多的功能实现,可以参照Ktorm的开发文档自行学习。下一章节我们将实现基于Ktorm的API接口的书写