linux

go env -w GOPROXY=https://goproxy.cn,direct
或
export GOPROXY=https://goproxy.cn

echo "export GOPROXY=https://goproxy.cn" >> ~/.profile && source ~/.profile

下载所有依赖包
go mod tidy

 

go mod init github/caoxiaojin/gorm_class

GOPROXY=https://goproxy.cn

gorm支持hive_gorm支持hive

 https://gorm.cn/zh_CN/docs

https://learnku.com/docs/gorm/v2/update/9734

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

 一、表操作

package main

import (
    "fmt"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
    "gorm.io/gorm/schema"
    "time"
)

func main()  {
    //dns := "db1:db123456@tcp(192.168.85.128:3306)/db1?charset=utf8mb4&parseTime=True&loc=Local"
    //db,err := gorm.Open(mysql.Open(dns),&gorm.Config{})
    db,err :=gorm.Open(mysql.New(mysql.Config{
        DSN: "db1:db123456@tcp(192.168.85.128:3306)/db1?charset=utf8mb4&parseTime=True&loc=Local",
        DefaultStringSize: 171,
    }),&gorm.Config{
        SkipDefaultTransaction: false,
        NamingStrategy: schema.NamingStrategy{
            TablePrefix: "t_", //表明前缀 `User` 的表名 应该是 `t_users`
            SingularTable: false,  // 使用单数表名,启用 表示 `t_user`
        },
        DisableForeignKeyConstraintWhenMigrating: true, // 逻辑外键
    })
    type User struct {
        Name string
    }
    sqlDB,_ := db.DB()
    sqlDB.SetMaxIdleConns(10)  // 连接池最大的空闲连接数
    sqlDB.SetMaxOpenConns(100) // 连接池最多容纳的链接数量
    sqlDB.SetConnMaxLifetime(time.Hour) // 链接池中链接的最大可复用时间

    // 建表一
    _ =db.AutoMigrate(&User{})

    // 建表二
    M := db.Migrator()
    //M.CreateTable(&User{})

    // 查看表是否存在
    fmt.Println(M.HasTable(&User{}))
    fmt.Println(M.HasTable("t_users"))

    // 删除表
    //fmt.Println(M.DropTable(&User{}))

    // 重命名表
    M.RenameTable(&User{},"t_users_old")
    fmt.Println(db,err)
}

 二、常规表信息设计

package main

import (
    "database/sql"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
    "gorm.io/gorm/schema"
    "time"
)

var GLOBL_DB *gorm.DB

func main()  {
    db,_ :=gorm.Open(mysql.New(mysql.Config{
        DSN: "db1:db123456@tcp(192.168.85.128:3306)/db1?charset=utf8mb4&parseTime=True&loc=Local",
        DefaultStringSize: 171,
    }),&gorm.Config{
        SkipDefaultTransaction: false,
        NamingStrategy: schema.NamingStrategy{
            TablePrefix: "t_", //表明前缀 `User` 的表名 应该是 `t_users`
            SingularTable: false,  // 使用单数表名,启用 表示 `t_user`
        },
        DisableForeignKeyConstraintWhenMigrating: true, // 逻辑外键
    })
    sqlDB,_ := db.DB()
    sqlDB.SetMaxIdleConns(10)  // 连接池最大的空闲连接数
    sqlDB.SetMaxOpenConns(100) // 连接池最多容纳的链接数量
    sqlDB.SetConnMaxLifetime(time.Hour) // 链接池中链接的最大可复用时间
    GLOBL_DB = db
    Testusercreate()
}

func Testusercreate()  {
    GLOBL_DB.AutoMigrate(&Testuser{})
}

type Model struct {
    UUID uint `gorm:"primaryKey"`
    Time time.Time `gorm:"column:my_time"`
}

type Testuser struct {
    Model Model `gorm:"embedded;embeddedPrefix:qm_"`
    Name string `gorm:"default:qm"` // 设置默认值
    Email *string `gorm:"not null"` // 不能为空
    Age uint8 `gorm:"comment:年龄"`
    Birthday *time.Time
    ActiveAT sql.NullTime
    CreateAt time.Time
    UpdateAt time.Time
}

三、单表的 增删改查

1)增

type Testuser struct {
    gorm.Model
    Name string `gorm:"default:qm"` // 设置默认值
    Age uint8 `gorm:"comment:年龄"`
}

