主题
概述
Ktorm 是 Kotlin 原生的 ORM 框架,专为 Kotlin 开发者设计。它提供类型安全的 DSL 风格 API,让数据库操作像写 Kotlin 代码一样自然流畅。
适用后端框架
| 框架 | 支持状态 |
|---|---|
| Spring Boot (Kotlin) Spring Boot (Kotlin) | ✅ 推荐 |
| Ktor | ✅ 完全支持 |
技术特性
| 特性 | 说明 |
|---|---|
| 类型安全 | 编译时检查 SQL 正确性 |
| DSL 风格 | 类似 SQL 的 Kotlin DSL |
| 轻量级 | 无反射,启动快 |
| 数据库支持 | MySQL, PostgreSQL, SQLite, Oracle, SQL Server |
| 事务支持 | 完整的事务管理 |
Kotlin ORM 选型对比
| 特性 | Ktorm | MyBatis Plus | JPA |
|---|---|---|---|
| Kotlin 原生 | ✅ 专为 Kotlin 设计 | ⚠️ Java 兼容 | ⚠️ Java 兼容 |
| 类型安全 | ✅ 编译时检查 | ❌ 运行时 | ⚠️ 部分 |
| DSL 风格 | ✅ 优雅简洁 | ❌ 方法链 | ❌ JPQL |
| 学习曲线 | 低 | 中 | 高 |
| 性能 | ✅ 无反射 | ✅ 良好 | ⚠️ 一般 |
| 社区规模 | 中 | 大(中国) | 大 |
选型建议
- Kotlin 项目首选:Ktorm,体验最佳
- 需要大量中文资料:MyBatis Plus
- 已有 JPA 经验:Spring Data JPA
定义表结构
Tables.kt
kotlin
import org.ktorm.schema.*
object Users : Table<User>("users") {
val id = long("id").primaryKey().bindTo { it.id }
val email = varchar("email").bindTo { it.email }
val name = varchar("name").bindTo { it.name }
val password = varchar("password").bindTo { it.password }
val role = varchar("role").bindTo { it.role }
val createdAt = datetime("created_at").bindTo { it.createdAt }
}
object Posts : Table<Post>("posts") {
val id = long("id").primaryKey().bindTo { it.id }
val title = varchar("title").bindTo { it.title }
val content = text("content").bindTo { it.content }
val published = boolean("published").bindTo { it.published }
val authorId = long("author_id").references(Users) { it.author }
val createdAt = datetime("created_at").bindTo { it.createdAt }
}定义实体类
Entities.kt
kotlin
import org.ktorm.entity.Entity
import java.time.LocalDateTime
interface User : Entity<User> {
companion object : Entity.Factory<User>()
var id: Long
var email: String
var name: String?
var password: String
var role: String
var createdAt: LocalDateTime
}
interface Post : Entity<Post> {
companion object : Entity.Factory<Post>()
var id: Long
var title: String
var content: String?
var published: Boolean
var author: User
var createdAt: LocalDateTime
}数据库连接
Database.kt
kotlin
import org.ktorm.database.Database
// PostgreSQL
val database = Database.connect(
url = "jdbc:postgresql://localhost:5432/mydb",
user = "postgres",
password = "postgres"
)
// MySQL
val database = Database.connect(
url = "jdbc:mysql://localhost:3306/mydb",
user = "root",
password = "password"
)
// SQLite
val database = Database.connect("jdbc:sqlite:./dev.db")CRUD 操作
查询
查询示例
kotlin
// 获取所有用户
val users = database.from(Users).select().map { Users.createEntity(it) }
// 条件查询
val admins = database.from(Users)
.select()
.where { Users.role eq "ADMIN" }
.map { Users.createEntity(it) }
// 分页查询
val pagedUsers = database.from(Users)
.select()
.orderBy(Users.createdAt.desc())
.limit(10)
.offset(0)
.map { Users.createEntity(it) }
// 复杂条件
val result = database.from(Users)
.select()
.where {
(Users.role eq "USER") and
(Users.email like "%@gmail.com") and
(Users.createdAt greaterEq startDate)
}
.map { Users.createEntity(it) }插入
插入示例
kotlin
// 使用实体插入
val user = User {
email = "test@example.com"
name = "Test User"
password = "hashed_password"
role = "USER"
createdAt = LocalDateTime.now()
}
database.sequenceOf(Users).add(user)
// 批量插入
database.batchInsert(Users) {
item {
set(Users.email, "user1@example.com")
set(Users.name, "User 1")
}
item {
set(Users.email, "user2@example.com")
set(Users.name, "User 2")
}
}更新
更新示例
kotlin
// 使用实体更新
user.name = "New Name"
user.flushChanges()
// 条件更新
database.update(Users) {
set(Users.role, "ADMIN")
where { Users.id eq 1L }
}删除
删除示例
kotlin
// 使用实体删除
user.delete()
// 条件删除
database.delete(Users) {
Users.id eq 1L
}关联查询
关联查询
kotlin
// 连接查询
val postsWithAuthor = database.from(Posts)
.leftJoin(Users, on = Posts.authorId eq Users.id)
.select(Posts.title, Users.name)
.map { row ->
PostWithAuthor(
title = row[Posts.title]!!,
authorName = row[Users.name]
)
}
// 通过实体访问关联
val post = database.sequenceOf(Posts).find { it.id eq 1L }
println(post?.author?.name) // 自动加载关联事务处理
事务
kotlin
database.useTransaction {
val user = User {
email = "new@example.com"
name = "New User"
}
database.sequenceOf(Users).add(user)
val post = Post {
title = "First Post"
author = user
}
database.sequenceOf(Posts).add(post)
// 抛出异常会自动回滚
}Spring Boot 集成
DatabaseConfig.kt
kotlin
import org.ktorm.database.Database
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import javax.sql.DataSource
@Configuration
class DatabaseConfig {
@Bean
fun database(dataSource: DataSource): Database {
return Database.connectWithSpringSupport(dataSource)
}
}UserRepository.kt
kotlin
import org.springframework.stereotype.Repository
import org.ktorm.database.Database
import org.ktorm.dsl.*
@Repository
class UserRepository(private val database: Database) {
fun findAll(): List<User> {
return database.sequenceOf(Users).toList()
}
fun findById(id: Long): User? {
return database.sequenceOf(Users).find { it.id eq id }
}
fun findByEmail(email: String): User? {
return database.sequenceOf(Users).find { it.email eq email }
}
fun save(user: User) {
database.sequenceOf(Users).add(user)
}
fun delete(id: Long) {
database.delete(Users) { it.id eq id }
}
}最佳实践
开发建议
- 使用
sequenceOf:比直接from().select()更方便 - 实体接口:定义为
interface而非data class - 懒加载关联:关联属性默认懒加载,注意 N+1 问题
- 事务边界:在 Service 层使用
useTransaction - 日志开启:开发时开启 SQL 日志便于调试