gorm的引入肯定是为了我们更好的操作数据库
在使用原生sql查询的时候
最大的问题就是没办法映射到结构体上
我们不难发现,数据库里面的记录就很想一个结构体,数据库的一列对应一个字段
所以数据库到结构体的映射就是orm的一个最大特点
所有的orm都是如此
使用一个类或者一个结构体表示一张表
然后使用一个实例化对象表示一条记录
字段表示列
安装
go get -u gorm.io/gormgo get gorm.io/driver/mysql一个简单的示例
package main
import ( //"database/sql" //"fmt" //"log"
"fmt"
//引入驱动 _ "github.com/go-sql-driver/mysql" "gorm.io/driver/mysql" "gorm.io/gorm")
// 用结构体来表示一个表type User struct { ID int Username string Age int}
// 在结构体中指定表名func (User) TableName() string { return "user"}func main() { //连接数据库 //数据源名称(用户名:密码@tcp(地址)/库名) dsn := "root:888888@tcp(127.0.0.1:3306)/mydb" db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) if err != nil { fmt.Println(err) return } //fmt.Println(db) //查询 //实例化切片 var userList []User db.Find(&userList) fmt.Println(userList)}[{1 wangwu 19} {2 lisi 20} {3 zhangsan 18} {4 fengfeng 23} {5 fangfang 18} {6 fengfengzhidao 25} {7 feifei12138 28} {8 lier 29}]单表模型
用一个 Go 结构体(struct)来对应数据库中的一张表。结构体的字段对应表的列
表结构
在gorm中,使用结构体表示一张表
例如User表
通常情况下,我们会使用Model结尾表示它是表的结构体
type UserModel struct { ID int64 `gorm:"primaryKey"` // 主键 Name string `gorm:"not null;unique"` // 不能为空,且唯一 CreatedAt time.Time // 在创建记录时自动设置为当前时间}标签参考这个 https://gorm.io/zh_CN/docs/models.html#字段标签
为了方便可以建一个全局变量
package global
import ( "fmt"
"gorm.io/driver/mysql" "gorm.io/gorm")
var DB *gorm.DBfunc Connect() { dsn := "root:888888@tcp(127.0.0.1:3306)/mydb" db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) if err != nil { fmt.Println(err) return } DB=db}自动生成表
让 GORM 根据结构体的定义,自动在数据库里创建或更新表结构
生成表结构只会新增字段,不会删除字段和更新字段
package main
import ( "fmt" "gorm_study/global" "time")
type UserModel struct { ID int //一般不写就是默认主键 Usernamme string `gorm:"not null;unique"` Age int `gorm:"default:18"` CreatedAt time.Time}
func migrate() { fmt.Println(global.DB) //表迁移 err := global.DB.AutoMigrate(&UserModel{}) if err != nil { fmt.Println("表结构迁移失败:", err) return } fmt.Println("表结构迁移成功")}func main() { global.Connect() migrate()}单表操作
插入数据
为了方便可以单独创建 models 下一个 user_model
package models
import "time"
type UserModel struct { ID int //一般不写就是默认主键 Usernamme string `gorm:"not null;unique"` Age int `gorm:"default:18"` CreatedAt time.Time}package main
import ( "fmt" "gorm_study/global" "gorm_study/models")
func main() { global.Connect() //插入数据(一次插入) err := global.DB.Create(&models.UserModel{ Usernamme: "张三", Age: 25, }).Error if err != nil { fmt.Println(err) }}回填式创建
//回填式插入 user := models.UserModel{ Usernamme: "lisi", Age: 25, } err := global.DB.Create(&user).Error if err != nil { fmt.Println(err) } fmt.Println(user.ID, user.CreatedAt, user.Usernamme)添加多个
var userList = []models.UserModel{ {Usernamme: "李四"}, {Usernamme: "wangwu"}, } err := global.DB.Create(&userList).Error if err != nil { fmt.Println(err) }特别注意:Create函数接收的参数是结构体的指针或者是切片
插入数据的钩子
package models
import ( "errors" "fmt" "time"
"gorm.io/gorm")
type UserModel struct { ID int //一般不写就是默认主键 Usernamme string `gorm:"not null;unique"` Age int `gorm:"default:18"` CreatedAt time.Time}
// 钩子函数func (u *UserModel) BeforeCreate(*gorm.DB) error { fmt.Println("创建钩子") return errors.New("xxxx")}查询数据
func query() { var userList []models.UserModel //查全部 global.DB.Find(&userList) fmt.Println(userList)}注意此时会报错,连接数据库需要加参数
dsn := "root:888888@tcp(127.0.0.1:3306)/mydb?parseTime=true&loc=Local"// 查全部var users []UserModelDB.Find(&users)fmt.Println(users)
// 带条件查询users = []UserModel{}DB.Find(&users, "name = ?", "张三")fmt.Println(users)
// 获取一条记录var user UserModelDB.Take(&user)fmt.Println(user)
// 如果查不到则会报错user = UserModel{}err := DB.Take(&user, "id = ?", 100).Errorif err == gorm.ErrRecordNotFound { fmt.Println("不存在的记录")}
// 如果不想出现错误user = UserModel{}err = DB.Limit(1).Find(&user, "id = ?", 100).Errorfmt.Println(err)
// 打印实际的sqlDB.Debug().Take(&user, "id = ?", 1)更新
有很多方法,Save、Update、UpdateColumn、Updates
不同的方法有不同的区别,如下:
- Save,有主键记录就是更新,并且可以更新零值,否则就是创建
- Update,可以更新零值,必须要有条件
- UpdateColumn,可以更新零值,不会走更新的Hook
- Updates,如果是结构体,则更新非零值,map可以更新零值
save
func updateSave() { var user models.UserModel //user.ID = 3 user.CreatedAt = time.Now() user.Usernamme = "miaomiao2" global.DB.Save(&user) fmt.Println(user)}update
func update() { var user = models.UserModel{ID: 1} global.DB.Model(&user).Update("usernamme", "zhangsan") fmt.Println(user)}更新的钩子
func (u *UserModel) BeforeUpdate(tx *gorm.DB) (err error) { fmt.Println("更新的钩子函数") return nil}Updates
func updates() { var user = models.UserModel{ID: 1} //global.DB.Model(&user).Updates(models.UserModel{ // Usernamme: "张三", // Age: 18, //}) global.DB.Model(&user).Updates(map[string]any{ "Usernamme": "张三", "Age": 0, }) fmt.Println(user)}Expr
通常用于获取原字段的数据
例如年龄加一
global.DB.Model(&user).Update("age", gorm.Expr("age+?", 1))删除
var user = UserModel{ID: 10}DB.Delete(&user)
DB.Delete(&UserModel{}, 9)
// 批量删除DB.Delete(&UserModel{}, []int{1, 2, 3})func (u *UserModel) BeforeDelete(tx *gorm.DB) (err error) { fmt.Println("删除钩子") return}软删除
如果你的模型包含了 gorm.DeletedAt字段(该字段也被包含在gorm.Model中),那么该模型将会自动获得软删除的能力
当调用Delete时,GORM并不会从数据库中删除该记录,而是将该记录的DeleteAt设置为当前时间,而后的一般查询方法将无法查找到此条记录。
type UserModel struct { ID int //一般不写就是默认主键 Usernamme string `gorm:"not null;unique"` Age int `gorm:"default:18"` CreatedAt time.Time DeletedAt gorm.DeletedAt}新增加了列要迁移
func Migrate() { err := DB.AutoMigrate(&models.UserModel{}) if err != nil { log.Fatalf("数据库迁移失败: %s", err) } fmt.Println("数据库迁移成功")
}查找被删除的记录
var user models.UserModel global.DB.Unscoped().Take(&user, 3) fmt.Println(user)永久删除
global.DB.Unscoped().Delete(&user)