func ActionCreate()  {
    GLOBL_DB.Create(&Testuser{Name: "张三",Age: 18})
    GLOBL_DB.Select("Name").Create(&Testuser{Name: "里斯",Age: 19}) // 只创建 Name 字段
    GLOBL_DB.Omit("Name").Create(&Testuser{Name: "里斯",Age: 19}) // 除了 Name 字段
    GLOBL_DB.Create(&[]TestUser{
        {Name: "张三",Age: 18},
        {Name: "张三",Age: 18},
        {Name: "张三",Age: 18},
        {Name: "张三",Age: 18},
    })
}

 2)查

func ActionSelect()  {
    var result = make(map[string]interface{})
    GLOBL_DB.Model(&Testuser{}).First(&result)
    fmt.Println(result)

    var User Testuser
    GLOBL_DB.Model(&Testuser{}).First(&User)
    fmt.Println(User)

    GLOBL_DB.Model(&Testuser{}).Take(&User)
    fmt.Println(User)

    GLOBL_DB.Model(&Testuser{}).Last(&User)
    fmt.Println(User)

    // 主键检索
    dbRes := GLOBL_DB.Model(&Testuser{}).First(&User,10)
    fmt.Println(errors.Is(dbRes.Error,gorm.ErrRecordNotFound))

    // 条件查询
    GLOBL_DB.Where("name = ?","qm").First(&User)
    GLOBL_DB.Where("name = ? AND age = 21","gm").First(&User)
    GLOBL_DB.Where(map[string]interface{}{
        "name":"gm",
    }).First(&User)
    GLOBL_DB.Where("name = ?","gm").Or("age = ?",11).First(&User)
    GLOBL_DB.Where(Testuser{Name: "gm"}).First(&User)

    GLOBL_DB.First(&User,"name = ?","gm")
    GLOBL_DB.First(&User,map[string]interface{}{"name":"gm"})
    GLOBL_DB.First(&User,Testuser{Name: "gm"})

    // 查询多条数据
    var Users []Testuser
    GLOBL_DB.Find(&Users)
    GLOBL_DB.Where("name LIKE ?","%gm%").Find(&Users)
    GLOBL_DB.Select("name").Where("name LIKE ?","%gm%").Find(&Users)  // 只要name字段
    GLOBL_DB.Omit("name").Where("name LIKE ?","%gm%").Find(&Users)  // 不要name字段
    
    // 提前定义接收的字段
    var u []Userinfo
    GLOBL_DB.Model(&Testuser{}).Where("name LIKE ?","%gm%").Find(&u)
}

type Userinfo struct {
    NAME string
    Age uint8
}

 3)更新

func ActionUpdate () {
    // Update 只更新选择的字段
    // Updates 更新所有字段,此时有2种形式,一种为Map,一种为结构体,结构体零值不参与更新
    // save 无论如何都更新,所有内容包括 0 值
    GLOBL_DB.Model(&Testuser{}).Where("name LIKE ?","%gm%").Update("name","lisi")

    var users []Testuser
    dbRes := GLOBL_DB.Model(&Testuser{}).Where("name LIKE ?","%gm%").Find(&users)
    for k:= range users {
        users[k].Age = 18
    }
    dbRes.Save(&users)

    var user Testuser
    GLOBL_DB.First(&user).Updates(Testuser{Name: "",Age: 0}) // 不参与更新
    GLOBL_DB.First(&user).Updates(map[string]interface{}{"Name":"","Age":0}) // 参与更新

    // 批量更新
    GLOBL_DB.Find(&users).Updates(map[string]interface{}{"Name":"","Age":0})
}

 删除

func Actiondel()  {
    var users []Testuser
    GLOBL_DB.Where("name = ?","gm").Delete(&users) // 软删除
    GLOBL_DB.Unscoped().Where("name = ?","gm").Delete(&users) // 硬删除
}

原生sql

func ActionSql()  {
    var users []Testuser
    GLOBL_DB.Raw("SELECT * FROM users WHERE name = ?","qm").Scan(&users)
}

或查询

db.Where("name = ? OR age > ?", "Alice", 18).Find(&users)
db.Where("name = ?", "Alice").Or("age > ?", 18).Find(&users)
db.Where("name = ?", "Alice").Or(db.Where("age > ?", 18).Where("gender = ?", "female")).Find(&users)

四、关联查询之 一对一关联

1)一对一关联:

注意初始化表一张表就可以了。关联数据会被关联创建

// belongsTO
func One2one()  {
    GLOBL_DB.AutoMigrate(&Dog{})
    g:=GirlGod{
        Model:gorm.Model{
            ID: 1,
        },
        Name: "琪琪",
    }
    d := Dog{
        Model:gorm.Model{
            ID: 1,
        },
        Name: "张三",
        GirlGod: g,
    }
    GLOBL_DB.Create(&d)
}

