• go的orm框架-Gorm


    官网文档

    特点

    • 全功能 ORM
    •  关联 (拥有一个,拥有多个,属于,多对多,多态,单表继承)
    •  Create,Save,Update,Delete,Find 中钩子方法
    •  支持 Preload、Joins 的预加载
    •  事务,嵌套事务,Save Point,Rollback To to Saved Point
    •  Context、预编译模式、DryRun 模式
    •  批量插入,FindInBatches,Find/Create with Map,使用 SQL 表达式、Context Valuer 进行 CRUD
    •  SQL 构建器,Upsert,锁,Optimizer/Index/Comment Hint,命名参数,子查询
    •  复合主键,索引,约束
    •  自动迁移
    •  自定义 Logger
    •  灵活的可扩展插件 API:Database Resolver(多数据库,读写分离)、Prometheus…
    •  每个特性都经过了测试的重重考验
    •  开发者友好

    约定(重点)

    主键

    GORM 使用一个名为ID每个模型的默认主键的字段。

    1. type User struct {
    2. ID string // 默认情况下,名为 `ID` 的字段会作为表的主键
    3. Name string
    4. }

    可以通过标签 primaryKey 将其它字段设为主键 

    1. // 将 `UUID` 设为主键
    2. type Animal struct {
    3. ID int64
    4. UUID string `gorm:"primaryKey"`
    5. Name string
    6. Age int64
    7. }

    表名称

    默认情况下,GORM 将结构名称转换为snake_case表名称并将其复数化。例如,一个User结构体出现users数据库中。

    您可以实现 Tabler 接口来更改默认表名,例如:

    1. type Tabler interface {
    2. TableName() string
    3. }
    4. // TableName 会将 User 的表名重写为 `profiles`
    5. func (User) TableName() string {
    6. return "profiles"
    7. }

    注意: TableName 不支持动态变化,它会被缓存下来以便后续使用。想要使用动态表名,你可以使用 Scopes,例如: 

    1. func UserTable(user User) func (tx *gorm.DB) *gorm.DB {
    2. return func (tx *gorm.DB) *gorm.DB {
    3. if user.Admin {
    4. return tx.Table("admin_users")
    5. }
    6. return tx.Table("users")
    7. }
    8. }
    9. db.Scopes(UserTable(user)).Create(&user)

    临时指定表名

    您可以使用 Table 方法临时指定表名,例如:

    1. // 根据 User 的字段创建 `deleted_users` 表
    2. db.Table("deleted_users").AutoMigrate(&User{})
    3. // 从另一张表查询数据
    4. var deletedUsers []User
    5. db.Table("deleted_users").Find(&deletedUsers)
    6. // SELECT * FROM deleted_users;
    7. db.Table("deleted_users").Where("name = ?", "jinzhu").Delete(&User{})
    8. // DELETE FROM deleted_users WHERE name = 'jinzhu';

    列名

    GORM 自动将结构体字段名转换为snake_case数据库中的列名。

    1. type User struct {
    2. ID uint // 列名是 `id`
    3. Name string // 列名是 `name`
    4. Birthday time.Time // 列名是 `birthday`
    5. CreatedAt time.Time // 列名是 `created_at`
    6. }

    您可以使用 column 标签或 命名策略 来覆盖列名 

    1. type Animal struct {
    2. AnimalID int64 `gorm:"column:beast_id"` // 将列名设为 `beast_id`
    3. Birthday time.Time `gorm:"column:day_of_the_beast"` // 将列名设为 `day_of_the_beast`
    4. Age int64 `gorm:"column:age_of_the_beast"` // 将列名设为 `age_of_the_beast`
    5. }

     你可以通过将 autoCreateTime 标签置为 false 来禁用时间戳追踪,例如:

    1. type User struct {
    2. CreatedAt time.Time `gorm:"autoCreateTime:false"`
    3. }

     

    时间戳字段

    GORM 使用名为CreatedAt和的字段UpdatedAt来自动跟踪记录的创建和更新时间。

    对于有 CreatedAt 字段的模型,创建记录时,如果该字段值为零值,则将该字段的值设为当前时间

    1. db.Create(&user) // 将 `CreatedAt` 设为当前时间
    2. user2 := User{Name: "jinzhu", CreatedAt: time.Now()}
    3. db.Create(&user2) // user2 的 `CreatedAt` 不会被修改
    4. // 想要修改该值,您可以使用 `Update`
    5. db.Model(&user).Update("CreatedAt", time.Now())

     对于有 UpdatedAt 字段的模型,更新记录时,将该字段的值设为当前时间。创建记录时,如果该字段值为零值,则将该字段的值设为当前时间

    1. db.Save(&user) // 将 `UpdatedAt` 设为当前时间
    2. db.Model(&user).Update("name", "jinzhu") // 会将 `UpdatedAt` 设为当前时间
    3. db.Model(&user).UpdateColumn("name", "jinzhu") // `UpdatedAt` 不会被修改
    4. user2 := User{Name: "jinzhu", UpdatedAt: time.Now()}
    5. db.Create(&user2) // 创建记录时,user2 的 `UpdatedAt` 不会被修改
    6. user3 := User{Name: "jinzhu", UpdatedAt: time.Now()}
    7. db.Save(&user3) // 更新时,user3 的 `UpdatedAt` 会修改为当前时间

     你可以通过将 autoUpdateTime 标签置为 false 来禁用时间戳追踪,例如:

    1. type User struct {
    2. UpdatedAt time.Time `gorm:"autoUpdateTime:false"`
    3. }

    安装

    要在有mod文件的文件夹下面执行下面的命令

    go get -u gorm.io/gorm

    连接到数据库(mysql)

    安装mysql驱动

    go get -u gorm.io/driver/mysql

     

    编写测试连接 

    基础版

    1. package main
    2. import (
    3. "fmt"
    4. "gorm.io/driver/mysql"
    5. "gorm.io/gorm"
    6. )
    7. func main() {
    8. // 参考 root:123456@tcp(192.168.31.131:3306)/gotest
    9. dsn := "root:123456@tcp(192.168.31.131:3306)/gotest?charset=utf8mb4&parseTime=True&loc=Local"
    10. db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
    11. if err != nil {
    12. fmt.Println("连接失败")
    13. return
    14. }
    15. fmt.Println("连接成功", db)
    16. }

    高级版

     

    1. package main
    2. import (
    3. "fmt"
    4. "gorm.io/driver/mysql"
    5. "gorm.io/gorm"
    6. )
    7. func main() {
    8. // 参考 root:123456@tcp(192.168.31.131:3306)/gotest
    9. dsn := "root:123456@tcp(192.168.31.131:3306)/gotest?charset=utf8mb4&parseTime=True&loc=Local"
    10. db, err := gorm.Open(mysql.New(mysql.Config{
    11. DSN: dsn, // DSN data source name
    12. DefaultStringSize: 256, // string 类型字段的默认长度
    13. DisableDatetimePrecision: true, // 禁用 datetime 精度,MySQL 5.6 之前的数据库不支持
    14. DontSupportRenameIndex: true, // 重命名索引时采用删除并新建的方式,MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
    15. DontSupportRenameColumn: true, // 用 `change` 重命名列,MySQL 8 之前的数据库和 MariaDB 不支持重命名列
    16. SkipInitializeWithVersion: false, // 根据当前 MySQL 版本自动配置
    17. }), &gorm.Config{})
    18. if err != nil {
    19. fmt.Println("连接失败")
    20. return
    21. }
    22. fmt.Println("连接成功", db)
    23. }

     crud

    准备数据库和结构体

    1. package main
    2. import (
    3. "errors"
    4. "fmt"
    5. "gorm.io/driver/mysql"
    6. "gorm.io/gorm"
    7. )
    8. type Stu struct {
    9. Id int `gorm:"primaryKey"`
    10. Name string
    11. Age int
    12. Address string
    13. }
    14. func getDb() *gorm.DB {
    15. dsn := "root:123456@tcp(192.168.31.131:3306)/gotest?charset=utf8mb4&parseTime=True&loc=Local"
    16. db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
    17. if err != nil {
    18. fmt.Println("连接失败")
    19. panic(errors.New("连接失败"))
    20. }
    21. fmt.Println("连接成功", db)
    22. return db
    23. }

    注意结构体中的属性首字母要大写,否则就不可见,还要指定主键 

    查询

    需要带条件的可以自己查看api

    查询一个

    first
     获取第一条记录(主键升序)
    
    1. func main() {
    2. db := getDb()
    3. testFirst(db)
    4. }
    5. func testFirst(db *gorm.DB) {
    6. var stu Stu
    7. res := db.Table("stu").First(&stu)
    8. if res.Error != nil {
    9. fmt.Println("查询数据失败")
    10. return
    11. }
    12. fmt.Println(stu)
    13. }

    Take
    获取一条记录,没有指定排序字段
    1. func testTake(db *gorm.DB) {
    2. var stu Stu
    3. res := db.Table("stu").Take(&stu)
    4. if res.Error != nil {
    5. fmt.Println("查询数据失败")
    6. return
    7. }
    8. fmt.Println(stu)
    9. }
    Last
    获取最后一条记录(主键降序)
    1. func testLast(db *gorm.DB) {
    2. var stu Stu
    3. res := db.Table("stu").Last(&stu)
    4. if res.Error != nil {
    5. fmt.Println("查询数据失败")
    6. return
    7. }
    8. fmt.Println(stu)
    9. }

    批量查询

    1. func testMany(db *gorm.DB) {
    2. var stus = make([]Stu, 0)
    3. //相当于条件是id为10
    4. _ = db.Table("stu").Find(&stus)
    5. fmt.Println(stus)
    6. }

    新增

    如果表不存在,会创建表

    新增一个

    1. func testAddOne(db *gorm.DB) {
    2. stu := Stu{Name: "新增名称", Age: 11, Address: "新增地址"}
    3. tx := db.Table("stu").Create(&stu)
    4. if tx.Error != nil {
    5. fmt.Println("新增失败")
    6. return
    7. }
    8. fmt.Println(stu.Id)
    9. }

    批量新增

    1. func testAddMany(db *gorm.DB) {
    2. stus := []Stu{{Name: "批量新增名称1", Age: 11, Address: "批量新增地址1"}, {Name: "批量新增名称2", Age: 11, Address: "批量新增地址2"}}
    3. tx := db.Table("stu").Create(&stus)
    4. if tx.Error != nil {
    5. fmt.Println("新增失败")
    6. return
    7. }
    8. fmt.Println(stus)
    9. }

    更新

    更新一个

    1. func testUpdateOne(db *gorm.DB) {
    2. var stu Stu
    3. _ = db.Table("stu").First(&stu)
    4. stu.Name = "更新后名字"
    5. db.Table("stu").Save(&stu)
    6. }
    1. func testUpdateOne1(db *gorm.DB) {
    2. db.Table("stu").Where("id=?", 72).Update("name", "更新").Update("address", "跟新地址")
    3. }

    批量更新

    1. func testUpdateMany(db *gorm.DB) {
    2. db.Table("stu").Where("id in (?)", []int{1,2,3,43}).Update("name", "更新").Update("address", "跟新地址")
    3. }

    删除

    1. func testDeleteMany(db *gorm.DB) {
    2. db.Table("stu").Where("id in (?)", []int{1, 2, 3, 43}).Delete(&Stu{})
    3. }

     

  • 相关阅读:
    vuez 与 Vue3 响应式比较
    Java 设计模式实战系列—策略模式
    【论文笔记】—低光图像增强—Supervised—URetinex-Net—2022-CVPR
    step5 lasso 回归 实战
    谈谈前端工程化
    2018 国际AIOps挑战赛单指标数据集分析
    C编译器04-生成汇编代码
    搭建vue2 工程
    coturn 在云服务器上安装配置和运行
    是时候来点现代c++了 c++11之超级重要之smart pointer详细解析
  • 原文地址:https://blog.csdn.net/qq_62408075/article/details/137268016