主键
本章将介绍 Kronos 中主键类型的概念及使用方法。
声明主键
在一个 KPojo 属性上使用 @PrimaryKey 声明主键。不设置生成策略参数时,字段映射为 PrimaryKeyType.DEFAULT。没有 @PrimaryKey 的字段映射为 PrimaryKeyType.NOT。
本页示例默认使用这些 import:
model
import com.kotlinorm.annotations.PrimaryKey
import com.kotlinorm.annotations.Table
import com.kotlinorm.interfaces.KPojo
import com.kotlinorm.orm.insert.insert
@Table("tb_user")
data class User(
@PrimaryKey(identity = true)
var id: Int? = null,
var username: String? = null
) : KPojo生成的字段元数据如下:
metadata
id.primaryKey -> PrimaryKeyType.IDENTITY
id.nullable -> false
username.primaryKey -> PrimaryKeyType.NOT一个主键字段只使用一个生成策略参数:identity、uuid、snowflake 或 custom。
PrimaryKeyType 速查
| 类型 | 注解写法 | 插入行为 | DDL 行为 |
|---|---|---|---|
NOT | 不使用 @PrimaryKey | 普通字段。 | 不是主键。 |
DEFAULT | @PrimaryKey | 使用 KPojo 上已有的字段值。 | 主键列。 |
IDENTITY | @PrimaryKey(identity = true) | 主键值为 null 时,从 insert 字段列表中移除。 | 数据库自增/identity 主键。 |
UUID | @PrimaryKey(uuid = true) | 插入前写入 UUIDGenerator.nextId()。 | 主键列。 |
SNOWFLAKE | @PrimaryKey(snowflake = true) | 插入前写入 SnowflakeIdGenerator.nextId()。 | 主键列。 |
CUSTOM | @PrimaryKey(custom = true) | 插入前写入 customIdGenerator?.nextId()。 | 主键列。 |
DEFAULT 手动主键
由应用程序或数据库默认值提供主键值时,直接使用不带参数的 @PrimaryKey。
kotlin
@Table("tb_region")
data class Region(
@PrimaryKey
var code: String? = null,
var name: String? = null
) : KPojo
Region(code = "CN", name = "China").insert().build()Mysql
INSERT INTO `tb_region` (`code`, `name`) VALUES (:code, :name)params
code -> "CN"
name -> "China"建表时,该字段是普通主键列。
DDL
`code` VARCHAR(255) NOT NULL PRIMARY KEYIDENTITY 数据库生成主键
使用数据库自增主键时,在 Int 或 Long 字段上设置 identity = true。
kotlin
@Table("tb_user")
data class IdentityUser(
@PrimaryKey(identity = true)
var id: Int? = null,
var username: String? = null
) : KPojo
IdentityUser(username = "Ada").insert().build()当 id 为 null 时,Kronos 会从 insert 字段列表中移除 identity 主键。
Mysql
INSERT INTO `tb_user` (`username`) VALUES (:username)params
username -> "Ada"MySQL 建表列形态如下:
DDL
`id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT如果手动传入 identity 主键值,Kronos 会保留该主键列。需要读取数据库生成值时,使用
📚Last Insert ID。
UUID UUID 字符串主键
String 主键需要由 Kronos 生成 UUID 时,设置 uuid = true。Kronos 会在构建 insert SQL 前调用 UUIDGenerator.nextId()。
kotlin
@Table("tb_uuid_user")
data class UuidUser(
@PrimaryKey(uuid = true)
var id: String? = null,
var username: String? = null
) : KPojo
UuidUser(username = "Ada").insert().build()Mysql
INSERT INTO `tb_uuid_user` (`id`, `username`) VALUES (:id, :username)params
id -> "550e8400-e29b-41d4-a716-446655440000"
username -> "Ada"建表时仍渲染为普通主键列。
DDL
`id` VARCHAR(255) NOT NULL PRIMARY KEYSNOWFLAKE 雪花算法主键
需要在应用进程内生成 Long 主键时,设置 snowflake = true。
kotlin
@Table("tb_order")
data class OrderRecord(
@PrimaryKey(snowflake = true)
var id: Long? = null,
var status: String? = null
) : KPojo
OrderRecord(status = "created").insert().build()Mysql
INSERT INTO `tb_order` (`id`, `status`) VALUES (:id, :status)params
id -> 1912549819912192000
status -> "created"多节点应用生成雪花 ID 时,先配置节点标识。
config
import com.kotlinorm.beans.generator.SnowflakeIdGenerator
fun configureSnowflakeIds() {
SnowflakeIdGenerator.datacenterId = 1
SnowflakeIdGenerator.workerId = 1
}datacenterId 和 workerId 的取值范围都是 0 到 31。
CUSTOM 自定义生成器主键
主键值需要由业务生成器提供时,设置 custom = true 并注册 KIdGenerator。
generator
import com.kotlinorm.beans.generator.customIdGenerator
import com.kotlinorm.interfaces.KIdGenerator
object TicketIdGenerator : KIdGenerator<String> {
override fun nextId(): String = "ticket-${System.currentTimeMillis()}"
}
fun configureTicketIds() {
customIdGenerator = TicketIdGenerator
}model
@Table("tb_ticket")
data class Ticket(
@PrimaryKey(custom = true)
var id: String? = null,
var title: String? = null
) : KPojo
Ticket(title = "Login issue").insert().build()Mysql
INSERT INTO `tb_ticket` (`id`, `title`) VALUES (:id, :title)params
id -> "ticket-1912549819912"
title -> "Login issue"插入
custom主键前必须设置customIdGenerator。没有设置时,生成的主键参数为null。
全局主键兜底策略
推荐在主键属性上直接使用 @PrimaryKey。只有未标注主键的模型都使用同名主键字段时,才使用 Kronos.primaryKeyStrategy 作为主键查找兜底。
config
import com.kotlinorm.Kronos
import com.kotlinorm.beans.config.KronosCommonStrategy
import com.kotlinorm.beans.dsl.Field
import com.kotlinorm.enums.PrimaryKeyType
fun configurePrimaryKeyStrategy() {
Kronos.primaryKeyStrategy = KronosCommonStrategy(
enabled = true,
field = Field("id", "id", primaryKey = PrimaryKeyType.IDENTITY)
)
}model
@Table("tb_audit_log")
data class AuditLog(
var id: Int? = null,
var message: String? = null
) : KPojo需要建表 DDL 和字段元数据都明确体现主键时,优先使用属性注解:
recommended
@PrimaryKey(identity = true)
var id: Int? = null