type Dog struct {
    gorm.Model
    Name string
    GirlGodID uint
    GirlGod GirlGod
}

type GirlGod struct {
    gorm.Model
    Name string
}

1.1)关联查询。Preload

func Find()  {
    var dog Dog
    GLOBL_DB.Preload("GirlGod").Find(&dog,2)
    fmt.Println(dog)
}

type Dog struct {
    gorm.Model
    Name string
    GirlGodID uint
    GirlGod GirlGod
}

type GirlGod struct {
    gorm.Model
    Name string
}

1.2)关联操作

func One2one () {
    d:=Dog{
        Model:gorm.Model{
            ID: 1,
        },
    }
    g:=GirlGod{
        Model:gorm.Model{
            ID: 1,
        },
    }
    g2:=GirlGod{
        Model:gorm.Model{
            ID: 1,
        },
    }

    //创建关联
    GLOBL_DB.Model(&d).Association("GirlGod").Append(&g)
    //删除关联
    GLOBL_DB.Model(&d).Association("GirlGod").Delete(&g)
    //更改关联
    GLOBL_DB.Model(&d).Association("GirlGod").Replace(&g,&g2)
    // 清理所有的关系
    GLOBL_DB.Model(&d).Association("GirlGod").Clear()
}

2)一对一关联的另一种写法。初始化2张表。并创建数据

gorm支持hive_User_02

gorm支持hive_sql_03

package main

import (
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
    "gorm.io/gorm/schema"
    "time"
)

var GLOBL_DB *gorm.DB

func main()  {
    db,_ :=gorm.Open(mysql.New(mysql.Config{
        DSN: "db1:db123456@tcp(192.168.85.128:3306)/db1?charset=utf8mb4&parseTime=True&loc=Local",
        DefaultStringSize: 171,
    }),&gorm.Config{
        SkipDefaultTransaction: false,
        NamingStrategy: schema.NamingStrategy{
            TablePrefix: "t_", //表明前缀 `User` 的表名 应该是 `t_users`
            SingularTable: false,  // 使用单数表名,启用 表示 `t_user`
        },
        DisableForeignKeyConstraintWhenMigrating: true, // 逻辑外键
    })
    sqlDB,_ := db.DB()
    sqlDB.SetMaxIdleConns(10)  // 连接池最大的空闲连接数
    sqlDB.SetMaxOpenConns(100) // 连接池最多容纳的链接数量
    sqlDB.SetConnMaxLifetime(time.Hour) // 链接池中链接的最大可复用时间
    GLOBL_DB = db
    One2one()
}
// belongsTO
func One2one()  {
    GLOBL_DB.AutoMigrate(&GirlGod{},&Dog{})
    d := Dog{
        Name: "李四",
    }
    g:=GirlGod{
        Name: "美眉",
        Dog: d,
    }
    GLOBL_DB.Create(&g)
}

type Dog struct {
    gorm.Model
    Name string
    GirlGodID uint
}

type GirlGod struct {
    gorm.Model
    Name string
    Dog Dog
}

View Code

 2.1) 查询。通过Preload 预加载把关联数据拿出来

func Find()  {
    var girl GirlGod
    GLOBL_DB.Preload("Dog").Find(&girl,2)
    fmt.Println(girl)
}

 五、一对多关联

1)数据创建

type Dog struct {
    gorm.Model
    Name string
    GirlGodID uint
}

type GirlGod struct {
    gorm.Model
    Name string
    Dogs []Dog
}

func One2one () {
    GLOBL_DB.AutoMigrate(&Dog{},&GirlGod{})
    d1 := Dog{
        Model:gorm.Model{
            ID: 1,
        },
        Name: "1号",
    }
    d2 := Dog{
        Model:gorm.Model{
            ID: 2,
        },
        Name: "2号",
    }
    g := GirlGod{
        Model:gorm.Model{
            ID: 1,
        },
        Name: "美女",
        Dogs: []Dog{d1,d2},
    }
    GLOBL_DB.Create(&g)
}

 1.1) 查询

func Find()  {
    var girl GirlGod
    // 查询所有的关系数据
    GLOBL_DB.Preload("Dogs").First(&girl)
    // 查询关系中携带条件
    GLOBL_DB.Preload("Dogs","name = ?","1号").First(&girl)
    // 查询关系中携带条件,条件可以是函数
    GLOBL_DB.Preload("Dogs", func(db *gorm.DB) *gorm.DB {
        return db.Where("name = ?","1号")
    }).First(&girl)
    fmt.Println(girl)
}

 2)3张表,一对多,多对一关系查询

