gorm表增删改查练习
官方中文文档: https://gorm.io/zh_CN/docs/
W3Cschool文档: https://www.w3cschool.cn/gormdoc/gormdoc-w57i3ltg.html
单表增删改查
go
package main
import (
"encoding/json"
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
type Student struct {
gorm.Model
Name string `gorm:"size:8"`
Age int
Sex string `gorm:"size:3"`
Email *string `gorm:"size:32"`
}
func JsonPrint(student interface{}) {
jsonData, err := json.MarshalIndent(student, "", " ")
if err != nil {
fmt.Println("JSON 编码失败:", err)
return
}
fmt.Println(string(jsonData))
}
func main() {
dsn := "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
fmt.Println("数据库创建失败", err)
return
}
//数据库资源释放:
//defer db.Close()
// 创建数据库
db.AutoMigrate(&Student{})
// 添加数据
//email := "fengxu@163.com"
//student := Student{
// Name: "fengxu",
// Age: 18,
// Sex: "男",
// Email: &email,
//}
//db.Create(&student)
// 批量插入数据
//var StudentList []Student
//for i := 1; i < 10; i++ {
// email := fmt.Sprintf("No.%d@163.com", i)
// student := Student{
// Name: fmt.Sprintf("No.%d", i),
// Age: 18 + i,
// Sex: "男",
// Email: &email,
// }
// StudentList = append(StudentList, student)
//}
//
//res := db.Create(&StudentList)
//
//if res.Error != nil {
// fmt.Println("插入数据失败,err:", res.Error)
// return
//}
// 存在则修改,不存在则新增
//email := "xiao@163.com"
//db.Save(&Student{ID: 1, Name: "xiao", Age: 2100, Sex: "男", Email: &email})
// 修改数据(单个字段)(id为1的修改name为萧寂)
// 批量修改数据也可以这样,如id 改成 > 1 就是批量修改
//db.Model(&Student{}).Where("id = ?", 1).Update("name", "萧寂")
// 修改数据(多个字段)(id为1的修改name为萧,age为30)
// 批量修改数据也可以这样,如id 改成 > 1 就是批量修改
//db.Model(&Student{}).Where("id > ?", 1).Updates(map[string]interface{}{
// "name": "萧",
// "age": 30,
//})
// 删除数据
// 1.硬删除,从数据库永久删除被匹配的记录(根据条件删除,可单独删除和批量删除)
//db.Unscoped().Where("name = ?", "萧").Delete(&Student{})
// 2.软删除(根据条件删除,可单独删除和批量删除)(如果你的模型包含了 gorm.DeletedAt字段(该字段也被包含在gorm.Model中),那么该模型将会自动获得软删除的能力!)
// 当调用Delete时,GORM并不会从数据库中删除该记录,而是将该记录的DeleteAt设置为当前时间,而后的一般查询方法将无法查找到此条记录。
//db.Where("age = ?", 20).Delete(&Student{})
// 3.根据主键删除(软删除)
//db.Delete(&Student{}, 34)
// 4.根据主键删除(硬删除)
//db.Unscoped().Delete(&Student{}, 34)
// 查询数据
// 1.查询所有数据(不返回带有软删除的数据)
//var student []Student
//db.Debug().Find(&student)
//// 打印查询到的数据
//// 将查询到的数据以 JSON 格式打印为数组
//JsonPrint(student)
// 2.查询到所有数据,包含软删除字段的数据
//var student []Student
//db.Unscoped().Find(&student)
//JsonPrint(student)
// 3.查询第一条数据(主键升序)
//var student Student
//db.First(&student)
//JsonPrint(student)
// 4.查询第一条数据(不指定排序字段)
//var student Student
//db.Take(&student)
//JsonPrint(student)
// 获取最后一条记录(主键降序)
//var student Student
//db.Last(&student)
//JsonPrint(student)
// 获取查询的数据的返回条数
//var student Student
//result := db.Last(&student)
//fmt.Println(result.RowsAffected) // 查询的数据返回条数
//fmt.Println(result.Error) // 错误信息,无错误为nil
// First和Last会根据主键排序,分别查询第一条和最后一条记录。只有在目标struct是指针或者通过db.Model()指定model时,该方法才有效。
//result := map[string]interface{}{}
//db.Model(&Student{}).First(&result)
//JsonPrint(result)
// 下面是个无效示例代码
//result := map[string]interface{}{}
//db.Table("students").First(&result)
// 配合Take有效(name是表名)
//result := map[string]interface{}{}
//db.Table("students").Take(&result)
//JsonPrint(result)
// 使用主键查询
// 主键id为36
//var student Student
////db.First(&student, 36) // 上下两个均可,可以为数字也能为字符串
//db.First(&student, "36")
//JsonPrint(student)
// 使用主键id查询包含于
// 如下,查询主键id包含34,35,36的记录
//var student []Student
//db.Debug().Find(&student, []int{34, 35, 36})
//JsonPrint(student)
// 如果主键是字符串,可以按照下面方式指定
// 不仅限于主键,也可以查询其他参数
//var student Student
//db.First(&student, "id = ?", "36")
//JsonPrint(student)
// 条件查询
// 获取第一条匹配的记录(name为No.3)
//var student Student
//db.Where("name = ?", "No.4").First(&student)
//JsonPrint(student)
// 获取除了name为No.1之外的全部记录
//var student []Student
//db.Where("name <> ?", "No.1").Find(&student)
//JsonPrint(student)
// 包含于,in语法
// 查询name为No.1或No.2的所有记录
//var student []Student
//db.Where("name IN ?", []string{"No.1", "No.2"}).Find(&student)
//JsonPrint(student)
// 模糊查询like
//var student []Student
//db.Debug().Where("name LIKE ?", "%No%").Find(&student)
//JsonPrint(student)
// 多个条件查询 and
//var student []Student
//db.Where("name = ? AND age >= ?", "No.1", "25").Find(&student)
//JsonPrint(student)
// 查询大于某个时间的
//var student []Student
//lastWeek := time.Now().Add(-7 * 24 * time.Hour) // 当前时间的7天前
//db.Debug().Where("updated_at > ?", lastWeek).Find(&student)
//JsonPrint(student)
// 并且 between and
// 查出七天内的数据
//var student []Student
//lastWeek := time.Now().Add(-7 * 24 * time.Hour) // 当前时间的7天前
//today := time.Now() // 当前时间
//db.Where("created_at BETWEEN ? AND ?", lastWeek, today).Find(&student)
//JsonPrint(student)
// 根据Struct&Map条件查询
// Struct的方式: 查出name为No.1,age为25的记录
//var student Student
//db.Where(&Student{Name: "No.1", Age: 25}).First(&student)
//JsonPrint(student)
// Map的方式: 查出name为No.1,age为25的记录
//var student []Student
//db.Where(map[string]interface{}{"name": "No.1", "age": 25}).Find(&student)
//JsonPrint(student)
// 注意:当使用结构作为条件查询时,GORM只会查询非零值字段。这意味着如果您的字段值为0,'',false或其他零值,该字段不会被用于构建查询条件,例如:
//var student []Student
//db.Where(&Student{Name: "No.1", Age: 0}).Find(&student)
//JsonPrint(student)
// 如果想要包含零值查询条件,你可以使用map,其会包含所有key-value的查询条件,例如:
//var student []Student
//db.Where(map[string]interface{}{"Name": "No.1", "Age": 0}).Find(&student)
//JsonPrint(student)
// 指定结构体查询字段
// 当使用struct进行查询时,你可以通过向Where()传入struct来指定查询条件的字段,值,表名,例如:
//var student []Student
//db.Where(&Student{Name: "No.1", Age: 19, Sex: "男"}, "name", "age", "sex").Find(&student)
//JsonPrint(student)
// 内联条件查询
// 查询条件也可以被内联到First和Find之类的方法中,其用法类似于Where
// 根据条件获取记录
//var student Student
// db.First(&student, "id = ?", "33")
// // db.Find(&users, "name <> ? AND age > ?", "No.1", 19)
//JsonPrint(student)
// Struct的方式
//var student Student
//db.Find(&student, Student{Age: 19})
//JsonPrint(student)
// Map的方式
//var student Student
//db.Find(&student, map[string]interface{}{"age": 19})
//JsonPrint(student)
// Not条件
// 查询name不为No.1的第一条记录
//var student []Student
//db.Not("name = ?", "No.1").First(&student)
//JsonPrint(student)
// Not in条件
// 查询name不为No.1和No.2的所有记录
//var students []Student
//db.Not(map[string]interface{}{"name": []string{"No.1", "No.2"}}).Find(&students)
//JsonPrint(students)
// Stuct方式
// 查询name不为No.1和age不为18的第一条记录
//var students []Student
//db.Not(Student{Name: "No.1", Age: 18}).First(&students)
//JsonPrint(students)
// Or条件
// 查询name为No.1或age为19的所有记录
//var students []Student
//db.Where("name = ?", "No.1").Or("age = ?", "19").Find(&students)
//JsonPrint(students)
// Struct方式
// 查询name为No.2或name为No.1并且age为19的所有记录
//var students []Student
//db.Debug().Where("name = 'No.2'").Or(Student{Name: "No.1", Age: 19}).Find(&students)
//JsonPrint(students)
}
一对一表增删改查
go
package main
import (
"encoding/json"
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"log"
)
// User 用户模型
type User struct {
gorm.Model
Name string
Email string
Detail UserDetail `gorm:"foreignKey:UserID;references:ID"`
}
// UserDetail 用户详细信息模型
type UserDetail struct {
gorm.Model
UserID uint
Address string
Phone string
}
// 单表指定查询出的属性结构体
type UserDTO struct {
Id int
Name string
Email string
}
// 多表指定查询出的属性结构体
type UserDTOTwo struct {
Id int
Name string
Email string
Phone string
Address string
}
type UserDetailTwo struct {
Address string
Phone string
}
// 两表联查带有层级结构的结构体
type UserResponse struct {
Name string `json:"name"`
Email string `json:"email"`
Detail UserDetailTwo `json:"detail"`
}
func JsonPrint(student interface{}) {
jsonData, err := json.MarshalIndent(student, "", " ")
if err != nil {
fmt.Println("JSON 编码失败:", err)
return
}
fmt.Println(string(jsonData))
}
func main() {
// 连接字符串,替换为你的MySQL配置
dsn := "root:admin@tcp(127.0.0.1:3306)/testgorm?charset=utf8mb4&parseTime=True&loc=Local"
// 连接数据库
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatal("failed to connect database:", err)
}
// 创建数据库表
err = db.AutoMigrate(&User{}, &UserDetail{})
if err != nil {
log.Fatal("failed to auto migrate:", err)
}
//// 添加数据
//// 创建用户详细信息
//detail := UserDetail{
// Address: "1234 Elm St",
// Phone: "123-456-7890",
//}
//// 创建用户并关联详细信息
//user := User{
// Name: "John Doe",
// Email: "johndoe@example.com",
// Detail: detail,
//}
//// 保存用户及其详细信息
//result := db.Create(&user) // 保存用户时,GORM 会自动保存关联的详细信息
//if result.Error != nil {
// fmt.Println(result.Error)
//}
//fmt.Println("表数据创建成功")
// 修改数据
// 仅修改User表的数据(例如更新用户邮箱)
// 假设我们要更新用户的邮箱
//var user User
//db.First(&user, 1) // 先查询出用户(这里根据id查出这条数据,具体可以看上面的单表的增删改查示例)
//user.Email = "newemail@example.com" // 更新邮箱
//db.Save(&user) // 保存更新
// 仅修改Detial表的数据(假设我们要更新用户的地址)
//var userDetail UserDetail
//db.First(&userDetail, "user_id = ?", 1) // 先查询出用户详细信息
//userDetail.Address = "5678 Oak St" // 更新地址
//db.Save(&userDetail) // 保存更新
// 同时修改两张表的数据
//tx := db.Begin() // 开启事务
//// 首先获取ID为1的用户
//var user User
//result := tx.Preload("Detail").First(&user, 1) // 预加载详细信息并根据ID查找用户(必须要预加载关联表)
//if result.Error != nil {
// tx.Rollback() // 回滚事务
// fmt.Println("查询发生了错误", result.Error)
// return
//}
//// 接下来,更新用户信息
//user.Name = "Jane Doe2"
//user.Email = "janedoe2@example.com"
//// 更新用户详细信息
//user.Detail.Address = "5678 Oak St1"
//user.Detail.Phone = "098-765-4321"
//// 使用Save方法更新用户及其关联的详细信息
//result1 := tx.Save(&user) // 更新用户
//result2 := tx.Model(&user.Detail).Updates(&user.Detail) // 更新关联的详细信息
//if result1.Error != nil || result2.Error != nil {
// tx.Rollback() // 回滚事务
// fmt.Println("更新发生了错误", result.Error, result2.Error)
// return
//}
//tx.Commit() // 提交事务
//fmt.Println("更新成功")
// 删除数据(由于是一对一的关系,所以两张表要一起删除,但是软删除)
// 开启事务
//tx := db.Begin()
// 查询用户及其详细信息
//var user User
//result := tx.Preload("Detail").First(&user, 1) // 根据ID查找用户并预加载详细信息
//if result.Error != nil {
// tx.Rollback() // 回滚事务
// fmt.Println("查询发生了错误", result.Error)
// return
//}
//// 删除用户详细信息
//if err := tx.Delete(&user.Detail).Error; err != nil {
// tx.Rollback() // 回滚事务
// fmt.Println("删除UserDetail发生了错误", err)
// return
//}
//// 删除用户
//if err := tx.Delete(&user).Error; err != nil {
// tx.Rollback() // 回滚事务
// fmt.Println("删除User发生了错误", err)
// return
//}
//// 提交事务
//tx.Commit()
//fmt.Println("删除两张表成功")
// 查询数据
// 只查询user表数据,并且只查询特定字段
// detail表也是这样查询,这种其实就是单表查询了
//var users []UserDTO
//result := db.Debug().Table("users").Select("id", "name", "email").Find(&users) // 查询User表所有数据
//if result.Error != nil {
// fmt.Println("查询User表发生了错误", result.Error)
//} else {
// JsonPrint(users)
//}
// 查询user表和detail表数据
//var usersWithDetail []User
//result := db.Preload("Detail").Find(&usersWithDetail) // 联查User和UserDetail表
//if result.Error != nil {
// log.Println("联查User和UserDetail表发生了错误", result.Error)
//} else {
// JsonPrint(usersWithDetail)
//}
// 两张表联查,只显示指定的字段,没有json层级关系
//var users []UserDTOTwo
//db.Debug().
// Table("users").
// Select("users.name, users.email, user_details.address, user_details.phone").
// Joins("left join user_details on users.id = user_details.user_id").
// Find(&users)
//JsonPrint(users)
// 两张表联查,只显示指定的字段,有json层级关系({name:"",email:"",detail:{phone:"",address:""}})
// 查询用户及其详细信息
//var users []User
//result := db.Preload("Detail").Find(&users)
//if result.Error != nil {
// log.Println("查询错误:", result.Error)
// return
//}
//// 转换为所需格式
//var userResponses []UserResponse
//for _, user := range users {
// userResponses = append(userResponses, UserResponse{
// Name: user.Name,
// Email: user.Email,
// Detail: UserDetailTwo{
// Phone: user.Detail.Phone,
// Address: user.Detail.Address,
// },
// })
//}
//JsonPrint(userResponses)
}
一对多表增删改查
go
package main
import (
"encoding/json"
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"log"
)
// User 用户模型
type User struct {
gorm.Model
Name string
Email string
Orders []Order `gorm:"foreignKey:UserID"` // 使用标签指定外键关系
}
// Order 订单模型
type Order struct {
gorm.Model
Number string
UserID uint // 用户ID,作为外键
}
func JsonPrint(student interface{}) {
jsonData, err := json.MarshalIndent(student, "", " ")
if err != nil {
fmt.Println("JSON 编码失败:", err)
return
}
fmt.Println(string(jsonData))
}
func main() {
// 连接字符串,替换为你的MySQL配置
dsn := "root:admin@tcp(127.0.0.1:3306)/testgorm?charset=utf8mb4&parseTime=True&loc=Local"
// 连接数据库
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatal("failed to connect database:", err)
}
// 创建数据库表
err = db.AutoMigrate(&User{}, &Order{})
if err != nil {
log.Fatal("failed to auto migrate:", err)
}
// 添加数据
// 创建用户
//user := User{Name: "John Doe", Email: "johndoe@example.com"}
//db.Create(&user)
//// 为用户创建订单
//orders := []Order{
// {Number: "001", UserID: user.ID},
// {Number: "002", UserID: user.ID},
// {Number: "003", UserID: user.ID},
//}
//result := db.CreateInBatches(orders, len(orders))
//if result.Error != nil {
// fmt.Println("failed to create orders:", result.Error)
// return
//}
// 批量创建用户和批量添加订单
// 创建用户列表
//users := []User{
// {Name: "John1 Doe", Email: "johndoe@example.com"},
// {Name: "Jane Doe", Email: "janedoe@example.com"},
//}
//// 批量添加用户
//db.Create(&users)
//// 创建订单列表
//orders := []Order{
// {Number: "003", UserID: users[0].ID}, // 第一个用户的订单
// {Number: "004", UserID: users[0].ID},
// {Number: "005", UserID: users[1].ID}, // 第二个用户的订单
// {Number: "006", UserID: users[1].ID},
//}
//// 批量添加订单
//result := db.CreateInBatches(orders, len(orders))
//if result.Error != nil {
// fmt.Println("failed to create orders:", result.Error)
//}
// 修改数据(查询到关联数据id,对单表进行操作即可,外面嵌套个事务,发生错误事务回滚下即可)
// 更新用户(查询到关联数据id,对单表进行操作即可,外面嵌套个事务,发生错误事务回滚下即可)
// 查询数据
// 查询当前用户及其所有订单(详细信息)
//var user User
//db.Preload("Orders").First(&user, 1) // 假设我们查询ID为1的用户
//JsonPrint(user)
// 查询当前用户及其所有订单(不含有修改时间,删除时候,更新时间这种)
var user User
result := db.Preload("Orders").First(&user, 1) // 假设我们查询ID为1的用户
if result.Error != nil {
fmt.Println("查询错误:", result.Error)
return
}
// 创建一个新的结构体来存储所需的字段
type UserResponse struct {
ID uint `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
Orders []struct {
Number string `json:"number"`
} `json:"orders"`
}
// 构建用户响应
var userResponse UserResponse
userResponse.ID = user.ID
userResponse.Name = user.Name
userResponse.Email = user.Email
for _, order := range user.Orders {
userResponse.Orders = append(userResponse.Orders, struct {
Number string `json:"number"`
}{Number: order.Number})
}
JsonPrint(userResponse) // 打印结果
}
多对多表增(删改查跟单表操作一样)
go
package main
import (
"encoding/json"
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
type User struct {
gorm.Model
Name string
Roles []Role `gorm:"many2many:user_roles;"` // 一个用户可以有多个角色
}
type Role struct {
gorm.Model
Name string
Users []User `gorm:"many2many:user_roles;"` // 一个角色可以被多个用户拥有
}
type UserRole struct {
gorm.Model
UserID uint `gorm:"primaryKey;autoIncrement:false"` // 用户id
RoleID uint `gorm:"primaryKey;autoIncrement:false"` // 角色id
}
type UserResponse struct {
ID uint `json:"id"`
Name string `json:"name"`
Roles []struct {
ID uint `json:"id"`
Name string `json:"name"`
} `json:"roles"`
}
func JsonPrint(student interface{}) {
jsonData, err := json.MarshalIndent(student, "", " ")
if err != nil {
fmt.Println("JSON 编码失败:", err)
return
}
fmt.Println(string(jsonData))
}
func main() {
// 连接字符串,替换为你的MySQL配置
dsn := "root:admin@tcp(127.0.0.1:3306)/testgorm?charset=utf8mb4&parseTime=True&loc=Local"
// 连接数据库
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
fmt.Println("数据库连接失败", err)
return
}
// 创建数据库表
err = db.AutoMigrate(&User{}, &Role{}, &UserRole{})
if err != nil {
fmt.Println("数据库表创建失败", err)
return
}
// 添加数据
// 开始事务
//tx := db.Begin()
//if tx.Error != nil {
// fmt.Println("事务开启失败", tx.Error)
// return
//}
//// 创建多个用户
//users := []User{{Name: "Alice"}, {Name: "Bob"}, {Name: "Charlie"}}
//for _, user := range users {
// result := tx.Create(&user)
// if result.Error != nil {
// tx.Rollback()
// fmt.Println("添加用户失败", result.Error)
// return
// }
//}
//// 创建多个角色
//roles := []Role{{Name: "Admin"}, {Name: "Editor"}, {Name: "Viewer"}}
//for _, role := range roles {
// result := tx.Create(&role)
// if result.Error != nil {
// tx.Rollback()
// fmt.Println("添加角色失败", result.Error)
// return
// }
//}
//// 创建用户和角色的关联
//userRoles := []UserRole{{UserID: 1, RoleID: 1}, {UserID: 1, RoleID: 2}, {UserID: 2, RoleID: 1}, {UserID: 3, RoleID: 3}}
//for _, userRole := range userRoles {
// result := tx.Create(&userRole)
// if result.Error != nil {
// tx.Rollback()
// fmt.Println("关联关系创建失败", result.Error)
// return
// }
//}
//// 提交事务
//if err := tx.Commit().Error; err != nil {
// tx.Rollback()
// fmt.Println("事务提交失败", err)
// return
//}
//fmt.Println("事务提交成功,数据关系创建成功")
// 查询数据
// 查询某个用户拥有的角色信息
// 查询ID为1的用户拥有的角色信息(全部信息)
//var user User
//result := db.Preload("Roles").First(&user, 1) // 使用Preload预加载Roles关联
//if result.Error != nil {
// fmt.Println("查找用户失败", result.Error)
// return
//}
//JsonPrint(user)
// 查询ID为1的用户拥有的角色信息(不含有创建时间,更新时间,修改时间等字段)
var user User
result := db.Preload("Roles").First(&user, 1) // 使用Preload预加载Roles关联
if result.Error != nil {
fmt.Println("查找用户失败", result.Error)
return
}
// 创建用户响应
var userResponse UserResponse
userResponse.ID = user.ID
userResponse.Name = user.Name
// 遍历用户角色,填充角色信息
for _, role := range user.Roles {
userResponse.Roles = append(userResponse.Roles, struct {
ID uint `json:"id"`
Name string `json:"name"`
}{
ID: role.ID,
Name: role.Name,
})
}
JsonPrint(userResponse) // 打印结果
}