第九篇:《GORM 实战:连接 MySQL 与 CRUD 操作》

发布时间:2026/7/24 9:11:50

第九篇:《GORM 实战:连接 MySQL 与 CRUD 操作》 在前面的文章中我们的图书数据都存储在内存中——服务重启后数据全部丢失。在实际项目中数据需要持久化存储最常用的关系型数据库是 MySQL。GORM 是 Go 生态中最流行的 ORM 库它提供了对象-关系映射能力让我们可以用 Go 结构体和方法来操作数据库而不需要手写 SQL。本文从 GORM 的安装与连接讲起涵盖模型定义、自动迁移、CRUD 操作等核心功能并通过一个完整的用户管理实战帮你掌握 Go 语言操作数据库的基本技能。一、ORM 是什么为什么选择 GORMORMObject-Relational Mapping对象关系映射 是一种编程技术用于在关系型数据库和面向对象编程语言之间建立映射关系。它将数据库表映射为编程语言中的对象/结构体将 SQL 操作转换为方法调用。使用 ORM 的主要好处开发效率高用结构体和方法替代手写 SQL减少模板代码。类型安全编译时检查字段类型避免 SQL 语法错误。可移植性ORM 抽象了底层 SQL 方言切换数据库MySQL → PostgreSQL时改动较小。GORM 是 Go 中最流行的 ORM 库目前维护版本为 v2具有以下核心特点二、安装与连接 MySQL2.1 安装 GORM 和 MySQL 驱动# 安装 GORMgo get-ugorm.io/gorm# 安装 MySQL 驱动go get-ugorm.io/driver/mysql2.2 连接 MySQL在 Go 中连接 MySQL 需要构建 DSNData Source Name数据源名称 字符串packagemainimport(gorm.io/driver/mysqlgorm.io/gormgorm.io/gorm/logger)funcmain(){// DSN: 用户名:密码tcp(主机:端口)/数据库名?charsetutf8mb4parseTimeTruelocLocaldsn:root:123456tcp(127.0.0.1:3306)/testdb?charsetutf8mb4parseTimeTruelocLocal// 连接数据库db,err:gorm.Open(mysql.Open(dsn),gorm.Config{Logger:logger.Default.LogMode(logger.Info),// 打印 SQL 日志})iferr!nil{panic(连接数据库失败: err.Error())}// 获取底层的 *sql.DB可以配置连接池sqlDB,_:db.DB()sqlDB.SetMaxIdleConns(10)// 设置空闲连接池中的最大连接数sqlDB.SetMaxOpenConns(100)// 设置数据库连接最大打开数sqlDB.SetConnMaxLifetime(time.Hour)// 设置连接可复用的最大时间fmt.Println(数据库连接成功!)}⚠️ 注意DSN 中的 parseTimeTrue 使 GORM 自动将 MySQL 的 DATETIME 类型映射为 Go 的 time.Timecharsetutf8mb4 支持完整的 Unicode包括 emoji。三、模型定义与标签在 GORM 中数据库表通过 Go 结构体来定义。结构体中的字段通过标签Tag 来控制数据库映射行为。3.1 基础模型packagemodelsimport(gorm.io/gormtime)// User 用户模型typeUserstruct{IDuintgorm:primaryKey json:idNamestringgorm:size:100;not null json:nameEmailstringgorm:size:100;uniqueIndex;not null json:emailAgeintgorm:default:0 json:ageCreatedAt time.Timejson:created_atUpdatedAt time.Timejson:updated_atDeletedAt gorm.DeletedAtgorm:index json:-}3.2 常用标签![标签 说明 示例primaryKey 设置为主键 gorm:“primaryKey”size 字段长度字符串 gorm:“size:100”not null 非空约束 gorm:“not null”unique 唯一约束 gorm:“unique”uniqueIndex 唯一索引 gorm:“uniqueIndex”index 普通索引 gorm:“index”default 默认值 gorm:“default:0”column 指定数据库列名 gorm:“column:user_name”type 指定数据库字段类型 gorm:“type:text”忽略该字段不存储 gorm:“-”](https://i-blog.csdnimg.cn/direct/afe3dbdae943489f9900136fa1e9c68f.png)3.3 嵌入 gorm.ModelGORM 提供了预定义的 gorm.Model包含 ID、CreatedAt、UpdatedAt、DeletedAt 四个常用字段typeModelstruct{IDuintgorm:primaryKeyCreatedAt time.Time UpdatedAt time.Time DeletedAt gorm.DeletedAtgorm:index}可以直接嵌入到你的模型中typeUserstruct{gorm.Model NamestringEmailstring}四、自动迁移Auto MigrationGORM 的自动迁移功能可以根据结构体自动创建或更新表结构funcmain(){db,err:gorm.Open(mysql.Open(dsn),gorm.Config{})iferr!nil{panic(err)}// 自动迁移创建表、添加字段、添加索引db.AutoMigrate(User{})// 可以同时迁移多个模型// db.AutoMigrate(User{}, Order{}, Product{})}⚠️ 注意自动迁移不会删除未使用的列也不会修改列的类型在部分数据库中可能受限。在生产环境中建议使用数据库迁移工具如 goose、golang-migrate来管理 schema 变更。五、CRUD 操作5.1 创建Create单条记录创建funccreateUser(db*gorm.DB){user:User{Name:张三,Email:zhangsanexample.com,Age:28,}result:db.Create(user)ifresult.Error!nil{fmt.Println(创建失败:,result.Error)return}fmt.Printf(创建成功用户 ID: %d\n,user.ID)}批量创建users:[]User{{Name:李四,Email:lisiexample.com,Age:22},{Name:王五,Email:wangwuexample.com,Age:25},}db.Create(users)创建时选择特定字段db.Select(Name,Email).Create(user)5.2 查询Read查询单条记录varuser User// 根据主键查询db.First(user,1)// SELECT * FROM users WHERE id 1;// 根据条件查询db.First(user,email ?,zhangsanexample.com)查询多条记录varusers[]User// 查询所有db.Find(users)// 条件查询db.Where(age ?,20).Find(users)// 链式查询db.Where(age ?,18).Order(age desc).Limit(10).Find(users)查询特定字段varusers[]User db.Select(name,email).Find(users)判断记录是否存在varuser User result:db.First(user,email ?,notexistsexample.com)ifresult.Errorgorm.ErrRecordNotFound{fmt.Println(记录不存在)}5.3 更新Update更新单条记录先查询再更新推荐varuser User db.First(user,1)user.Name张三改user.Age30db.Save(user)// 保存所有字段更新指定字段db.Model(User{}).Where(id ?,1).Update(name,新名字)// 更新多个字段db.Model(User{}).Where(id ?,1).Updates(User{Name:新名字,Age:30,})// 或用 mapdb.Model(User{}).Where(id ?,1).Updates(map[string]interface{}{name:新名字,age:30,})更新时忽略特定字段db.Model(user).Omit(created_at).Save(user)5.4 删除Delete物理删除// 根据主键删除db.Delete(User{},1)// 条件删除db.Where(age ?,18).Delete(User{})软删除如果模型中包含 gorm.DeletedAt 字段GORM 默认执行软删除——数据不会从数据库中物理删除而是将 deleted_at 字段设置为当前时间。查询时会自动忽略被软删除的记录。// 软删除db.Delete(User{},1)// 查询时会自动忽略软删除的记录db.Find(users)// 不会包含 ID 为 1 的记录// 查询包含软删除的记录db.Unscoped().Find(users)// 永久删除物理删除db.Unscoped().Delete(User{},1)六、实战用户管理服务下面是一个整合了 GORM 的完整用户管理 APIpackagemainimport(fmtnet/httptimegithub.com/gin-gonic/gingorm.io/driver/mysqlgorm.io/gormgorm.io/gorm/logger)// ---- 模型 ----typeUserstruct{IDuintgorm:primaryKey json:idNamestringgorm:size:100;not null json:nameEmailstringgorm:size:100;uniqueIndex;not null json:emailAgeintjson:ageCreatedAt time.Timejson:created_atUpdatedAt time.Timejson:updated_atDeletedAt gorm.DeletedAtgorm:index json:-}// ---- 请求结构体 ----typeCreateUserRequeststruct{Namestringjson:name binding:requiredEmailstringjson:email binding:required,emailAgeintjson:age binding:required,min1,max150}typeUpdateUserRequeststruct{Namestringjson:nameEmailstringjson:email binding:omitempty,emailAgeintjson:age binding:omitempty,min1,max150}// ---- 全局 DB ----vardb*gorm.DB// ---- Handlers ----funccreateUser(c*gin.Context){varreq CreateUserRequestiferr:c.ShouldBindJSON(req);err!nil{c.JSON(http.StatusBadRequest,gin.H{error:err.Error()})return}user:User{Name:req.Name,Email:req.Email,Age:req.Age,}iferr:db.Create(user).Error;err!nil{c.JSON(http.StatusInternalServerError,gin.H{error:创建用户失败: err.Error()})return}c.JSON(http.StatusCreated,user)}funcgetUsers(c*gin.Context){varusers[]User db.Find(users)c.JSON(http.StatusOK,users)}funcgetUser(c*gin.Context){id:c.Param(id)varuser Useriferr:db.First(user,id).Error;err!nil{c.JSON(http.StatusNotFound,gin.H{error:用户不存在})return}c.JSON(http.StatusOK,user)}funcupdateUser(c*gin.Context){id:c.Param(id)varreq UpdateUserRequestiferr:c.ShouldBindJSON(req);err!nil{c.JSON(http.StatusBadRequest,gin.H{error:err.Error()})return}// 使用 map 动态更新updates:make(map[string]interface{})ifreq.Name!{updates[name]req.Name}ifreq.Email!{updates[email]req.Email}ifreq.Age0{updates[age]req.Age}iflen(updates)0{c.JSON(http.StatusBadRequest,gin.H{error:没有需要更新的字段})return}result:db.Model(User{}).Where(id ?,id).Updates(updates)ifresult.RowsAffected0{c.JSON(http.StatusNotFound,gin.H{error:用户不存在})return}c.JSON(http.StatusOK,gin.H{message:更新成功})}funcdeleteUser(c*gin.Context){id:c.Param(id)result:db.Delete(User{},id)ifresult.RowsAffected0{c.JSON(http.StatusNotFound,gin.H{error:用户不存在})return}c.Status(http.StatusNoContent)}funcmain(){// 连接数据库dsn:root:123456tcp(127.0.0.1:3306)/testdb?charsetutf8mb4parseTimeTruelocLocalvarerrerrordb,errgorm.Open(mysql.Open(dsn),gorm.Config{Logger:logger.Default.LogMode(logger.Info),})iferr!nil{panic(连接数据库失败: err.Error())}// 自动迁移iferr:db.AutoMigrate(User{});err!nil{panic(迁移失败: err.Error())}// 设置 Ginr:gin.Default()api:r.Group(/api/v1/users){api.POST(/,createUser)api.GET(/,getUsers)api.GET(/:id,getUser)api.PUT(/:id,updateUser)api.DELETE(/:id,deleteUser)}fmt.Println(服务器启动在 :8080)r.Run(:8080)}七、小结GORMGo 生态最流行的 ORM 库通过结构体和方法操作数据库避免手写 SQL。安装与连接go get gorm.io/gorm gorm.io/driver/mysqlDSN 配置连接参数。模型定义使用结构体标签gorm:“…”控制字段映射、约束和索引。自动迁移db.AutoMigrate(Model{}) 自动创建/更新表结构。CRUD 操作Create创建、First/Find查询、Save/Updates更新、Delete删除支持软删除。

相关新闻