type Info struct {
    gorm.Model
    Money int
    DogID uint
}

type Dog struct {
    gorm.Model
    Name string
    GirlGodID uint
    Info Info
}

type GirlGod struct {
    gorm.Model
    Name string
    Dogs []Dog
}

func Find()  {
    var girl GirlGod
    // 链式关联查询
    GLOBL_DB.Preload("Dogs.Info").First(&girl)
    // 链式关联查询 加条件查询
    GLOBL_DB.Preload("Dogs.Info").Preload("Dogs","name = ?","1号").First(&girl)
    GLOBL_DB.Preload("Dogs.Info","money > 100").Preload("Dogs","name = ?","1号").First(&girl)

    // joins的用法
    GLOBL_DB.Preload("Dogs", func(db *gorm.DB) *gorm.DB {
        return db.Joins("Info").Where("money > 200")
    }).First(&girl)
}

六、多对多关联

 1)创建多个数据

type Info struct {
    gorm.Model
    Money int
    DogID uint
}

type Dog struct {
    gorm.Model
    Name string
    Info Info
    GirlGods []GirlGod `gorm:"many2many:dog_girl_god"`
}

type GirlGod struct {
    gorm.Model
    Name string
    Dogs []Dog `gorm:"many2many:dog_girl_god"`
}

func Many2many () {
    GLOBL_DB.AutoMigrate(&Dog{},&GirlGod{},&Info{})
    i := Info{
        Money: 2000,
    }
    g1 := GirlGod{
        Name: "美女1号",
    }
    g2 := GirlGod{
        Name: "美女2号",
    }
    d:= Dog{
        Name: "狗子1号",
        GirlGods: []GirlGod{g1,g2},
        Info: i,
    }
    GLOBL_DB.Create(&d)
}

gorm支持hive_gorm支持hive_04

 2) 查询与关系维护

func Find()  {
    d:=Dog{
        Model:gorm.Model{
            ID: 1,
        },
    }
    // 查看 Dog 包含下面的GirlGods信息
    GLOBL_DB.Preload("GirlGods").Find(&d)
    fmt.Println(d)
    // 只需要 Dog下面的GirlGods信息
    var girls []GirlGod
    GLOBL_DB.Model(&d).Association("GirlGods").Find(&girls)
    fmt.Println(girls)

    // 查看 girls包含下面的Dog信息
    GLOBL_DB.Model(&d).Preload("Dogs").Association("GirlGods").Find(&girls)
    GLOBL_DB.Model(&d).Preload("Dogs.Info").Association("GirlGods").Find(&girls)

}

func guanxi()  {
    GLOBL_DB.Model(&d).Association("GirlGods").Append(&g1,&g2)
    GLOBL_DB.Model(&d).Association("GirlGods").Delete(&g2)
    GLOBL_DB.Model(&d).Association("GirlGods").Replace(&g2)
    GLOBL_DB.Model(&d).Association("GirlGods").Replace(&g2,g1)
    GLOBL_DB.Model(&d).Association("GirlGods").Clear()
}

 七、多态的使用

1)构建数据

type Jiazi struct {
    ID uint
    Name string
    Xiaofengche  Xiaofengche `gorm:"polymorphic:Owner"`
}

type Yujie struct {
    ID uint
    Name string
    Xiaofengche  Xiaofengche `gorm:"polymorphic:Owner"`
}

type Xiaofengche struct {
    ID uint
    Name string
    OwnerType string
    OwnerID uint
}


func Many2many () {
    GLOBL_DB.AutoMigrate(&Jiazi{},&Yujie{},&Xiaofengche{})
    GLOBL_DB.Create(&Jiazi{Name: "夹子",Xiaofengche: Xiaofengche{Name: "小风车"}})
    GLOBL_DB.Create(&Yujie{Name: "御姐",Xiaofengche: Xiaofengche{Name: "大风车"}})
}

gorm支持hive_Test_05

 可自定义类型字段

列如

type Jiazi struct {
	ID uint
	Name string
	Xiaofengche  Xiaofengche `gorm:"polymorphic:Owner;polymorphicValue:huhu"`
}

gorm支持hive_sql_06

 2)多态也支持一对多

type Jiazi struct {
    ID uint
    Name string
    Xiaofengche  []Xiaofengche `gorm:"polymorphic:Owner;polymorphicValue:huhu"`
}

type Xiaofengche struct {
    ID uint
    Name string
    OwnerType string
    OwnerID uint
}

