CRUD操作 #
一、创建操作 #
1.1 创建单条记录 #
go
func main() {
r := gin.Default()
r.POST("/users", func(c *gin.Context) {
var user User
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
// 创建记录
if err := DB.Create(&user).Error; err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.JSON(201, user)
})
r.Run()
}
1.2 批量创建 #
go
r.POST("/users/batch", func(c *gin.Context) {
var users []User
if err := c.ShouldBindJSON(&users); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
// 批量创建
if err := DB.Create(&users).Error; err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.JSON(201, users)
})
// 分批创建
r.POST("/users/batch-large", func(c *gin.Context) {
var users []User
if err := c.ShouldBindJSON(&users); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
// 每批100条
if err := DB.CreateInBatches(&users, 100).Error; err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.JSON(201, users)
})
1.3 创建时指定字段 #
go
// 只插入指定字段
DB.Select("Name", "Email").Create(&user)
// 排除指定字段
DB.Omit("Age").Create(&user)
1.4 FirstOrCreate #
go
// 查找或创建
user := User{Name: "Alice"}
result := DB.Where(User{Name: "Alice"}).FirstOrCreate(&user)
// user.ID > 0 表示已存在,= 0 表示新创建
二、查询操作 #
2.1 基本查询 #
go
// 查询所有
var users []User
DB.Find(&users)
// 查询单条
var user User
DB.First(&user, 1) // 按主键查询
DB.First(&user, "id = ?", 1) // 按条件查询
DB.Take(&user) // 取一条记录
DB.Last(&user) // 取最后一条
// 检查是否存在
if errors.Is(DB.First(&user, 1).Error, gorm.ErrRecordNotFound) {
// 记录不存在
}
2.2 条件查询 #
go
// WHERE条件
DB.Where("name = ?", "Alice").First(&user)
DB.Where("name <> ?", "Alice").Find(&users)
DB.Where("age > ?", 18).Find(&users)
DB.Where("age >= ?", 18).Find(&users)
DB.Where("age < ?", 18).Find(&users)
DB.Where("age <= ?", 18).Find(&users)
DB.Where("age IN ?", []int{18, 19, 20}).Find(&users)
DB.Where("name LIKE ?", "%ali%").Find(&users)
DB.Where("name LIKE ?", "ali%").Find(&users)
// AND条件
DB.Where("name = ? AND age >= ?", "Alice", 18).Find(&users)
// OR条件
DB.Where("name = ?", "Alice").Or("name = ?", "Bob").Find(&users)
// NOT条件
DB.Not("name", "Alice").Find(&users)
2.3 结构体和Map条件 #
go
// 结构体条件
DB.Where(&User{Name: "Alice", Age: 18}).First(&user)
// SELECT * FROM users WHERE name = "Alice" AND age = 18;
// Map条件
DB.Where(map[string]interface{}{"name": "Alice", "age": 18}).Find(&users)
// 主键切片
DB.Where([]int64{1, 2, 3}).Find(&users)
2.4 选择字段 #
go
// 选择指定字段
DB.Select("name", "age").Find(&users)
DB.Select("name, age").Find(&users)
// 使用函数
DB.Select("AVG(age) as avg_age").Find(&result)
2.5 排序 #
go
// 单字段排序
DB.Order("age desc").Find(&users)
DB.Order("age desc, name asc").Find(&users)
2.6 分页 #
go
// Limit和Offset
DB.Limit(10).Find(&users)
DB.Limit(10).Offset(10).Find(&users)
// 分页函数
func Paginate(page, pageSize int) func(db *gorm.DB) *gorm.DB {
return func(db *gorm.DB) *gorm.DB {
if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = 10
}
offset := (page - 1) * pageSize
return db.Offset(offset).Limit(pageSize)
}
}
// 使用分页
DB.Scopes(Paginate(1, 10)).Find(&users)
2.7 分组 #
go
type Result struct {
Name string
Total int
}
// GROUP BY
DB.Model(&User{}).Select("name, count(*) as total").Group("name").Find(&results)
// HAVING
DB.Model(&User{}).Select("name, count(*) as total").Group("name").Having("count(*) > ?", 1).Find(&results)
2.8 关联查询 #
go
// 预加载
DB.Preload("Posts").Find(&users)
DB.Preload("Posts").Preload("Profile").Find(&users)
// 条件预加载
DB.Preload("Posts", "title LIKE ?", "%go%").Find(&users)
// 嵌套预加载
DB.Preload("Posts.Comments").Find(&users)
// Joins预加载
DB.Joins("Posts").Find(&users)
2.9 统计 #
go
var count int64
DB.Model(&User{}).Count(&count)
// 条件统计
DB.Model(&User{}).Where("age > ?", 18).Count(&count)
// 分组统计
DB.Model(&User{}).Select("count(*) as count, age").Group("age").Find(&results)
三、更新操作 #
3.1 更新单个字段 #
go
// 更新单个字段
DB.Model(&user).Update("name", "Alice Updated")
// 条件更新
DB.Model(&User{}).Where("id = ?", 1).Update("name", "Alice Updated")
// 更新多个字段
DB.Model(&user).Updates(User{Name: "Alice", Age: 20})
DB.Model(&user).Updates(map[string]interface{}{"name": "Alice", "age": 20})
3.2 更新整个模型 #
go
// 更新所有字段
user.Name = "Alice Updated"
user.Age = 20
DB.Save(&user)
3.3 更新表达式 #
go
// 更新表达式
DB.Model(&user).Update("age", gorm.Expr("age + ?", 1))
DB.Model(&user).Update("age", gorm.Expr("age * ?", 2))
3.4 批量更新 #
go
// 批量更新
DB.Model(&User{}).Where("age > ?", 18).Updates(map[string]interface{}{"status": "adult"})
// 更新所有
DB.Model(&User{}).Where("1 = 1").Updates(map[string]interface{}{"status": "active"})
3.5 更新选中字段 #
go
// 只更新选中字段
DB.Model(&user).Select("Name").Updates(map[string]interface{}{"name": "Alice", "age": 20})
// 排除字段
DB.Model(&user).Omit("Age").Updates(map[string]interface{}{"name": "Alice", "age": 20})
四、删除操作 #
4.1 删除记录 #
go
// 删除单条记录
DB.Delete(&user, 1)
DB.Delete(&user, "id = ?", 1)
// 条件删除
DB.Where("name = ?", "Alice").Delete(&User{})
// 批量删除
DB.Where("age < ?", 18).Delete(&User{})
4.2 软删除 #
go
type User struct {
ID uint
Name string
DeletedAt gorm.DeletedAt `gorm:"index"`
}
// 软删除
DB.Delete(&user, 1)
// 查询时会自动排除软删除记录
DB.Find(&users)
// 包含软删除记录
DB.Unscoped().Find(&users)
// 永久删除
DB.Unscoped().Delete(&user, 1)
4.3 物理删除 #
go
// 永久删除(绕过软删除)
DB.Unscoped().Delete(&user, 1)
五、原生SQL #
5.1 原生查询 #
go
// 原生SQL查询
var users []User
DB.Raw("SELECT * FROM users WHERE age > ?", 18).Scan(&users)
// 原生SQL查询单条
var user User
DB.Raw("SELECT * FROM users WHERE id = ?", 1).Scan(&user)
5.2 原生执行 #
go
// 执行原生SQL
DB.Exec("UPDATE users SET age = ? WHERE id = ?", 20, 1)
// 执行存储过程
DB.Exec("CALL update_user_age(?, ?)", 1, 20)
5.3 Rows #
go
// 使用Rows
rows, err := DB.Model(&User{}).Where("age > ?", 18).Rows()
if err != nil {
panic(err)
}
defer rows.Close()
for rows.Next() {
var user User
DB.ScanRows(rows, &user)
fmt.Println(user)
}
六、事务操作 #
6.1 自动事务 #
go
func CreateUserWithProfile(user *User, profile *Profile) error {
return DB.Transaction(func(tx *gorm.DB) error {
if err := tx.Create(user).Error; err != nil {
return err
}
profile.UserID = user.ID
if err := tx.Create(profile).Error; err != nil {
return err
}
return nil
})
}
6.2 手动事务 #
go
func CreateUserWithProfile(user *User, profile *Profile) error {
tx := DB.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
if err := tx.Create(user).Error; err != nil {
tx.Rollback()
return err
}
profile.UserID = user.ID
if err := tx.Create(profile).Error; err != nil {
tx.Rollback()
return err
}
return tx.Commit().Error
}
七、完整示例 #
7.1 用户CRUD #
go
package main
import (
"net/http"
"strconv"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
type User struct {
ID uint `gorm:"primaryKey" json:"id"`
Name string `json:"name"`
Email string `json:"email"`
Age int `json:"age"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
}
func main() {
r := gin.Default()
// 列表查询
r.GET("/users", func(c *gin.Context) {
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "10"))
var users []User
var total int64
DB.Model(&User{}).Count(&total)
DB.Scopes(Paginate(page, pageSize)).Find(&users)
c.JSON(200, gin.H{
"data": users,
"total": total,
"page": page,
"page_size": pageSize,
})
})
// 获取详情
r.GET("/users/:id", func(c *gin.Context) {
id, _ := strconv.Atoi(c.Param("id"))
var user User
if err := DB.First(&user, id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
c.JSON(404, gin.H{"error": "用户不存在"})
return
}
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.JSON(200, user)
})
// 创建用户
r.POST("/users", func(c *gin.Context) {
var user User
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
if err := DB.Create(&user).Error; err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.JSON(201, user)
})
// 更新用户
r.PUT("/users/:id", func(c *gin.Context) {
id, _ := strconv.Atoi(c.Param("id"))
var user User
if err := DB.First(&user, id).Error; err != nil {
c.JSON(404, gin.H{"error": "用户不存在"})
return
}
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
if err := DB.Save(&user).Error; err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.JSON(200, user)
})
// 删除用户
r.DELETE("/users/:id", func(c *gin.Context) {
id, _ := strconv.Atoi(c.Param("id"))
if err := DB.Delete(&User{}, id).Error; err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.Status(204)
})
r.Run()
}
func Paginate(page, pageSize int) func(db *gorm.DB) *gorm.DB {
return func(db *gorm.DB) *gorm.DB {
if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = 10
}
offset := (page - 1) * pageSize
return db.Offset(offset).Limit(pageSize)
}
}
八、总结 #
8.1 核心要点 #
| 操作 | 方法 |
|---|---|
| 创建 | Create、CreateInBatches |
| 查询 | Find、First、Take、Last |
| 更新 | Update、Updates、Save |
| 删除 | Delete、Unscoped().Delete |
8.2 最佳实践 #
| 实践 | 说明 |
|---|---|
| 错误处理 | 检查Error |
| 软删除 | 使用DeletedAt |
| 分页查询 | 使用Limit和Offset |
| 事务 | 保证数据一致性 |
8.3 下一步 #
现在你已经掌握了CRUD操作,接下来让我们学习 数据库迁移,了解数据库结构管理!
最后更新:2026-03-28