GORM 单表操作与高级查询
GORM 单表操作与高级查询1. GORM 简介与快速开始GORM 是 Go 语言中最流行的 ORM 框架它提供了丰富的功能模型定义、自动迁移、链式操作、事务、预编译等。本文聚焦于单表操作将带你从创建连接开始逐步深入各种查询技巧让你能高效地写出健壮的数据访问代码。环境准备在你的 Go 项目中安装 GORM 及对应的数据库驱动这里以 MySQL 为例go get-ugorm.io/gorm go get-ugorm.io/driver/mysql2. 模型定义与数据库连接假设我们有一个用户表users对应结构体如下packagemainimport(gorm.io/gormgorm.io/driver/mysqltime)typeUserstruct{IDuintgorm:primaryKeyNamestringgorm:size:100;not nullEmailstringgorm:uniqueIndex;size:150Ageuint8IsActiveboolgorm:default:trueCreatedAt time.Time UpdatedAt time.Time}数据库连接与自动迁移funcmain(){dsn:user:passtcp(127.0.0.1:3306)/mydb?charsetutf8mb4parseTimeTruelocLocaldb,err:gorm.Open(mysql.Open(dsn),gorm.Config{})iferr!nil{panic(failed to connect database)}// 自动迁移仅开发环境推荐db.AutoMigrate(User{})}注意生产环境建议使用版本化迁移工具如golang-migrate。3. 单表基础操作增删改查3.1 创建记录user:User{Name:Alice,Email:aliceexample.com,Age:25}result:db.Create(user)// 通过指针传递ID 会自动回填fmt.Println(user.ID,result.RowsAffected,result.Error)批量创建users:[]User{{Name:Bob,Email:bobexample.com,Age:30},{Name:Charlie,Email:charlieexample.com,Age:22},}db.Create(users)3.2 查询单条记录First按主键升序获取第一条记录Take没有排序获取任意一条Last按主键降序获取最后一条varuser User db.First(user,1)// 根据主键查找db.First(user,name ?,Alice)// 条件查找// 检查是否未找到iferr:db.Take(user,email ?,noexist.com).Error;err!nil{iferrors.Is(err,gorm.ErrRecordNotFound){// 未找到记录}}3.3 查询多条记录varusers[]User db.Find(users)// 查询所有db.Where(age ?,20).Find(users)// 条件查询3.4 更新记录// 更新单个字段db.Model(user).Update(is_active,false)// 更新多个字段使用 map 或 structdb.Model(user).Updates(User{Name:Alice Updated,Age:26})db.Model(user).Updates(map[string]interface{}{name:Alice Updated,age:26})// 批量条件更新db.Model(User{}).Where(age ?,25).Update(is_active,false)3.5 删除记录// 软删除如果模型包含 gorm.DeletedAt 字段则会自动软删除db.Delete(user)// 根据主键删除db.Where(age ?,60).Delete(User{})// 批量删除4. 高级查询技巧以下所有查询均基于单表users进行所有示例可直接运行。4.1 条件构建Where / Or / Notvarusers[]User// 等值查询db.Where(name ?,Alice).Find(users)// 多个条件之间是 ANDdb.Where(name ? AND age ?,Alice,20).Find(users)// 使用 map 构建条件等值 ANDdb.Where(map[string]interface{}{name:Alice,is_active:true}).Find(users)// 使用 struct 构建条件零值字段会被忽略db.Where(User{Name:Alice,Age:25}).Find(users)// Or 条件db.Where(name ?,Alice).Or(name ?,Bob).Find(users)// Not 条件db.Not(age ?,18).Find(users)db.Not(name,[]string{Alice,Bob}).Find(users)// NOT IN4.2 比较与范围查询// 大于、小于、不等于db.Where(age ?,25).Find(users)db.Where(age ?,30).Find(users)// BETWEENdb.Where(age BETWEEN ? AND ?,20,30).Find(users)// INdb.Where(name IN ?,[]string{Alice,Bob}).Find(users)// 组合条件db.Where((age ? AND is_active ?) OR email ?,25,true,adminexample.com).Find(users)4.3 模糊匹配与正则// LIKEdb.Where(name LIKE ?,%li%).Find(users)// 包含 li// 正则MySQL 示例db.Where(name REGEXP ?,^A[a-z]).Find(users)// 以 A 开头后面跟小写字母4.4 排序、分页与限量// 排序db.Order(age desc, name asc).Find(users)// 分页Limit Offsetvarpageint2varpageSizeint10db.Limit(pageSize).Offset((page-1)*pageSize).Find(users)// 更推荐使用 Scopes 封装分页逻辑funcPaginate(page,pageSizeint)func(db*gorm.DB)*gorm.DB{returnfunc(db*gorm.DB)*gorm.DB{ifpage0{page1}ifpageSize0{pageSize10}offset:(page-1)*pageSizereturndb.Offset(offset).Limit(pageSize)}}db.Scopes(Paginate(2,10)).Find(users)4.5 聚合查询Count / Sum / Group By / Having// 计数varcountint64db.Model(User{}).Where(age ?,20).Count(count)// 分组统计每年龄的人数typeAgeGroupstruct{Ageuint8Countint}varageGroups[]AgeGroup db.Model(User{}).Select(age, count(*) as count).Group(age).Find(ageGroups)// 分组后过滤db.Model(User{}).Select(age, count(*) as count).Group(age).Having(count ?,2).Find(ageGroups)// 求和、平均值等varsumAgeint64db.Model(User{}).Select(sum(age)).Scan(sumAge)4.6 字段选择与 Distinct// 只查询特定字段db.Select(name,email).Find(users)// 去重varemails[]stringdb.Model(User{}).Distinct(email).Find(emails)4.7 子查询与原生 SQL单表操作也常需要子查询如查询年龄大于平均年龄的用户varusers[]User subQuery:db.Model(User{}).Select(avg(age))db.Where(age (?),subQuery).Find(users)执行原生 SQLvaruser User db.Raw(SELECT * FROM users WHERE name ?,Alice).Scan(user)// 使用 Exec 执行更新/删除db.Exec(UPDATE users SET is_active ? WHERE age ?,false,20)4.8 事务中的单表操作err:db.Transaction(func(tx*gorm.DB)error{// 在事务中执行一系列单表操作iferr:tx.Create(User{Name:TxUser}).Error;err!nil{returnerr}iferr:tx.Model(User{}).Where(name ?,Alice).Update(age,28).Error;err!nil{returnerr}// 返回 nil 提交返回 error 则回滚returnnil})iferr!nil{// 处理事务失败}5. 实战案例用户管理系统查询模块下面给出一个完整的服务层示例展示如何在函数中组合各种高级查询。packageserviceimport(gorm.io/gormyour-project/model)typeUserQuerystruct{KeywordstringAgeMinintAgeMaxintIsActive*bool// 使用指针以便区分零值PageintPageSizeint}funcSearchUsers(db*gorm.DB,q UserQuery)([]model.User,int64,error){varusers[]model.Uservartotalint64query:db.Model(model.User{})ifq.Keyword!{like:%q.Keyword%queryquery.Where(name LIKE ? OR email LIKE ?,like,like)}ifq.AgeMin0{queryquery.Where(age ?,q.AgeMin)}ifq.AgeMax0{queryquery.Where(age ?,q.AgeMax)}ifq.IsActive!nil{queryquery.Where(is_active ?,*q.IsActive)}// 先统计总数iferr:query.Count(total).Error;err!nil{returnnil,0,err}// 分页与排序err:query.Order(created_at DESC).Offset((q.Page-1)*q.PageSize).Limit(q.PageSize).Find(users).Errorreturnusers,total,err}这样就能灵活应对前端的各种组合查询需求并且实现了分页与总数返回。