func Many2many () {
    GLOBL_DB.Create(&Jiazi{Name: "夹子",Xiaofengche: []Xiaofengche{
        {Name: "小风车1"},
        {Name: "小风车2"},
    }})
}

 八、外键关联

gorm支持hive_User_02

gorm支持hive_sql_03

//  foreignKey 默认引用id
// references 重置引用
type Jiazi struct {
    ID uint
    Name string
    Xiaofengche  []Xiaofengche `gorm:"foreignKey:JiaziName;references:Name"`
}

type Xiaofengche struct {
    ID uint
    Name string
    JiaziName string
}

func Many2many () {
    GLOBL_DB.AutoMigrate(&Jiazi{},&Xiaofengche{})
    GLOBL_DB.Create(&Jiazi{Name: "夹子",Xiaofengche: []Xiaofengche{
        {Name: "小风车1"},
        {Name: "小风车2"},
    }})
}

View Code

gorm支持hive_gorm支持hive_09

 九、many2many的外键关联

//  foreignKey 默认引用id
// references 重置引用
type Jiazi struct {
    ID uint
    Name string
    Xiaofengche  []Xiaofengche `gorm:"many2many:jiazi_fengche;foreignKey:Name;references:FCName"`
}

type Xiaofengche struct {
    ID uint
    FCName string
    JiaziName string
}

func Many2many () {
    GLOBL_DB.AutoMigrate(&Jiazi{},&Xiaofengche{})
    GLOBL_DB.Create(&Jiazi{Name: "夹子",Xiaofengche: []Xiaofengche{
        {FCName: "小风车1"},
        {FCName: "小风车2"},
    }})
}

 扩展

gorm支持hive_User_02

gorm支持hive_sql_03

//  foreignKey 默认引用id
// references 重置引用
type Jiazi struct {
    ID uint
    Name string
    Xiaofengche  []Xiaofengche `gorm:"many2many:jiazi_fengche;foreignKey:Name;references:FCName;joinReferences:fengche"`
}

type Xiaofengche struct {
    ID uint
    FCName string
    JiaziName string
}

func Many2many () {
    GLOBL_DB.AutoMigrate(&Jiazi{},&Xiaofengche{})
    GLOBL_DB.Create(&Jiazi{Name: "夹子",Xiaofengche: []Xiaofengche{
        {FCName: "小风车1"},
        {FCName: "小风车2"},
    }})
}

View Code

 标签

many2many:jiazi_fengche;
foreignKey:Name;
references:FCName;
joinReferences:fengche

 八、事务的使用

1)使用 Transaction 来提交事务

func TestTransaction(){
    flag := false
    GLOBL_DB.AutoMigrate(&TMG{})
    GLOBL_DB.Transaction(func(tx *gorm.DB) error {
        tx.Create(&TMG{Name: "汉字"})
        tx.Create(&TMG{Name: "汉字"})
        tx.Create(&TMG{Name: "汉字"})
        if flag {
            return nil
        } else {
            return errors.New("有汉字")
        }
    })
}

备注

1)使用 Transaction 开启事务
2)内部需要使用func函数来写执行的sql
3)func函数需要有返回值,nil 返回则执行sql语句生成在数据库,errors不会生成数据库数据

2)事务的嵌套使用

func TestTransaction1(){
    GLOBL_DB.AutoMigrate(&TMG{})
    GLOBL_DB.Transaction(func(tx *gorm.DB) error {
        tx.Create(&TMG{Name: "一"})
        tx.Create(&TMG{Name: "二"})
        tx.Transaction(func(tx *gorm.DB) error {
            tx.Create(&TMG{Name: "三"})
            return errors.New("有汉字")
        })
        return nil
    })
}

3)Begin 开启事务,Commit提交事务,Rollback 回滚,提交的事务不会被执行

func TestTransaction2(){
    GLOBL_DB.AutoMigrate(&TMG{})
    tx := GLOBL_DB.Begin()
    tx.Create(&TMG{Name: "一"})
    tx.Create(&TMG{Name: "aa"})
    if true {
        // 回滚
        tx.Rollback()
    }
    // 有了 Rollback。Commit已经没有用了
    tx.Commit()
}

4)SavePoint 与 RollbackTo的使用

func TestTransaction3(){
    GLOBL_DB.AutoMigrate(&TMG{})
    tx := GLOBL_DB.Begin()
    tx.Create(&TMG{Name: "一"})
    tx.Create(&TMG{Name: "aa"})

    // 忽略 SavePoint 到 RollbackTo 中间的代码
    tx.SavePoint("duo")
    tx.Create(&TMG{Name: "bb"})
    tx.RollbackTo("dop")

    tx.Commit()
}

 九、自定义数据类型

