GORM 除了提供基本的 CRUD 操作,还支持多种高级查询功能,能够帮助你更灵活地从数据库中检索数据
1. 条件查询
可以使用 Where
方法根据不同条件筛选数据。
基本条件查询
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
type User struct {
gorm.Model
Name string
Age int
Email string
}
func main() {
dsn := "user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic("failed to connect database")
}
var users []User
// 查询年龄大于 20 的用户
db.Where("age > ?", 20).Find(&users)
for _, user := range users {
fmt.Printf("Name: %s, Age: %d\n", user.Name, user.Age)
}
}
多条件查询
// 查询年龄大于 20 且名字为 John 的用户
db.Where("age > ? AND name = ?", 20, "John").Find(&users)
模糊查询
// 查询名字中包含 "Doe" 的用户
db.Where("name LIKE ?", "%Doe%").Find(&users)
2. 排序查询
使用 Order
方法对查询结果进行排序。
// 按年龄升序排序
db.Order("age ASC").Find(&users)
// 按年龄降序排序
db.Order("age DESC").Find(&users)
3. 分页查询
通过 Limit
和 Offset
方法实现分页查询。
// 每页 10 条记录,查询第 2 页的数据
page := 2
pageSize := 10
offset := (page - 1) * pageSize
db.Limit(pageSize).Offset(offset).Find(&users)
4. 分组查询
使用 Group
方法进行分组,结合 Having
方法进行分组过滤。
type Result struct {
Age int
Count int
}
var results []Result
// 按年龄分组并统计每组的用户数量
db.Model(&User{}).Select("age, count(*) as count").Group("age").Find(&results)
// 只返回用户数量大于 2 的分组
db.Model(&User{}).Select("age, count(*) as count").Group("age").Having("count > 2").Find(&results)
5. 关联查询
预加载关联数据
使用 Preload
方法在查询主模型时同时加载关联的模型数据,避免 N + 1 查询问题。
type User struct {
gorm.Model
Name string
Posts []Post
}
type Post struct {
gorm.Model
Title string
UserID uint
}
// 查询用户及其帖子
var user User
db.Preload("Posts").First(&user, 1)
关联条件查询
// 查询有帖子标题包含 "GORM" 的用户
db.Where("exists (select 1 from posts where posts.user_id = users.id and posts.title like ?)", "%GORM%").Find(&users)
6. 子查询
// 子查询示例:查询年龄大于平均年龄的用户
subQuery := db.Model(&User{}).Select("AVG(age)")
db.Where("age > (?)", subQuery).Find(&users)
7. 原生 SQL 查询
在某些复杂场景下,可以使用 Raw
方法执行原生 SQL 查询。
var users []User
db.Raw("SELECT * FROM users WHERE age > ?", 20).Scan(&users)
在gin中使用GORM
在 Go 语言中,Gin 是一个轻量级的 Web 框架,而 GORM 是与之搭配较为理想的 ORM(对象关系映射)框架,和 Gin 配合可以高效地构建 Web 应用。
连接数据库
创建一个数据库连接文件,用于初始化 GORM 连接到 MySQL 数据库。
请将user
、password
和dbname
替换为你自己的数据库用户名、密码和数据库名。
定义模型
创建一个模型文件,定义数据库表对应的 Go 结构体。
创建 Gin 路由和控制器
创建一个 Gin 路由文件,处理 HTTP 请求,并使用 GORM 进行数据库操作。
package main
import (
"log"
"net/http"
"github.com/gin-gonic/gin"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
// 全局数据库连接变量
var db *gorm.DB
// 数据库连接配置
func ConnectDB() error {
dsn := "user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
var err error
db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
return err
}
return nil
}
// 用户模型
type User struct {
gorm.Model
Name string
Email string `gorm:"unique"`
Password string
}
// 初始化路由
func SetupRouter() *gin.Engine {
r := gin.Default()
err := ConnectDB()
if err != nil {
log.Fatal("failed to connect database")
}
// 自动迁移模型
db.AutoMigrate(&User{})
// 定义路由组
api := r.Group("/api")
{
users := api.Group("/users")
{
users.GET("", GetUsers)
users.GET("/:id", GetUser)
users.POST("", CreateUser)
users.PUT("/:id", UpdateUser)
users.DELETE("/:id", DeleteUser)
}
}
return r
}
// GetUsers 获取所有用户
func GetUsers(c *gin.Context) {
var users []User
db.Find(&users)
c.JSON(http.StatusOK, users)
}
// GetUser 获取单个用户
func GetUser(c *gin.Context) {
var user User
id := c.Param("id")
if err := db.First(&user, id).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
return
}
c.JSON(http.StatusOK, user)
}
// CreateUser 创建用户
func CreateUser(c *gin.Context) {
var user User
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if err := db.Create(&user).Error; err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Failed to create user"})
return
}
c.JSON(http.StatusCreated, user)
}
// UpdateUser 更新用户
func UpdateUser(c *gin.Context) {
var user User
id := c.Param("id")
if err := db.First(&user, id).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
return
}
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if err := db.Save(&user).Error; err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Failed to update user"})
return
}
c.JSON(http.StatusOK, user)
}
// DeleteUser 删除用户
func DeleteUser(c *gin.Context) {
var user User
id := c.Param("id")
if err := db.First(&user, id).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
return
}
if err := db.Delete(&user).Error; err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Failed to delete user"})
return
}
c.JSON(http.StatusNoContent, nil)
}
func main() {
r := SetupRouter()
r.Run(":8080")
}