主键是数据库表的唯一标识。GORM 对主键有完善的约定和配置支持,包括自增主键、复合主键、UUID 主键等场景。
名为 ID 的字段自动成为主键:
type User struct {
ID uint // 自动成为主键,自增
Name string
}
生成的 SQL:
CREATE TABLE `users` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`name` longtext,
PRIMARY KEY (`id`)
);
用其他字段作为主键:
type User struct {
UserID uint `gorm:"primaryKey"`
Name string
}
多个字段组成主键:
type OrderItem struct {
OrderID uint `gorm:"primaryKey"`
ItemID uint `gorm:"primaryKey"`
Qty int
}
生成的 SQL:
CREATE TABLE `order_items` (
`order_id` bigint unsigned NOT NULL,
`item_id` bigint unsigned NOT NULL,
`qty` bigint,
PRIMARY KEY (`order_id`, `item_id`)
);
整数类型的主键默认自增:
type User struct {
ID uint // 自增主键
Name string
}
type User struct {
ID uint `gorm:"primaryKey;autoIncrement:false"`
Name string
}
GORM 不直接支持,需要用原生 SQL:
db.Exec("ALTER TABLE users AUTO_INCREMENT = 1000")
用 UUID 作为主键:
import "github.com/google/uuid"
type User struct {
ID uuid.UUID `gorm:"type:uuid;primaryKey;default:gen_random_uuid()"`
Name string
}
PostgreSQL 内置 gen_random_uuid() 函数。MySQL 需要用触发器或应用层生成。
应用层生成 UUID:
type User struct {
ID uuid.UUID `gorm:"type:uuid;primaryKey"`
Name string
}
func (u *User) BeforeCreate(tx *gorm.DB) error {
if u.ID == uuid.Nil {
u.ID = uuid.New()
}
return nil
}
type User struct {
ID string `gorm:"primaryKey;size:36"`
Name string
}
创建时手动设置:
user := User{
ID: uuid.New().String(),
Name: "张三",
}
db.Create(&user)
import "github.com/bwmarrin/snowflake"
type User struct {
ID int64 `gorm:"primaryKey"`
Name string
}
func (u *User) BeforeCreate(tx *gorm.DB) error {
if u.ID == 0 {
node, _ := snowflake.NewNode(1)
u.ID = node.Generate().Int64()
}
return nil
}
创建记录后,主键值会回填到结构体:
user := User{Name: "张三"}
db.Create(&user)
fmt.Println(user.ID) // 输出插入后的主键值
GORM v2 不直接暴露 LastInsertId,但可以通过回填获取:
user := User{Name: "张三"}
result := db.Create(&user)
fmt.Println(user.ID) // 新记录的主键
fmt.Println(result.RowsAffected) // 影响行数
主键类型影响关联关系的定义:
// 整数主键
type User struct {
ID uint
Name string
Posts []Post
}
type Post struct {
ID uint
UserID uint // 外键类型要匹配
User User
}
// UUID 主键
type User struct {
ID uuid.UUID
Name string
Posts []Post
}
type Post struct {
ID uuid.UUID
UserID uuid.UUID // 外键类型要匹配
User User
}
有些场景不需要主键(如关联表):
type UserRole struct {
UserID uint `gorm:"primaryKey"`
RoleID uint `gorm:"primaryKey"`
}
实际上还是复合主键,只是没有单独的自增字段。
主键配置要点:
| 场景 | 配置方式 |
|---|---|
| 默认主键 | 字段名 ID |
| 自定义主键 | gorm:"primaryKey" |
| 复合主键 | 多个字段加 primaryKey 标签 |
| 关闭自增 | autoIncrement:false |
| UUID 主键 | gorm:"type:uuid;primaryKey" |
| 字符串主键 | gorm:"primaryKey;size:36" |
选择主键类型要考虑业务需求: