gin-gorm操作数据库
GORM 是 Golang 的一个 orm 框架。简单说,ORM 就是通过实例对象的语法,完成关系型数据库的操作的技术,是"对象-关系映射"(Object/Relational Mapping) 的缩写。使用 ORM框架可以让我们更方便的操作数据库。
GORM 官方支持的数据库类型有: MySQL, PostgreSQL, SQlite, SQL Server
安装#
gorm.io/gorm // gorm
gorm.io/driver/mysql // mysql驱动
配置连接数据库#
package models
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
// gorm.DB 是GORM的数据库操作对象
// DB对象供整个项目使用,所以应该是一个全局的对象
var DB *gorm.DB
var err error
func init() {
/*
数据库连接参数:
"数据库账号:数据库密码@tcp(地址:端口)/数据库名?charset=utf8mb4&parseTime=True&loc=Local"
parseTime=True:
parseTime 是一个连接参数,用于告诉 GORM 在将数据库时间戳类型的值解析为 Go 时间类型时是否启用自动解析。
当 parseTime=True 时,GORM 会自动将数据库中的时间戳类型的值解析为 Go 的 time.Time 类型。
这使得你可以直接将数据库中的时间戳字段映射到 Go 的时间类型,而无需手动进行类型转换
loc=Local:
loc 是一个连接参数,用于指定数据库连接的时区位置。
当 loc=Local 时,GORM 会将数据库的时间戳类型的值作为本地时间进行解析和处理。
这意味着数据库中存储的时间戳值将根据本地时区进行转换,而不是使用默认的 UTC 时区
*/
dsn := "root:123456@tcp(127.0.0.1:3306)/gindb?charset=utf8mb4&parseTime=True&loc=Local"
//gorm.Open用于打开与数据库的连接,使用 gorm.Open 函数来建立与数据库的连接。该函数接受两个参数:数据库驱动、配置选项
// mysql.Open(dsn) 创建 MySQL 数据库驱动程序实例的函数调用
// &gorm.Config{} 是一个 GORM 库中用于配置的结构体实例,用于传递给 gorm.Open 函数以自定义数据库连接和操作的行为
DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
}
定义数据库模型#
1、结构体的名称必须首字母大写 ,并和数据库表名称对应。例如:表名称为 user 结构体名称定义成 User,表名称为 article_cate 结构体名称定义成 ArticleCate
2、结构体中的字段名称首字母必须大写,并和数据库表中的字段一一对应。例如:结构体中的 Id 和数据库中的 id 对应,Username 和数据库中的 username 对应,AddTime 和数据库中的 add_time 字段对应
3、默认情况表名是结构体名称的复数形式。如果我们的结构体名称定义成 User,表示这个模型默认操作的是 users 表
4、使用结构体中的自定义方法 TableName 改变结构体的默认表名称
package models
// GORM 倾向于约定,而不是配置。默认情况下,GORM 使用 ID 作为主键,使用结构体名的 蛇形复数 作为表名,字段名的 蛇形 作为列名,并使用 CreatedAt、UpdatedAt 字段追踪创建、更新时间
type User struct { // 对应复数users表
// 定义users表对应的字段
Id int
Username string
Age int
Email string
AddTime int // 时间戳
}
// 配置操作数据库的表名称,如果不配置默认是结构体名称的复数形式,也就是users
func (User) TableName() string {
return "user"
}
数据库CURD#
数据查询#
查询全部数据#
func (a ApiController) ApiGetInfo(context *gin.Context) {
// 查询数据库,因为Users表有很多数据,定义成一个切片,存储每一个查询到的结构体
userList := []models.User{}
// 拿到声明好的全局的DB对象,该模块定义init方法,调用的时候自动执行连接数据库
// 通过Find方法,将查询到的数据传给userList,参数为指向模型结构体的指针或指向切片的指针
models.DB.Find(&userList)
context.JSON(http.StatusOK, userList)
}
查询一条数据#
// 查询ID为3的数据
userList := models.User{Id: 3}
models.DB.Find(&userList)
条件查询#
userList := []models.User{}
// 查询age大于20的用户
models.DB.Where("age>20").Find(&userList)
userList := []models.User{}
// ?是占位符,等同于age>3
models.DB.Where("age>?",3).Find(&userList)
userList := []models.User{}
// 查询ID大于3并且小于9的数据
models.DB.Where("id>3 AND id < 9").Find(&userList)
userList := []models.User{}
// 查询ID在3、5、6中的数据
models.DB.Where("id in (?)",[]int{3,5,6}).Find(&userList)
userList := []models.User{}
// 模糊查询,查询username包含li的数据
models.DB.Where("username like ?", "%li%").Find(&userList)
userList := []models.User{}
// 查询 ID在3和9之间的数据
models.DB.Where("id between ? and ?", 3, 9).Find(&userList)
userList := []models.User{}
// 查询 id=3 or id=6 or id =8的数据
models.DB.Where("id = ? or id = ? or id = ?", 3, 6,8).Find(&userList)
// or语句的第二种写法
models.DB.Where("id = ?",3).Or("id=?",5).Or("id=?",7).Find(&userList)
userList := []models.User{}
// 查询指定字段,非指定查询字段默认为零值或者空,如果只想要对应两个字段,定义一个新的结构体
models.DB.Select("id,title").Find(&userList)
userList := []models.User{}
// asc代表升序,desc代表降序
// 查询所有数据 使用id降序排序、使用add_time升序排序
models.DB.Order("id desc").Order("add_time asc").Find(&userList)
userList := []models.User{}
// 使用limit查询两条数据
models.DB.Order("id desc").Limit(2).Find(&userList)
userList := []models.User{}
// Offset进行分页,跳过前两条数据,从第三条开始查询,
models.DB.Offset(2).Limit(2).Find(&userList)
userList := []models.User{}
// 统计查询数量
var count int64
models.DB.Find(&userList).Count(&count)
创建数据#
func (a ApiController) ApiSetInfo(context *gin.Context) {
user := models.User{
Username: "lll",
Age: 11,
Email: "111",
AddTime: 10101010,
}
// 使用create创建数据
models.DB.Create(&user)
context.String(http.StatusOK, "ok")
}
修改数据#
先查询再更新(常用)#
func (a ApiController) ApiSetInfo(context *gin.Context) {
// 结构体指定字段可以查询 ID=2的数据,如果不指定更新哪个数据,则会创建一个新的数据
user := models.User{Id: 2}
// 将username修改为setname
user.Username = "setname"
// 邮箱修改为 123.qq.com
user.Email = "123.qq.com"
// 将ID为2的数据的username和email更新
models.DB.Save(&user)
context.String(http.StatusOK, "ok")
}
func (a ApiController) ApiSetInfo(context *gin.Context) {
user := models.User{}
// 查找ID=6的数据
models.DB.Where("id = ?", 3).Find(&user)
// 修改数据
user.Username = "12333"
user.Email = "444"
// 保存修改数据
models.DB.Save(&user)
context.String(http.StatusOK, "ok")
}
更新单个字段#
user := models.User{}
// 将user表 ID=3的username字段的值改为1233
models.DB.Model(&user).Where("id= ?", 3).Update("username", "1233")
更新多个字段#
func (a ApiController) ApiSetInfo(context *gin.Context) {
user := models.User{}
// 传入更新的结构体对象 更新ID为的数据的其他字段
models.DB.Model(&user).Updates(models.User{
Id: 1,
Username: "11",
Age: 1,
Email: "1",
AddTime: 1,
})
context.String(http.StatusOK, "ok")
}
删除数据#
// 删除ID=4的数据
user := models.User{Id: 4}
models.DB.Delete(&user)
// 删除username=li的数据
user := models.User{}
models.DB.Where("username = ?", "li").Delete(&user)
使用原生sql#
userList := []models.User{}
// 使用sql语句进行查询,赋值给userlist
models.DB.Raw("select id,username from user where username = ?", "li").Scan(&userList)
// 删除id为3的数据
models.DB.Exec("delete from user where id = ?", 3)
// 修改数据id=3的username为li
models.DB.Exec("update user set username = `li` where id = ?", 3)
var count int64
// 统计查询数量
models.DB.Raw("select count(1) from user ").Scan(&count)
gorm表关联查询#
一对一#
模型定义#
User表对应用户,City对应城市,一个用户只能在一座城市
// 结构体模型
type User struct {
Id int
Username string
Age int
Email string
AddTime int
CityId int // 外键
City City // 对应的City模型
}
func (User) TableName() string {
return "user"
}
// 外键表
type City struct {
Id int
Name string
}
func (City) TableName() string {
return "city"
}
// 自定义外键字段
type User struct {
Id int
Username string
Age int
Email string
AddTime int
CId int // 外键默认是模型_id,我们可以自己定义外键字段
City City `gorm:"foreignKey:CId;references:id"` // 指定外键为c_id,对应的主键是id
// 外键默认对应是表名_id,如果是表名_id,可以不配置
// 主键默认对应是id,如果就是id,可以不配置
}
数据查询#
userList := []models.User{}
// 查询数据,并且显示对应的City模型的分类
// 传参是结构体定义的另一个结构体模型的变量
models.DB.Preload("City").Find(&userList)
context.JSON(http.StatusOK, userList)
一对多#
模型定义#
User表对应用户,City对应城市,一座城市可以有多个用户
package models
type User struct {
Id int
Username string
Age int
Email string
AddTime int
CityId int
City City
}
func (User) TableName() string {
return "user"
}
type City struct {
Id int
Name string
// 外键模型
User []User `gorm:"foreignKey:city_id"` // 指定外键为city_id
}
func (City) TableName() string {
return "city"
}
数据查询#
valueList := []models.City{}
// 获取所有的City分类对应的数据
models.DB.Preload("User").Find(&valueList)
多对多#
User表对应用户,City对应城市,一个用户可以去多个城市,一个城市可以有多个用户
模型定义#
package models
package models
// User表
type User struct {
Id int
Username string
Age int
Email string
AddTime int
CityId int
// 多对多关联关系的中间表为user_city
City []City `gorm:"many2many:user_city;"`
}
func (User) TableName() string {
return "user"
}
// city表
type City struct {
Id int
Name string
// 多对多关联关系的中间表为user_city
User []User `gorm:"many2many:user_city;"`
}
func (City) TableName() string {
return "city"
}
// 关联关系表
type UserCity struct {
UserID int
CityID int
}
func (UserCity) TableName() string {
return "user_city"
}
数据查询#
// 查询user表,并关联查询user对应的city
userList := []models.User{}
models.DB.Preload("City").Find(&userList)
// 查询uusername=li的数据和关联city
userList := []models.User{}
models.DB.Preload("City").Where("username = ?", "li").Find(&userList)
// 查询City表的关联数据
cityList := []models.City{}
models.DB.Preload("User").Find(&cityList)
// limit条件查询
cityList := []models.City{}
models.DB.Preload("User").Limit(1).Find(&cityList)
gorm使用事物#
事务处理可以用来维护数据库的完整性,保证成批的 SQL 语句要么全执行,要么全不执行
禁用默认事物#
事物默认是开启的,为了确保数据一致性,GORM 会在事务里执行写入操作(创建、更新、删除)。如果没有这方面的要求,可以在初始化时禁用它,这将获得大约 30%+ 性能提升
// 连接数据库的时候配置 SkipDefaultTransaction为true 表示禁用事物
DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{SkipDefaultTransaction: true})
使用事物#
// 如果连接数据库的禁用事物,则不能使用事物
// 开启事物
tx := models.DB.Begin()
// 抛出异常
defer func() {
if r := recover(); r != nil {
// 遇到异常的时候回滚
tx.Rollback()
return
}
}()
// 事物操作,应该用tx代替db
// 更新id为1的数据
user := models.User{Id: 1}
tx.Find(&user)
user.Username = "li"
// 更新username数据,如果更新的时候遇到err,进行回滚操作
if err := tx.Save(&user).Error; err != nil {
tx.Rollback()
return
}
// 可以执行多个不同的操作,最后统一提交
// 如果没有错误,则执行提交的操作
tx.Commit()
风月都好看,人间也浪漫.
分类:
Golang-Gin框架
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)