1)数据库存json。通过 value存到数据库,通过Scan从数据库解析出来

type CInfo struct {
    Name string
    Age int
}

func (c CInfo)Value() (driver.Value,error) {
    str,err := json.Marshal(c)
    if err != nil {
        return nil, err
    }
    return string(str),nil
}

func (c *CInfo)Scan(value interface{}) (error) {
    str,ok := value.([]byte)
    if !ok {
        return errors.New("不匹配的数据类型")
    }
    json.Unmarshal(str,c)
    return nil
}

type Cuser struct {
    ID int
    Info CInfo
}

func Make(){
    GLOBL_DB.AutoMigrate(&Cuser{})
    GLOBL_DB.Create(&Cuser{Info:CInfo{Name: "哈哈",Age: 22}})
}

func Find()  {
    var u Cuser
    GLOBL_DB.First(&u)
    fmt.Println(u)
}

9.1) 字符串拼接

gorm支持hive_User_02

gorm支持hive_sql_03

package main

import (
    "database/sql/driver"
    "errors"
    "strings"
)

type CInfo struct {
    Name string
    Age  int
}

type CUser struct {
    ID   uint
    Info CInfo `gorm:"type:text"`
    Args Args
}

type Args []string

//存储 1,2,3,4
func (self Args) Value() (driver.Value, error) {
    if len(self) > 0 {
        var str string = self[0]
        for _, v := range self[1:] {
            str += "," + v
        }
        return str, nil
    } else {
        return "", nil
    }
}

func (self *Args) Scan(value interface{}) error {
    str, ok := value.([]byte)
    if !ok {
        return errors.New("数据类型无法解析")
    }
    *self = strings.Split(string(str), ",")
    return nil
}

func main() {

}

View Code

 十、导入sql

gorm支持hive_User_02

gorm支持hive_sql_03

package main

import (
    "fmt"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
    "io/ioutil"
    "strings"
)

var (
    db_cmdb *gorm.DB
)

func gormMysql(tableDb string) {
    connstr := fmt.Sprintf("root:123456@tcp(192.168.85.123:3306)/%s?charset=utf8mb4&parseTime=true", tableDb)
    mysqlConfig := mysql.Config{
        DSN:                       connstr, // DSN data source name
        DefaultStringSize:         191,     // string 类型字段的默认长度
        SkipInitializeWithVersion: false,   // 根据版本自动配置
    }
    if db, err := gorm.Open(mysql.New(mysqlConfig), &gorm.Config{
        SkipDefaultTransaction:                   false,
        DisableForeignKeyConstraintWhenMigrating: true, // 逻辑外键
    }); err != nil {
        return
    } else {
        sqlDB, _ := db.DB()
        sqlDB.SetMaxIdleConns(10)
        sqlDB.SetMaxOpenConns(100)
        db_cmdb = db
    }
}

}
func readfile() {
    sqls, _ := ioutil.ReadFile("futong_cmp_cmdb.sql")
    sqlArr := strings.Split(string(sqls), ";")
    for _, sql := range sqlArr {
        sql = strings.TrimSpace(sql)
        if sql == "" {
            continue
        }
        err := db_cmdb.Exec(sql).Error
        if err != nil {
            fmt.Println(err)
            return
        } else {
            fmt.Println(sql, " success")
        }
    }
}

func main() {
    gormMysql("cmdb")
    readfile()
}

View Code

 查询

func (self *modelDataRepository) mysqlData(tableDB string, modelData common.ModelDataList) (schema []map[string]interface{}, count int64, err error) {
    db := func(db *gorm.DB) *gorm.DB {
        for key, value := range modelData.SearchMap {
            db.Where(fmt.Sprintf("%s LIKE  ?", key), fmt.Sprintf("%%%s%%", value))
        }
        return db
    }
    tx := global.MapDB[tableDB].Begin()
    tx.Scopes(db).Table(modelData.ModelName).Offset(int(modelData.Current - 1)).Limit(int(modelData.Size)).Find(&schema)
    tx.Scopes(db).Table(modelData.ModelName).Count(&count)
    return schema, count, err
}

 begin查询更新

tx := DB.Begin()
    tx = tx.Where("project_code = ?",config.ProjectCode)
    tx = tx.Where("environment = ?",config.Environment)
    tx = tx.Where("service = ?",config.Service)
    tx = tx.Where("filename = ?",config.Filename)
    tx.Model(model.KerriganConfig{}).Update("content",config.Content)
    tx.Commit()

