创建记录
2026/1/15大约 4 分钟GORMCreateInsert
创建记录
一、基本创建
1.1 创建单条记录
user := User{Name: "张三", Age: 18, Email: "zhangsan@example.com"}
result := db.Create(&user)
// 返回插入数据的主键
fmt.Println(user.ID)
// 返回影响的行数
fmt.Println(result.RowsAffected)
// 返回错误
fmt.Println(result.Error)1.2 创建时指定字段
// 只创建指定字段
db.Select("Name", "Age").Create(&user)
// 忽略指定字段
db.Omit("Email").Create(&user)1.3 批量创建
users := []User{
{Name: "张三", Age: 18},
{Name: "李四", Age: 20},
{Name: "王五", Age: 22},
}
db.Create(&users)
// 查看每条记录的 ID
for _, user := range users {
fmt.Println(user.ID)
}二、批量插入
2.1 分批创建
users := []User{{Name: "user1"}, {Name: "user2"}, {Name: "user3"}}
// 每批 100 条
db.CreateInBatches(users, 100)2.2 自定义批次大小
// 大量数据插入
var users []User
for i := 0; i < 10000; i++ {
users = append(users, User{
Name: fmt.Sprintf("user%d", i),
Email: fmt.Sprintf("user%d@example.com", i),
})
}
// 每批 1000 条
db.CreateInBatches(users, 1000)三、使用 Map 创建
3.1 单条记录
db.Model(&User{}).Create(map[string]interface{}{
"Name": "张三",
"Age": 18,
"Email": "zhangsan@example.com",
})3.2 批量创建
db.Model(&User{}).Create([]map[string]interface{}{
{"Name": "张三", "Age": 18},
{"Name": "李四", "Age": 20},
})四、默认值
4.1 数据库默认值
type User struct {
ID uint
Name string
Age int `gorm:"default:18"`
}
// Age 会使用默认值 18
user := User{Name: "张三"}
db.Create(&user)4.2 零值处理
// 零值不会被插入
user := User{Name: "张三", Age: 0}
db.Create(&user) // Age 使用默认值
// 使用指针避免零值问题
type User struct {
ID uint
Name string
Age *int
}
age := 0
user := User{Name: "张三", Age: &age}
db.Create(&user) // Age 会插入 0五、钩子函数
5.1 BeforeCreate
func (u *User) BeforeCreate(tx *gorm.DB) error {
// 创建前执行
u.UUID = uuid.New().String()
return nil
}5.2 AfterCreate
func (u *User) AfterCreate(tx *gorm.DB) error {
// 创建后执行
log.Printf("用户 %s 创建成功", u.Name)
return nil
}5.3 完整示例
type User struct {
ID uint
UUID string
Name string
CreatedAt time.Time
}
func (u *User) BeforeCreate(tx *gorm.DB) error {
u.UUID = uuid.New().String()
log.Println("BeforeCreate:", u.Name)
return nil
}
func (u *User) AfterCreate(tx *gorm.DB) error {
log.Println("AfterCreate:", u.Name, "ID:", u.ID)
return nil
}六、Upsert
6.1 冲突时不处理
import "gorm.io/gorm/clause"
// 遇到冲突时什么都不做
db.Clauses(clause.OnConflict{DoNothing: true}).Create(&user)6.2 冲突时更新
// 冲突时更新所有字段
db.Clauses(clause.OnConflict{
UpdateAll: true,
}).Create(&user)
// 冲突时更新指定字段
db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "email"}},
DoUpdates: clause.AssignmentColumns([]string{"name", "age"}),
}).Create(&user)6.3 完整示例
users := []User{
{Email: "user1@example.com", Name: "User1", Age: 18},
{Email: "user2@example.com", Name: "User2", Age: 20},
}
// 如果 email 冲突,更新 name 和 age
db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "email"}},
DoUpdates: clause.AssignmentColumns([]string{"name", "age"}),
}).Create(&users)七、关联创建
7.1 创建时保存关联
type User struct {
ID uint
Name string
Profile Profile
}
type Profile struct {
ID uint
UserID uint
Bio string
}
// 同时创建用户和 Profile
user := User{
Name: "张三",
Profile: Profile{Bio: "这是个人简介"},
}
db.Create(&user)7.2 跳过关联
// 不创建关联
db.Omit("Profile").Create(&user)
// 或使用 Select
db.Select("Name").Create(&user)八、使用 SQL 表达式
8.1 使用函数
import "gorm.io/gorm/clause"
db.Model(&User{}).Create(map[string]interface{}{
"Name": "张三",
"Age": 18,
"CreatedAt": clause.Expr{SQL: "NOW()"},
})8.2 使用子查询
db.Model(&User{}).Create(map[string]interface{}{
"Name": "张三",
"Age": db.Model(&User{}).Select("AVG(age)").Where("status = ?", 1),
})九、性能优化
9.1 批量插入优化
// 方式1:使用 CreateInBatches
users := make([]User, 10000)
db.CreateInBatches(users, 1000)
// 方式2:使用事务
db.Transaction(func(tx *gorm.DB) error {
for i := 0; i < 10000; i++ {
if err := tx.Create(&User{Name: fmt.Sprintf("user%d", i)}).Error; err != nil {
return err
}
}
return nil
})9.2 跳过钩子
// 跳过钩子函数,提高性能
db.Session(&gorm.Session{SkipHooks: true}).Create(&user)9.3 禁用事务
// 单条插入时禁用事务
db.Session(&gorm.Session{SkipDefaultTransaction: true}).Create(&user)十、完整示例
10.1 用户注册
package service
import (
"errors"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
)
type UserService struct {
db *gorm.DB
}
func (s *UserService) Register(username, email, password string) (*User, error) {
// 检查用户是否存在
var count int64
s.db.Model(&User{}).Where("email = ?", email).Count(&count)
if count > 0 {
return nil, errors.New("邮箱已被注册")
}
// 密码加密
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return nil, err
}
// 创建用户
user := User{
Username: username,
Email: email,
Password: string(hashedPassword),
Status: 1,
}
if err := s.db.Create(&user).Error; err != nil {
return nil, err
}
return &user, nil
}10.2 批量导入
func (s *UserService) BatchImport(users []User) error {
// 使用事务批量插入
return s.db.Transaction(func(tx *gorm.DB) error {
// 每批 1000 条
return tx.CreateInBatches(users, 1000).Error
})
}10.3 带关联创建
type Article struct {
ID uint
Title string
Content string
AuthorID uint
Tags []Tag `gorm:"many2many:article_tags;"`
}
type Tag struct {
ID uint
Name string
}
func (s *ArticleService) Create(title, content string, authorID uint, tagNames []string) error {
// 查找或创建标签
var tags []Tag
for _, name := range tagNames {
tag := Tag{Name: name}
s.db.FirstOrCreate(&tag, Tag{Name: name})
tags = append(tags, tag)
}
// 创建文章
article := Article{
Title: title,
Content: content,
AuthorID: authorID,
Tags: tags,
}
return s.db.Create(&article).Error
}十一、常见问题
11.1 主键未返回
// 确保传递指针
user := User{Name: "张三"}
db.Create(&user) // 正确
fmt.Println(user.ID)
// 错误示例
db.Create(user) // 错误:不会返回 ID11.2 批量插入失败
// 检查错误
users := []User{{Name: "张三"}, {Name: "李四"}}
result := db.Create(&users)
if result.Error != nil {
log.Println("插入失败:", result.Error)
}11.3 唯一约束冲突
// 使用 Upsert 处理冲突
db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "email"}},
DoUpdates: clause.AssignmentColumns([]string{"name"}),
}).Create(&user)