Go的ORM框架的使用

Written by

in

文章目录
  • 全功能 ORM 关联 (Has One,Has Many,Belongs To,Many To Many,多态,单表继承) Create,Save,Update,Delete,Find 中钩子方法 支持 Preload、Joins 的预加载 事务,嵌套事务,Save Point,Rollback To Saved Point Context、预编译模式、DryRun 模式 批量插入,FindInBatches,Find/Create with Map,使用 SQL 表达式、Context Valuer 进行 CRUD SQL 构建器,Upsert,数据库锁,Optimizer/Index/Comment Hint,命名参数,子查询 复合主键,索引,约束 Auto Migration 自定义 Logger Generics API for type-safe queries and operations Extendable, flexible plugin API: Database Resolver (multiple databases, read/write splitting) / Prometheus… 每个特性都经过了测试的重重考验 开发者友好
  • go get -u gorm.io/gorm go get -u gorm.io/driver/sqlite
  • 基础的增删改查 package main import ( “context” “gorm.io/driver/sqlite” “gorm.io/gorm” ) type Product struct { gorm.Model Code string Price uint } func main() { db, err := gorm.Open(sqlite.Open(“test.db”), &gorm.Config{}) if err != nil { panic(“failed to connect database”) } ctx := context.Background() // Migrate the schema db.AutoMigrate(&Product{}) // Create err = gorm.G[Product](db).Create(ctx, &Product{Code: “D42”, Price: 100}) // Read product, err := gorm.G[Product](db).Where(“id = ?”, 1).First(ctx) // find product with integer primary key products, err := gorm.G[Product](db).Where(“code = ?”, “D42”).Find(ctx) // find product with code D42 // Update – update product’s price to 200 err = gorm.G[Product](db).Where(“id = ?”, product.ID).Update(ctx, “Price”, 200) // Update – update multiple fields err = gorm.G[Product](db).Where(“id = ?”, product.ID).Updates(ctx, map[string]interface{}{“Price”: 200, “Code”: “F42”}) // Delete – delete product err = gorm.G[Product](db).Where(“id = ?”, product.ID).Delete(ctx) }
  • GORM 通过将 Go 结构体(Go structs)可以理解为Java里的Do层映射到数据库表来简化数据库交互。 了解如何在GORM中定义模型,是充分利用GORM全部功能的基础。 模型是使用普通结构体定义的。 这些结构体可以包含具有基本Go类型、指针或这些类型的别名,甚至是自定义类型(只需要实现 database/sql 包中的Scanner和Valuer接口)。 type User struct { ID uint // 标准字段,用作主键 Name string // 普通字符串字段 Email *string // 指向字符串的指针,允许为空(NULL) Age uint8 // 无符号8位整数 Birthday *time.Time // 指向时间的指针,可以为空(NULL) MemberNumber sql.NullString // 使用 sql.NullString 来处理可为空的字符串 ActivatedAt sql.NullTime // 使用 sql.NullTime 来处理可为空的时间字段 CreatedAt time.Time // GORM 自动管理的创建时间 UpdatedAt time.Time // GORM 自动管理的更新时间 ignored string // 未导出的字段会被 GORM 忽略 } 在此模型中: 具体数字类型如 uint、string和 uint8 直接使用。 指向 *string 和 *time.Time 类型的指针表示可空字段。 来自 database/sql 包的 sql.NullString 和 sql.NullTime 用于具有更多控制的可空字段。 CreatedAt 和 UpdatedAt 是特殊字段,当记录被创建或更新时,GORM 会自动向内填充当前时间。 Non-exported fields (starting with a small letter) are not mapped
  • 主键:GORM 使用一个名为ID 的字段作为每个模型的默认主键。 表名:默认情况下,GORM 将结构体名称转换为 snake_case 并为表名加上复数形式。 例如,一个 User 结构体在数据库中对应的表名会变成 users,而 GormUserName 则会变成 gorm_user_names。 列名:GORM 自动将结构体字段名称转换为 snake_case 作为数据库中的列名。 时间戳字段:GORM使用字段 CreatedAt 和 UpdatedAt 来自动跟踪记录的创建和更新时间。遵循这些约定可以大大减少您需要编写的配置或代码量。 但是,GORM也具有灵活性,允许根据自己的需求自定义这些设置。
  • 最基础的用法 import ( “gorm.io/driver/mysql” “gorm.io/gorm” ) func main() { // 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情 dsn := “user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local” db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) }
  • package main import ( “fmt” “time” “gorm.io/driver/mysql” “gorm.io/gorm” “gorm.io/gorm/clause” ) // 定义符合 GORM 约定的 User 模型(嵌入 gorm.Model) type User struct { gorm.Model // 自动包含 ID, CreatedAt, UpdatedAt, DeletedAt Name string `gorm:”size:255″` // 可指定字段长度 Email *string `gorm:”unique”` // 唯一索引 Age uint8 `gorm:”default:18″` // 默认值 Birthday *time.Time // 指向时间的指针 MemberNumber sql.NullString // 处理可为空的字符串 ActivatedAt sql.NullTime // 处理可为空的时间字段 ignored string // 未导出字段会被 GORM 忽略 } func main() { // 1. 连接 MySQL 数据库 dsn := “root:root@tcp(127.0.0.1:3306)/gorm_demo?charset=utf8mb4&parseTime=True&loc=Local” db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) if err != nil { panic(“数据库连接失败: ” + err.Error()) } // 2. 自动迁移(创建表) db.AutoMigrate(&User{}) // 3. 创建操作 (Create) fmt.Println(“n=== 创建用户 ===”) user1 := User{ Name: “张三”, Email: &[]string{“zhangsan@example.com”}[0], Age: 30, Birthday: &time.Date(1990, 1, 1, 0, 0, 0, 0, time.UTC), MemberNumber: sql.NullString{String: “M12345”, Valid: true}, ActivatedAt: sql.NullTime{Time: time.Now(), Valid: true}, } if err := db.Create(&user1).Error; err != nil { panic(“创建用户失败: ” + err.Error()) } fmt.Printf(“创建成功! ID: %dn”, user1.ID) // 4. 查询操作 (Read) fmt.Println(“n=== 查询用户 ===”) var user2 User // 查询单个记录 if err := db.First(&user2, user1.ID).Error; err != nil { panic(“查询用户失败: ” + err.Error()) } fmt.Printf(“查询到用户: %s (ID: %d, 年龄: %d)n”, user2.Name, user2.ID, user2.Age) // 查询多个记录 var users []User db.Where(“age > ?”, 25).Find(&users) fmt.Printf(“年龄大于25的用户: %d 个n”, len(users)) // 使用条件查询 var user3 User db.Where(“name = ?”, “张三”).First(&user3) fmt.Printf(“条件查询: %s (ID: %d)n”, user3.Name, user3.ID) // 5. 更新操作 (Update) fmt.Println(“n=== 更新用户 ===”) user2.Age = 31 if err := db.Save(&user2).Error; err != nil { panic(“更新用户失败: ” + err.Error()) } fmt.Printf(“更新成功! 年龄: %dn”, user2.Age) // 更新特定字段 db.Model(&user2).Update(“age”, 32) fmt.Printf(“更新特定字段: 年龄: %dn”, user2.Age) // 6. 删除操作 (Delete) fmt.Println(“n=== 删除用户 ===”) // 软删除(默认) if err := db.Delete(&user2).Error; err != nil { panic(“软删除失败: ” + err.Error()) } fmt.Printf(“软删除成功! ID: %dn”, user2.ID) // 硬删除(需要设置 DeleteMode 为 HardDelete) if err := db.Unscoped().Delete(&user2).Error; err != nil { panic(“硬删除失败: ” + err.Error()) } fmt.Printf(“硬删除成功! ID: %dn”, user2.ID) // 7. 其他常用操作 fmt.Println(“n=== 其他常用操作 ===”) // 创建或更新(如果存在则更新,不存在则创建) user4 := User{Name: “李四”, Age: 25} db.FirstOrCreate(&user4, User{Name: “李四”}) fmt.Printf(“创建或更新: %s (ID: %d)n”, user4.Name, user4.ID) // 通过 ID 查询 var user5 User db.First(&user5, 1) // 通过 ID 查询 fmt.Printf(“通过 ID 查询: %sn”, user5.Name) // 分页查询 var usersPage []User db.Limit(2).Offset(0).Find(&usersPage) fmt.Printf(“分页查询: %d 个用户n”, len(usersPage)) // 计数 var count int64 db.Model(&User{}).Where(“age > ?”, 25).Count(&count) fmt.Printf(“年龄大于25的用户总数: %dn”, count) } 在使用 GORM 的 AutoMigrate 功能时,无需手动创建数据库表,只需定义好 Go 结构体(模型),然后调用 AutoMigrate 方法,GORM 会自动根据结构体定义创建数据库表。 方式2: package main import ( “fmt” “time” “gorm.io/driver/mysql” “gorm.io/gorm” “gorm.io/gorm/clause” ) // 自定义表名模型(演示如何指定表名) type EntityRobot struct { ID uint `gorm:”primary_key”` EntityID uint `gorm:”index:idx_entity_biz”` BizType string `gorm:”size:50;index:idx_entity_biz”` Params map[string]interface{} `gorm:”type:json”` // 使用JSON存储参数 CreatedAt time.Time UpdatedAt time.Time } // 实现TableName方法指定表名 func (EntityRobot) TableName() string { return “entity_robot” // 自定义表名,与数据库表名一致 } func main() { // 1. 数据库连接 dsn := “root:root@tcp(127.0.0.1:3306)/gorm_demo?charset=utf8mb4&parseTime=True&loc=Local” db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) if err != nil { panic(“数据库连接失败: ” + err.Error()) } // 2. 自动迁移(创建表) db.AutoMigrate(&EntityRobot{}) // 3. 创建测试数据 robot := EntityRobot{ EntityID: 1001, BizType: “user_profile”, Params: map[string]interface{}{“name”: “张三”, “age”: 30}, } db.Create(&robot) // 4. 演示您的示例:指定表名 + 条件更新 entityId := uint(1001) bizType := “user_profile” params := map[string]interface{}{ “params”: map[string]interface{}{“name”: “李四”, “age”: 32}, } // 使用 Table() 指定表名 + Where 条件 + Update result := db.Table(“entity_robot”). Where(“entity_id = ? AND biz_type = ?”, entityId, bizType). Updates(params) // 检查更新结果 fmt.Printf(“更新影响行数: %dn”, result.RowsAffected) if result.Error != nil { panic(“更新失败: ” + result.Error.Error()) } // 5. 验证更新结果 var updatedRobot EntityRobot db.Where(“entity_id = ? AND biz_type = ?”, entityId, bizType).First(&updatedRobot) fmt.Printf(“更新后参数: %+vn”, updatedRobot.Params) // 6. 其他常用操作演示 // 6.1 创建(带JSON参数) newRobot := EntityRobot{ EntityID: 1002, BizType: “order”, Params: map[string]interface{}{“order_id”: “ORD1001”, “amount”: 199.9}, } db.Create(&newRobot) // 6.2 查询(带条件) var robots []EntityRobot db.Where(“biz_type = ?”, “order”).Find(&robots) fmt.Printf(“查询到 %d 个订单记录n”, len(robots)) // 6.3 软删除(默认) db.Delete(&newRobot) // 6.4 硬删除(需要使用 Unscoped) db.Unscoped().Delete(&newRobot) // 6.5 批量更新(更新多个记录) db.Table(“entity_robot”). Where(“biz_type = ?”, “user_profile”). Updates(map[string]interface{}{ “params”: map[string]interface{}{“status”: “active”}, }) // 6.6 原生SQL查询 var rawResult []struct { EntityID uint BizType string } db.Raw(“SELECT entity_id, biz_type FROM entity_robot WHERE params->>’$.age’ > ?”, 30).Scan(&rawResult) fmt.Printf(“查询到 %d 条年龄>30的记录n”, len(rawResult)) } 这种方式也是我们项目中常用的一个操作 到此这篇关于Go的ORM框架的使用的文章就介绍到这了,更多相关Go ORM框架内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客! 您可能感兴趣的文章: golang gorm 操作mysql及gorm基本用法 Go语言中使用gorm小结 golang gorm中格式化时间问题详解 golang gorm多条件筛选查询操作 Django ORM 查询表中某列字段值的方法 Go基于GORM 获取当前请求所执行的 SQL 信息(思路详解)
  • 目录
    • 特性
    • 安装
    • 快速入门
    • 模型的定义
    • 约定
      • 示例
      • 自定义约定示例
      • gorm.Model
      • 字段级权限控制
    • 连接数据库
      • CRUD

        • 全功能 ORM
        • 关联 (Has One,Has Many,Belongs To,Many To Many,多态,单表继承)
        • Create,Save,Update,Delete,Find 中钩子方法
        • 支持 Preload、Joins 的预加载
        • 事务,嵌套事务,Save Point,Rollback To Saved Point
        • Context、预编译模式、DryRun 模式
        • 批量插入,FindInBatches,Find/Create with Map,使用 SQL 表达式、Context Valuer 进行 CRUD
        • SQL 构建器,Upsert,数据库锁,Optimizer/Index/Comment Hint,命名参数,子查询
        • 复合主键,索引,约束
        • Auto Migration
        • 自定义 Logger
        • Generics API for type-safe queries and operations
        • Extendable, flexible plugin API: Database Resolver (multiple databases, read/write splitting) / Prometheus…
        • 每个特性都经过了测试的重重考验
        • 开发者友好

        go get -u gorm.io/gorm
        go get -u gorm.io/driver/sqlite
        

        基础的增删改查

        package main
        
        import (
          "context"
          "gorm.io/driver/sqlite"
          "gorm.io/gorm"
        )
        
        type Product struct {
          gorm.Model
          Code  string
          Price uint
        }
        
        func main() {
          db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
          if err != nil {
            panic("failed to connect database")
          }
        
          ctx := context.Background()
        
          // Migrate the schema
          db.AutoMigrate(&Product{})
        
          // Create
          err = gorm.G[Product](db).Create(ctx, &Product{Code: "D42", Price: 100})
        
          // Read
          product, err := gorm.G[Product](db).Where("id = ?", 1).First(ctx) // find product with integer primary key
          products, err := gorm.G[Product](db).Where("code = ?", "D42").Find(ctx) // find product with code D42
        
          // Update - update product's price to 200
          err = gorm.G[Product](db).Where("id = ?", product.ID).Update(ctx, "Price", 200)
          // Update - update multiple fields
          err = gorm.G[Product](db).Where("id = ?", product.ID).Updates(ctx, map[string]interface{}{"Price": 200, "Code": "F42"})
        
          // Delete - delete product
          err = gorm.G[Product](db).Where("id = ?", product.ID).Delete(ctx)
        }
        

        GORM 通过将 Go 结构体(Go structs)可以理解为Java里的Do层映射到数据库表来简化数据库交互。 了解如何在GORM中定义模型,是充分利用GORM全部功能的基础。

        模型是使用普通结构体定义的。 这些结构体可以包含具有基本Go类型、指针或这些类型的别名,甚至是自定义类型(只需要实现 database/sql 包中的Scanner和Valuer接口)。

        type User struct {
            ID           uint           // 标准字段,用作主键
            Name         string         // 普通字符串字段
            Email        *string        // 指向字符串的指针,允许为空(NULL)
            Age          uint8          // 无符号8位整数
            Birthday     *time.Time     // 指向时间的指针,可以为空(NULL)
            MemberNumber sql.NullString // 使用 sql.NullString 来处理可为空的字符串
            ActivatedAt  sql.NullTime   // 使用 sql.NullTime 来处理可为空的时间字段
            CreatedAt    time.Time      // GORM 自动管理的创建时间
            UpdatedAt    time.Time      // GORM 自动管理的更新时间
            ignored      string         // 未导出的字段会被 GORM 忽略
        }
        

        在此模型中:

        • 具体数字类型如 uint、string和 uint8 直接使用。
        • 指向 *string 和 *time.Time 类型的指针表示可空字段。
        • 来自 database/sql 包的 sql.NullString 和 sql.NullTime 用于具有更多控制的可空字段。
        • CreatedAt 和 UpdatedAt 是特殊字段,当记录被创建或更新时,GORM 会自动向内填充当前时间。
        • Non-exported fields (starting with a small letter) are not mapped

        1. 主键:GORM 使用一个名为ID 的字段作为每个模型的默认主键。
        2. 表名:默认情况下,GORM 将结构体名称转换为 snake_case 并为表名加上复数形式。

        例如,一个 User 结构体在数据库中对应的表名会变成 users,而 GormUserName 则会变成 gorm_user_names。

        1. 列名:GORM 自动将结构体字段名称转换为 snake_case 作为数据库中的列名。
        2. 时间戳字段:GORM使用字段 CreatedAt 和 UpdatedAt 来自动跟踪记录的创建和更新时间。
          遵循这些约定可以大大减少您需要编写的配置或代码量。 但是,GORM也具有灵活性,允许根据自己的需求自定义这些设置。

        1. 列名转换
        结构体字段 数据库列名 说明
        ID id 默认主键
        Name name 转换为 snake_case
        Email email 转换为 snake_case
        Age age 转换为 snake_case
        CreatedAt created_at 时间戳字段
        UpdatedAt updated_at 时间戳字段
        1. 表名转换
        结构体名称 数据库表名 说明
        User users 结构体名转 snake_case + 复数
        GormUserName gorm_user_names 结构体名转 snake_case + 复数
        Product products 结构体名转 snake_case + 复数
        OrderItem order_items 结构体名转 snake_case + 复数

        如果需要自定义表名,可以实现TableName方法:

        func (User) TableName() string {
            return "user_profiles" // 自定义表名
        }
        

        或者通过配置全局修改:

        db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{
            NamingStrategy: schema.NamingStrategy{
                TablePrefix:     "tbl_", // 表名前缀
                SingularTable:   true,   // 使用单数表名
                NoLowerCase:     false,  // 使用小写
                NameReplacer:    strings.NewReplacer("ID", "Id"), // 替换特定名称
            },
        })
        

        GORM提供了一个预定义的结构体,名为gorm.Model,其中包含常用字段:

        // gorm.Model 的定义
        type Model struct {
          ID        uint           `gorm:"primaryKey"`
          CreatedAt time.Time
          UpdatedAt time.Time
          DeletedAt gorm.DeletedAt `gorm:"index"`
        }
        
        • ID :每个记录的唯一标识符(主键)。
        • CreatedAt :在创建记录时自动设置为当前时间。
        • UpdatedAt:每当记录更新时,自动更新为当前时间。
        • DeletedAt:用于软删除(将记录标记为已删除,而实际上并未从数据库中删除)。
          使用方式如下:
        package model
        
        import (
            "database/sql"
            "time"
        
            "gorm.io/gorm"
        )
        
        type User struct {
            gorm.Model
            ID           uint           // 标准字段,用作主键
            Name         string         // 普通字符串字段
            Email        *string        // 指向字符串的指针,允许为空(NULL)
            Age          uint8          // 无符号8位整数
            Birthday     *time.Time     // 指向时间的指针,可以为空(NULL)
            MemberNumber sql.NullString // 使用 sql.NullString 来处理可为空的字符串
            ActivatedAt  sql.NullTime   // 使用 sql.NullTime 来处理可为空的时间字段
            ignored      string         // 未导出的字段会被 GORM 忽略
        }
        

        可导出的字段在使用 GORM 进行 CRUD 时拥有全部的权限,此外,GORM 允许您用标签控制字段级别的权限。这样您就可以让一个字段的权限是只读、只写、只创建、只更新或者被忽略

        type User struct {
          Name string `gorm:"<-:create"` // 允许读和创建
          Name string `gorm:"<-:update"` // 允许读和更新
          Name string `gorm:"<-"`        // 允许读和写(创建和更新)
          Name string `gorm:"<-:false"`  // 允许读,禁止写
          Name string `gorm:"->"`        // 只读(除非有自定义配置,否则禁止写)
          Name string `gorm:"->;<-:create"` // 允许读和写
          Name string `gorm:"->:false;<-:create"` // 仅创建(禁止从 db 读)
          Name string `gorm:"-"`  // 通过 struct 读写会忽略该字段
          Name string `gorm:"-:all"`        // 通过 struct 读写、迁移会忽略该字段
          Name string `gorm:"-:migration"`  // 通过 struct 迁移会忽略该字段
        }
        

        嵌入结构体

        1. 方式1:直接嵌入
        type Author struct {
          Name  string
          Email string
        }
        
        type Blog struct {
          Author
          ID      int
          Upvotes int32
        }
        // equals
        type Blog struct {
          ID      int64
          Name    string
          Email   string
          Upvotes int32
        }
        
        1. 通过标签 embedded嵌入
        type Author struct {
            Name  string
            Email string
        }
        
        type Blog struct {
          ID      int
          Author  Author `gorm:"embedded"`
          Upvotes int32
        }
        // 等效于
        type Blog struct {
          ID    int64
          Name  string
          Email string
          Upvotes  int32
        }
        
        1. 使用标签 embeddedPrefix 来为 db 中的字段名添加前缀
        type Blog struct {
          ID      int
          Author  Author `gorm:"embedded;embeddedPrefix:author_"`
          Upvotes int32
        }
        // 等效于
        type Blog struct {
          ID          int64
          AuthorName string
          AuthorEmail string
          Upvotes     int32
        }
        

        声明模型时,标签是可选的,GORM支持以下标签:标签不区分大小写,但建议使用驼峰式命名法(camelCase)。如果使用多个标签,则应使用分号(;)分隔。对于解析器具有特殊含义的字符可以使用反斜杠(1)进行转义,以便将其用作参数值。

        标签名 说明
        column 指定 db 列名
        type 列数据类型,推荐使用兼容性好的通用类型,例如:所有数据库都支持 bool、int、uint、float、string、time、bytes,并且可以和其他标签一起使用,例如:not null、size、autoIncrement … 像 varbinary(8) 这样指定数据库数据类型也是支持的。在使用指定数据库数据类型时,它需要是完整的数据库数据类型,如:MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT
        serializer 指定将数据序列化或反序列化到数据库中的序列化器,例如:serializer:json/gob/unixtime
        size 定义列数据类型的大小或长度,例如:size: 256
        primaryKey 将列定义为主键
        unique 将列定义为唯一键
        default 定义列的默认值
        precision 指定列的精度
        scale 指定列大小
        not null 指定列为 NOT NULL
        autoIncrement 指定列为自动增长
        autoIncrementIncrement 自动步长,控制连续记录之间的间隔
        embedded 嵌套字段
        embeddedPrefix 嵌入字段的列名前缀
        autoCreateTime 创建时追踪当前时间,对于 int 字段,它会追踪时间戳秒数,您可以使用 nano / milli 来追踪纳秒、毫秒时间戳,例如:autoCreateTime:nano
        autoUpdateTime 创建/更新时追踪当前时间,对于 int 字段,它会追踪时间戳秒数,您可以使用 nano / milli 来追踪纳秒、毫秒时间戳,例如:autoUpdateTime:milli
        index 根据参数创建索引,多个字段使用相同的名称则创建复合索引,查看 索引 获取详情
        uniqueIndex 与 index 相同,但创建的是唯一索引
        check 创建检查约束,例如 check:age > 13,查看 约束 获取详情
        <- 设置字段写入的权限,<-:create 只创建、<-:update 只更新、<-:false 无写入权限、<- 创建和更新权限
        -> 设置字段读的权限,->:false 无读权限
        忽略该字段,- 表示无读写,-:migration 表示无迁移权限,-:all 表示无读写迁移权限
        comment 迁移时为字段添加注释

        最基础的用法

        import (
          "gorm.io/driver/mysql"
          "gorm.io/gorm"
        )
        
        func main() {
          // 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情
          dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
          db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
        }
        

        package main
        
        import (
                "fmt"
                "time"
        
                "gorm.io/driver/mysql"
                "gorm.io/gorm"
                "gorm.io/gorm/clause"
        )
        
        // 定义符合 GORM 约定的 User 模型(嵌入 gorm.Model)
        type User struct {
                gorm.Model // 自动包含 ID, CreatedAt, UpdatedAt, DeletedAt
        
                Name         string         `gorm:"size:255"` // 可指定字段长度
                Email        *string        `gorm:"unique"`   // 唯一索引
                Age          uint8          `gorm:"default:18"` // 默认值
                Birthday     *time.Time     // 指向时间的指针
                MemberNumber sql.NullString // 处理可为空的字符串
                ActivatedAt  sql.NullTime   // 处理可为空的时间字段
                ignored      string         // 未导出字段会被 GORM 忽略
        }
        
        func main() {
                // 1. 连接 MySQL 数据库
                dsn := "root:root@tcp(127.0.0.1:3306)/gorm_demo?charset=utf8mb4&parseTime=True&loc=Local"
                db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
                if err != nil {
                        panic("数据库连接失败: " + err.Error())
                }
        
                // 2. 自动迁移(创建表)
                db.AutoMigrate(&User{})
        
                // 3. 创建操作 (Create)
                fmt.Println("n=== 创建用户 ===")
                user1 := User{
                        Name:      "张三",
                        Email:     &[]string{"zhangsan@example.com"}[0],
                        Age:       30,
                        Birthday:  &time.Date(1990, 1, 1, 0, 0, 0, 0, time.UTC),
                        MemberNumber: sql.NullString{String: "M12345", Valid: true},
                        ActivatedAt:  sql.NullTime{Time: time.Now(), Valid: true},
                }
                if err := db.Create(&user1).Error; err != nil {
                        panic("创建用户失败: " + err.Error())
                }
                fmt.Printf("创建成功! ID: %dn", user1.ID)
        
                // 4. 查询操作 (Read)
                fmt.Println("n=== 查询用户 ===")
                var user2 User
                // 查询单个记录
                if err := db.First(&user2, user1.ID).Error; err != nil {
                        panic("查询用户失败: " + err.Error())
                }
                fmt.Printf("查询到用户: %s (ID: %d, 年龄: %d)n", user2.Name, user2.ID, user2.Age)
        
                // 查询多个记录
                var users []User
                db.Where("age > ?", 25).Find(&users)
                fmt.Printf("年龄大于25的用户: %d 个n", len(users))
        
                // 使用条件查询
                var user3 User
                db.Where("name = ?", "张三").First(&user3)
                fmt.Printf("条件查询: %s (ID: %d)n", user3.Name, user3.ID)
        
                // 5. 更新操作 (Update)
                fmt.Println("n=== 更新用户 ===")
                user2.Age = 31
                if err := db.Save(&user2).Error; err != nil {
                        panic("更新用户失败: " + err.Error())
                }
                fmt.Printf("更新成功! 年龄: %dn", user2.Age)
        
                // 更新特定字段
                db.Model(&user2).Update("age", 32)
                fmt.Printf("更新特定字段: 年龄: %dn", user2.Age)
        
                // 6. 删除操作 (Delete)
                fmt.Println("n=== 删除用户 ===")
                // 软删除(默认)
                if err := db.Delete(&user2).Error; err != nil {
                        panic("软删除失败: " + err.Error())
                }
                fmt.Printf("软删除成功! ID: %dn", user2.ID)
        
                // 硬删除(需要设置 DeleteMode 为 HardDelete)
                if err := db.Unscoped().Delete(&user2).Error; err != nil {
                        panic("硬删除失败: " + err.Error())
                }
                fmt.Printf("硬删除成功! ID: %dn", user2.ID)
        
                // 7. 其他常用操作
                fmt.Println("n=== 其他常用操作 ===")
                // 创建或更新(如果存在则更新,不存在则创建)
                user4 := User{Name: "李四", Age: 25}
                db.FirstOrCreate(&user4, User{Name: "李四"})
                fmt.Printf("创建或更新: %s (ID: %d)n", user4.Name, user4.ID)
        
                // 通过 ID 查询
                var user5 User
                db.First(&user5, 1) // 通过 ID 查询
                fmt.Printf("通过 ID 查询: %sn", user5.Name)
        
                // 分页查询
                var usersPage []User
                db.Limit(2).Offset(0).Find(&usersPage)
                fmt.Printf("分页查询: %d 个用户n", len(usersPage))
        
                // 计数
                var count int64
                db.Model(&User{}).Where("age > ?", 25).Count(&count)
                fmt.Printf("年龄大于25的用户总数: %dn", count)
        }
        

        在使用 GORM 的 AutoMigrate 功能时,无需手动创建数据库表,只需定义好 Go 结构体(模型),然后调用 AutoMigrate 方法,GORM 会自动根据结构体定义创建数据库表。

        方式2:

        package main
        
        import (
                "fmt"
                "time"
        
                "gorm.io/driver/mysql"
                "gorm.io/gorm"
                "gorm.io/gorm/clause"
        )
        
        // 自定义表名模型(演示如何指定表名)
        type EntityRobot struct {
                ID         uint           `gorm:"primary_key"`
                EntityID   uint           `gorm:"index:idx_entity_biz"`
                BizType    string         `gorm:"size:50;index:idx_entity_biz"`
                Params     map[string]interface{} `gorm:"type:json"` // 使用JSON存储参数
                CreatedAt  time.Time
                UpdatedAt  time.Time
        }
        
        // 实现TableName方法指定表名
        func (EntityRobot) TableName() string {
                return "entity_robot" // 自定义表名,与数据库表名一致
        }
        
        func main() {
                // 1. 数据库连接
                dsn := "root:root@tcp(127.0.0.1:3306)/gorm_demo?charset=utf8mb4&parseTime=True&loc=Local"
                db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
                if err != nil {
                        panic("数据库连接失败: " + err.Error())
                }
        
                // 2. 自动迁移(创建表)
                db.AutoMigrate(&EntityRobot{})
        
                // 3. 创建测试数据
                robot := EntityRobot{
                        EntityID: 1001,
                        BizType:  "user_profile",
                        Params:   map[string]interface{}{"name": "张三", "age": 30},
                }
                db.Create(&robot)
        
                // 4. 演示您的示例:指定表名 + 条件更新
                entityId := uint(1001)
                bizType := "user_profile"
                params := map[string]interface{}{
                        "params": map[string]interface{}{"name": "李四", "age": 32},
                }
        
                // 使用 Table() 指定表名 + Where 条件 + Update
                result := db.Table("entity_robot").
                        Where("entity_id = ? AND biz_type = ?", entityId, bizType).
                        Updates(params)
        
                // 检查更新结果
                fmt.Printf("更新影响行数: %dn", result.RowsAffected)
                if result.Error != nil {
                        panic("更新失败: " + result.Error.Error())
                }
        
                // 5. 验证更新结果
                var updatedRobot EntityRobot
                db.Where("entity_id = ? AND biz_type = ?", entityId, bizType).First(&updatedRobot)
                fmt.Printf("更新后参数: %+vn", updatedRobot.Params)
        
                // 6. 其他常用操作演示
        
                // 6.1 创建(带JSON参数)
                newRobot := EntityRobot{
                        EntityID: 1002,
                        BizType:  "order",
                        Params:   map[string]interface{}{"order_id": "ORD1001", "amount": 199.9},
                }
                db.Create(&newRobot)
        
                // 6.2 查询(带条件)
                var robots []EntityRobot
                db.Where("biz_type = ?", "order").Find(&robots)
                fmt.Printf("查询到 %d 个订单记录n", len(robots))
        
                // 6.3 软删除(默认)
                db.Delete(&newRobot)
        
                // 6.4 硬删除(需要使用 Unscoped)
                db.Unscoped().Delete(&newRobot)
        
                // 6.5 批量更新(更新多个记录)
                db.Table("entity_robot").
                        Where("biz_type = ?", "user_profile").
                        Updates(map[string]interface{}{
                                "params": map[string]interface{}{"status": "active"},
                        })
        
                // 6.6 原生SQL查询
                var rawResult []struct {
                        EntityID uint
                        BizType  string
                }
                db.Raw("SELECT entity_id, biz_type FROM entity_robot WHERE params->>'$.age' > ?", 30).Scan(&rawResult)
                fmt.Printf("查询到 %d 条年龄>30的记录n", len(rawResult))
        }
        

        这种方式也是我们项目中常用的一个操作

        到此这篇关于Go的ORM框架的使用的文章就介绍到这了,更多相关Go ORM框架内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客!

        您可能感兴趣的文章:

        • golang gorm 操作mysql及gorm基本用法
        • Go语言中使用gorm小结
        • golang gorm中格式化时间问题详解
        • golang gorm多条件筛选查询操作
        • Django ORM 查询表中某列字段值的方法
        • Go基于GORM 获取当前请求所执行的 SQL 信息(思路详解)

        站内搜索