十一、json字段内部查询,待验证测试

type Book struct {
    ID       uint           `gorm:"primary_key"`
    Title    string         `gorm:"size:100;not null"`
    Author   string         `gorm:"size:100;not null"`
    Metadata map[string]interface{} `gorm:"type:jsonb;not null"`
}

在 tag 中,我们使用了 "type:jsonb",表示这是一个 json 字段。我们需要在查询时指定 json 中的 key,可以通过下面的方式来实现:

db.Where("metadata->>'$.language'=?", "en").Find(&books)
上面的代码使用了 "->>" 操作符,表示从 json 中获取一个字符串值。其中,".language" 是 json 中的 key 名称,"en" 是需要匹配的字符串值。
-----------------------------------------------------------
如果需要匹配的不是字符串,而是数字或布尔值,可以使用 "->" 操作符:
db.Where("metadata->'$.year' BETWEEN ? and ?", 1950, 2000).Find(&books)
上面的代码可以查询出 metadata 中 "year" key 字段的值在 1950 到 2000 之间的 Book 记录。

 json 字段

package resource

import (
    "fiy/common/models"

    "gorm.io/datatypes"
)

/*
  @Author : lanyulei
*/

// 字段数据
type Data struct {
    Id       int            `gorm:"column:id; primary_key;AUTO_INCREMENT" json:"id"`                          // 字段分组ID
    Uuid     string         `gorm:"column:uuid; type:varchar(45); unique;" json:"uuid" binding:"required"`    // 设备唯一ID
    InfoId   int            `gorm:"column:info_id; type:int(11); index;" json:"info_id" binding:"required"`   // 对应的模型ID
    InfoName string         `gorm:"column:info_name; type:varchar(128);" json:"info_name" binding:"required"` // 对应的模型名称
    Status   int            `gorm:"column:status; type:int(11); default:1" json:"status"`                     // 0 没有状态,1 空闲,2 故障,3 待回收,4 正在使用
    Data     datatypes.JSON `gorm:"column:data; type:json" json:"data" binding:"required"`                    // 数据
    models.BaseModel
}

func (Data) TableName() string {
    return "cmdb_resource_data"
}

 json字段已验证

gorm支持hive_User_02

gorm支持hive_sql_03

package main

import (
    "database/sql/driver"
    "encoding/json"
    "fmt"
    "gorm.io/datatypes"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
    "gorm.io/gorm/schema"
    "time"
)

type XTime struct {
    time.Time
}

// 1. 为 Xtime 重写 MarshaJSON 方法,在此方法中实现自定义格式的转换;
func (t XTime) MarshalJSON() ([]byte, error) {
    output := fmt.Sprintf("\"%s\"", t.Format("2006-01-02 15:04:05"))
    return []byte(output), nil
}

// 2. 为 Xtime 实现 Value 方法,写入数据库时会调用该方法将自定义时间类型转换并写入数据库;
func (t XTime) Value() (driver.Value, error) {
    var zeroTime time.Time
    if t.Time.UnixNano() == zeroTime.UnixNano() {
        return nil, nil
    }
    return t.Time, nil
}

// 3. 为 Xtime 实现 Scan 方法,读取数据库时会调用该方法将时间数据转换成自定义时间类型;
func (t *XTime) Scan(v interface{}) error {
    value, ok := v.(time.Time)
    if ok {
        *t = XTime{Time: value}
        return nil
    }
    return fmt.Errorf("can not convert %v to timestamp", v)
}

type ServicePrototype struct {
    Id       int            `gorm:"column:id; primary_key;AUTO_INCREMENT;comment:唯一id" json:"id"`
    Name     string         `gorm:"column:name; type:varchar(128);unique;comment:名称" json:"name" v:"required"`
    UserName string         `gorm:"column:username; type:varchar(128);comment:创建人" json:"username"`
    Data     datatypes.JSON `gorm:"column:data; type:json" json:"data" binding:"required"`
}

var DB *gorm.DB

func init() {
    if db, err := gorm.Open(mysql.New(mysql.Config{
        DSN:               "root:m9uSFL7duAVXfeAwGUSG@tcp(192.168.85.123:3306)/ft_cmdb?charset=utf8mb4&parseTime=True&loc=Local",
        DefaultStringSize: 171,
    }), &gorm.Config{
        SkipDefaultTransaction: false,
        NamingStrategy: schema.NamingStrategy{
            TablePrefix:   "t_",  //表明前缀 `User` 的表名 应该是 `t_users`
            SingularTable: false, // 使用单数表名,启用 表示 `t_user`
        },
        DisableForeignKeyConstraintWhenMigrating: true, // 逻辑外键
    }); err != nil {
        panic(err.Error())
    } else {
        DB = db
        sqlDB, _ := DB.DB()
        sqlDB.SetMaxIdleConns(10)           // 连接池最大的空闲连接数
        sqlDB.SetMaxOpenConns(100)          // 连接池最多容纳的链接数量
        sqlDB.SetConnMaxLifetime(time.Hour) // 链接池中链接的最大可复用时间
    }
    if err := DB.AutoMigrate(&ServicePrototype{}); err != nil {
        fmt.Println(err)
    }
}

func insert() {
    data := make(map[string]interface{})
    data["age"] = 13
    data["city"] = "上海"
    newdata, _ := json.Marshal(&data)
    servicePrototype := ServicePrototype{Name: "zhangsan1", UserName: "admin1", Data: newdata}
    DB.Create(&servicePrototype)
}

func find() {
    var servicePrototype ServicePrototype
    DB.Where("data->>'$.age'=?", 13).Find(&servicePrototype)
    fmt.Println(servicePrototype.Data)
    fmt.Println(servicePrototype.Name)
}

func main() {
    find()
}

View Code

 存储切片

var servicePrototype ServicePrototype
DB.Where("name = ?", "zhangsan2").Where("data->>'$[0].age'=?", 13).Find(&servicePrototype)

 切片查询

MySQL [ft_cmdb]> select * from t_service_prototypes where JSON_CONTAINS(data,JSON_OBJECT('age', 14));
+----+-----------+----------+----------------------------------------------------------------+
| id | name      | username | data                                                           |
+----+-----------+----------+----------------------------------------------------------------+
|  1 | zhangsan  | admin    | [{"age": 12, "city": "北京"}, {"age": 14, "city": "上海"}]     |
|  3 | zhangsan1 | admin1   | [{"age": 15, "city": "杭州"}, {"age": 14, "city": "重庆"}]     |
+----+-----------+----------+----------------------------------------------------------------+

 对应的go代码

var servicePrototype []ServicePrototype
    DB.Where("JSON_CONTAINS(data, JSON_OBJECT('age', ?))", 14).Find(&servicePrototype)

 设置表名描述

gorm支持hive_User_02

gorm支持hive_sql_03

type User struct {
    gorm.Model
    Name   string `gorm:"comment:用户姓名"`
    Age    int    `gorm:"comment:用户年龄"`
    Email  string `gorm:"comment:用户邮箱"`
}

type Product struct {
    gorm.Model
    Name   string `gorm:"comment:产品名称"`
    Price  float64 `gorm:"comment:产品价格"`
}

func main() {
    db, err := gorm.Open("mysql", "your-database-connection-string")
    if err != nil {
        // 处理数据库连接错误
    }
    defer db.Close()

    // 设置表描述信息
    db.Set("gorm:table_options", "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户信息表'").AutoMigrate(&User{})
    db.Set("gorm:table_options", "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='产品信息表'").AutoMigrate(&Product{})
}

View Code

 设置表名描述优化

gorm支持hive_User_02

gorm支持hive_sql_03

import (
    "gorm.io/gorm"
    "gorm.io/gorm/clause"
)

type User struct {
    gorm.Model
    Name   string `gorm:"comment:用户姓名"`
    Age    int    `gorm:"comment:用户年龄"`
    Email  string `gorm:"comment:用户邮箱"`
}

type Product struct {
    gorm.Model
    Name   string `gorm:"comment:产品名称"`
    Price  float64 `gorm:"comment:产品价格"`
}

func main() {
    db, err := gorm.Open("mysql", "your-database-connection-string")
    if err != nil {
        // 处理数据库连接错误
    }
    defer db.Close()

    // 定义表描述信息
    userTableOptions := clause.TableOption{
        Option: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户信息表'",
    }
    productTableOptions := clause.TableOption{
        Option: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='产品信息表'",
    }

    // 迁移模型并设置表描述信息
    db.AutoMigrate(&User{}, &Product{}, &gorm.Model{},
        &clause.Table{Name: "users", TableOption: userTableOptions},
        &clause.Table{Name: "products", TableOption: productTableOptions},
    )
}

View Code

 表名优化

func (Order) TableOptions() string {
    return "engine=innodb comment='订单表'"
}

if t, ok := t.(database.TableOptions); ok {
    defTableOpts = t.TableOptions()
}

循环执行 .Set("gorm:table_options", defTableOpts)