zoukankan      html  css  js  c++  java
  • mysql之GORM接口

    Mysqlgolang中推荐使用Gormhttps://gorm.io/docs/

    import "github.com/jinzhu/gorm"

    1. 连接数据库

    user:password@(localhost)/dbname?charset=utf8&parseTime=True&loc=Local
    db, err := gorm.Open("mysql", "user:password@/dbname?charset=utf8&parseTime=True&loc=Local")
    defer db.Close()

    In order to handle time.Time correctly, you need to include parseTime as a parameter.

    In order to fully support UTF-8 encoding, you need to change charset=utf8 to charset=utf8mb4.

    2. model

    由于gorm是使用的orm映射,所以需要定义要操作的表的model,在go中需要定义一个struct, struct的名字就是对应数据库中的表名注意gorm查找struct名对应数据库中的表名的时候会默认把你的struct中的大写字母转换为小写并加上“s”,所以可以加上 db.SingularTable(true) 让gorm转义struct名字的时候不用加上s。可以提前在数据库中创建好表的然后再用gorm去查询的,也可以用gorm去创建表,建议直接在数据库上创建,修改表字段的操作方便,gorm只用来查询和更新数据。

    type User struct {
      gorm.Model //嵌入常用字段
      Name         string
      Age          sql.NullInt64
      Birthday     *time.Time
      Email        string  `gorm:"type:varchar(100);unique_index"`
      Role         string  `gorm:"size:255"` // set field size to 255
      MemberNumber *string `gorm:"unique;not null"` // set member number to unique and not null
      Num          int     `gorm:"AUTO_INCREMENT"` // set num to auto incrementable
      Address      string  `gorm:"index:addr"` // create index with name `addr` for address
      IgnoreMe     int     `gorm:"-"` // ignore this field
    }

    定义models时tags是可选项,gorm支持如下tags:

    Column:指定列名

    Type:指定列数据类型

    Size:指定列大小,默认255

    PRIMARY_KEY:指定列作为主键

    UNIQUE:指定列唯一

    DEFAULT:指定列默认值

    PRECISION:指定列精度

    NOT NULL:指定列NOT NULL

    AUTO_INCREMENT:指定列自动增加

    INDEX:创建索引with or without name,same name creates composite indexes

    UNIQUE_INDEX:Like INDEX,Create unique index

    EMBEDDED:Set struct as embedded

    EMBEDDED_PREFIX:Set embedded struct’s prefix name

    -:忽略此域fields

    gorm.Model

    gorm.Model is a basic GoLang struct which includes the following fields: ID, CreatedAt, UpdatedAt, DeletedAt. 

    It may be embedded into your model or you may build your own model without it.

    // gorm.Model definition
    type Model struct {
      ID        uint `gorm:"primary_key"`
      CreatedAt time.Time
      UpdatedAt time.Time
      DeletedAt *time.Time
    }
    
    // Inject fields `ID`, `CreatedAt`, `UpdatedAt`, `DeletedAt` into model `User`
    type User struct {
      gorm.Model
      Name string
    }
    
    // Declaring model w/o gorm.Model
    type User struct {
      ID   int
      Name string
    }

    GORM uses any field with the name ID as the table’s primary key by default.

    type User struct {
      ID   string // field named `ID` will be used as primary field by default
      Name string
    }
    
    // Set field `AnimalID` as primary field
    type Animal struct {
      AnimalID int64 `gorm:"primary_key"`
      Name     string
      Age      int64
    }

    You can apply any rules on the default table name by defining the DefaultTableNameHandler.

    gorm.DefaultTableNameHandler = func (db *gorm.DB, defaultTableName string) string  {
      return "prefix_" + defaultTableName;
    }

    3. 增删改查

    注:域的零值不会被插入数据库,也不会被查询,但使用时的值为默认零值。

    all fields having a zero value, like 0, '', false or other zero values, won’t be saved into the database but will use its default value. If you want to avoid this, consider using a pointer type or scanner/valuer.

    When query with struct, GORM will only query with those fields has non-zero value, that means if your field’s value is 0, '', false or other zero values, it won’t be used to build query conditions, for example:

    db.Where(&User{Name: "jinzhu", Age: 0}).Find(&users)
    //// SELECT * FROM users WHERE name = "jinzhu";

    Struct& map查询

    // Struct
    db.Where(&User{Name: "jinzhu", Age: 20}).First(&user)
    //// SELECT * FROM users WHERE name = "jinzhu" AND age = 20 ORDER BY id LIMIT 1;
    
    // Map
    db.Where(map[string]interface{}{"name": "jinzhu", "age": 20}).Find(&users)
    //// SELECT * FROM users WHERE name = "jinzhu" AND age = 20;
    
    // Slice of primary keys
    db.Where([]int64{20, 21, 22}).Find(&users)
    //// SELECT * FROM users WHERE id IN (20, 21, 22);

    4. 关联

    外键表示一个表中的一个字段被另一个表中的一个字段引用。外键可以使得两张表关联,保证数据的一致性和实现一些级联操作。MySQL会自动为所有表的主键进行索引,但是外键字段必须由用户进行明确的索引。

    Belongs to的主体是profile,其属于另一个模型(User),外键在主体中指定,在主体中保存(foreignkey),关联到从体中某字段(associate_foreignkey)。

    Has oneHas many的主体是user,其拥有其他模型(profile),外键在主体中指定,指定从体中某字段为外键(foreignkey),关联主体中某字段(associate_foreignkey)。

    属于(belongs to)

    Belongs to会与另一个模型建立一对一关系,因此声明的每一个模型实例都会“属于”另一个模型实例。

    Foreign Key,若要定义属于关系,外键必须存在, 默认外键使用所有者的类型名称及其主键。

    type User struct {
      gorm.Model
      Name string
    }
    
    // `Profile` 属于 `User`, 外键是`UserID` 
    type Profile struct {
      gorm.Model
      UserID int   // 默认外键UserID
      User   User
      Name   string
    }
    type Profile struct {
      gorm.Model
      Name      string
      User      User `gorm:"foreignkey:UserRefer"` // 将 UserRefer 指定为外键
      UserRefer uint
    }

    对于一个 belongs to 关系,GORM 通常使用所有者的主键作为外键的值,上例中,外键的值是 User  ID

    可以用 association_foreignkey 标签来更改它,例如:

    type User struct {
      gorm.Model
      Refer string
      Name string
    }
    
    type Profile struct {
      gorm.Model
      Name      string
      User      User `gorm:"association_foreignkey:Refer"` // 将 Refer 作为关联外键
      UserRefer string
    }

    可以用Related查找belongs to关系:

    db.Model(&user).Related(&profile)
    //// SELECT * FROM profiles WHERE user_id = 111; // 111 is user's ID

    Has one

    在一个 has one 关联中,其也与另一个 model 建立了一对一关系,但它和一对一关系有不同的语义(及结果)。 Has one 表示:model 的每一个示例都包含或拥有另一个 model 的示例。

     has one 关系中,被拥有 model 必须存在一个外键字段,用于保存所属 model 的主键。

    外键名通常使用 has one 拥有者 model 的类型加 主键 生成,对于上面的例子,其外键名为 UserID.

    // User 只能有一张信用卡 (CreditCard), CreditCardID 是外键
    type CreditCard struct {
      gorm.Model
      Number   string
      UserID   uint
    // UserName string
    }
    
    type User struct {
      gorm.Model
      CreditCard   CreditCard
    }
    type User struct {
      gorm.Model
      CreditCard CreditCard `gorm:"foreignkey:UserName"`
    }

    在 has one 关系中,被拥有 model 会使用其外键,保存拥有者 model 的主键,您可以更改保存至另一个字段通过association_foreignkey

    type CreditCard struct {
      gorm.Model
      Number string
      UID    string
    }
    
    type User struct {
      gorm.Model
      Name       `sql:"index"`
      CreditCard CreditCard `gorm:"foreignkey:uid;association_foreignkey:name"`
    }

    可以通过Related使用has one关联:

    var card CreditCard
    db.Model(&user).Related(&card, "CreditCard")
    //// SELECT * FROM credit_cards WHERE user_id = 123; // 123 is user's primary key
    // CreditCard 是 users 的字段,其含义是,获取 user 的 CreditCard 并填充至 card 变量
    // 如果字段名与 model 名相同,比如上面的例子,此时字段名可以省略不写,像这样:
    db.Model(&user).Related(&card)

    Has Many

    在一个 has many 关联中,其也与另一个 model 建立了一对多关系,不同于 has one,model 的拥有者可以有零个或多个实例。

    // User 可以有多张信用卡(CreditCards), UserID 是外键
    type User struct {
      gorm.Model
      CreditCards []CreditCard
    }
    
    type CreditCard struct {
      gorm.Model
      Number   string
      UserID  uint 
    // UserRefer uint
    }
    type User struct {
      gorm.Model
      CreditCards []CreditCard `gorm:"foreignkey:UserRefer"`
    }

    Foreign Key,在 has many 关系中,被拥有 model 必须存在一个外键字段,默认的外键字段名称通常使用其拥有者 model 加上它的主键(比如 UserID, CardID, 等)。

    要使用另一个字段作为外键,你可以通过标签 foreignkey 来定制它。

    可通过association_foreignkey修改关联外键。

    type User struct {
      gorm.Model
      MemberNumber string
      CreditCards  []CreditCard `gorm:"foreignkey:UserMemberNumber;association_foreignkey:MemberNumber"`
    }
    
    type CreditCard struct {
      gorm.Model
      Number           string
      UserMemberNumber string
    }

    可以通过Related使用has many关联:

    db.Model(&user).Related(&emails)
    //// SELECT * FROM emails WHERE user_id = 111; // 111 是 user 的主键

    预加载

    Preload()方法的参数应该是主体结构的字段名。

    // 下面的例子会用到 User 和 Order 结构体
    type User struct {
      gorm.Model
      Username string
      Orders Order
    }
    type Order struct {
      gorm.Model
      UserID uint
      Price float64
    }
    // Preload 方法的参数应该是主结构体的字段名
    db.Preload("Orders").Find(&users)
    //// SELECT * FROM users;
    //// SELECT * FROM orders WHERE user_id IN (1,2,3,4);
    db.Preload("Orders").Preload("Profile").Preload("Role").Find(&users)
    //// SELECT * FROM users;
    //// SELECT * FROM orders WHERE user_id IN (1,2,3,4); // has many
    //// SELECT * FROM profiles WHERE user_id IN (1,2,3,4); // has one
    //// SELECT * FROM roles WHERE id IN (4,5,6); // belongs to

    关联查询示例

    定义了一个 User 和 Company, User 中可以包含多个 Company, 如下:

    type User struct {
            ID        int        `gorm:"TYPE:int(11);NOT NULL;PRIMARY_KEY;INDEX"`
            Name      string     `gorm:"TYPE: VARCHAR(255); DEFAULT:'';INDEX"`
            Companies []Company  `gorm:"FOREIGNKEY:UserId;ASSOCIATION_FOREIGNKEY:ID"`
            CreatedAt time.Time  `gorm:"TYPE:DATETIME"`
            UpdatedAt time.Time  `gorm:"TYPE:DATETIME"`
            DeletedAt *time.Time `gorm:"TYPE:DATETIME;DEFAULT:NULL"`
    }
    type Company struct {
            gorm.Model
            Industry int    `gorm:"TYPE:INT(11);DEFAULT:0"`
            Name     string `gorm:"TYPE:VARCHAR(255);DEFAULT:'';INDEX"`
            Job      string `gorm:"TYPE:VARCHAR(255);DEFAULT:''"`
            UserId   int    `gorm:"TYPE:int(11);NOT NULL;INDEX"`
    }

    在查询 User 时希望把 Company 的信息也一并查询, 有以下三种方法:

    Related

    使用 Related 方法, 需要把 User 查询好, 然后根据 User 定义中指定的 FOREIGNKEY 去查找 Company, 如果没定义, 则调用时需要指定, 如下:

    var u User
    db.First(&u)
    db.Model(&u).Related(&u.Companies).Find(&u.Companies)

    User 列表时遍历列表一一查询 Company

    Association

    使用 Association 方法, 需要把 User 查询好, 然后根据 User 定义中指定的 AssociationForeignKey 去查找 Company, 必须定义, 如下:

    var u User
    db.First(&u)
    db.Model(&u).Association("Companies").Find(&u.Companies)

    Preload

    使用 Preload 方法, 在查询 User 时先去获取 Company 的记录, 如下:

    // 查询单条 user
    var u User
    db.Debug().Preload("Companies").First(&u)
    // 对应的 sql 语句
    // SELECT * FROM users LIMIT 1;
    // SELECT * FROM companies WHERE user_id IN (1);
    
    // 查询所有 user
    var list []User
    db.Debug().Preload("Companies").Find(&list)
    // 对应的 sql 语句
    // SELECT * FROM users;
    // SELECT * FROM companies WHERE user_id IN (1,2,3...);

    5. 钩子Hooks/callback

    Hooks(一般称之为钩子函数)的功能是在运行创建/查询/更新/删除语句之前或者之后执行。

    如果你为一个 model 定义了一个具体的方法,它将会在运行 创建,更新,查询,删除时自动被调用,并且如果任何回调函数函数返回一个错误,GORM 将会停止接下来的操作并且回滚当前的事务。

    Scope包含当前对数据库操作的所有信息。

    Scope contain current operation's information when you perform any operation on the database

    type Scope struct {    
        Search  *search    
        Value   interface{}    
        SQL     string    
        SQLVars []interface{}
        // contains filtered or unexported fields
    }

    Gorm使用可链接的API,*gorm.DB是链的桥梁,对于每个链API,它将创建一个新的关系。

    当我们开始执行任何操作时,GORM将基于当前的*gorm.DB创建一个新的*gorm.Scope实例。并且基于当前操作的类型,它将调用注册的creating, updating, querying, deleting或row_querying回调来运行操作。

    GORM本身由Callbacks提供支持,因此您可以根据需要完全自定义GORM。

    注册新callback

    func updateCreated(scope *Scope) {
        if scope.HasColumn("Created") {
            scope.SetColumn("Created", NowFunc())
        }
    }
    db.Callback().Create().Register("update_created_at", updateCreated)// 注册Create进程的回调

    删除现有callback

    db.Callback().Create().Remove("gorm:create")// Create回调中删除`gorm:create`回调

    替换现有的callback

    db.Callback().Create().Replace("gorm:create", newCreateFunction)

    // 使用新函数`newCreateFunction`替换回调`gorm:create`用于创建过程

    注册callback顺序

    db.Callback().Create().Before("gorm:create").Register("update_created_at", updateCreated)
    db.Callback().Create().After("gorm:create").Register("update_created_at", updateCreated)
    db.Callback().Query().After("gorm:query").Register("my_plugin:after_query", afterQuery)
    db.Callback().Delete().After("gorm:delete").Register("my_plugin:after_delete", afterDelete)
    db.Callback().Update().Before("gorm:update").Register("my_plugin:before_update", beforeUpdate)
    db.Callback().Create().Before("gorm:create").After("gorm:before_create").Register("my_plugin:before_create", beforeCreate)

    参考:

    1. https://gorm.io/docs/conventions.html  英文文档 中文文档  官网

    2. http://gorm.book.jasperxu.com/中文文档

    3. GORM 关联查询简书

    4. golang之mysql操作-GORM

    5.「连载十」定制 GORM Callbacks

    6.  golang操作mysql使用总结  sql操作

  • 相关阅读:
    蓝桥杯 历届试题 青蛙跳杯子 (BFS)
    HDOJ 1233 (克鲁斯卡尔+并查集)
    HDOJ 1198
    HDOJ 1041 (推公式,大数)水题
    单词接龙
    1284 2 3 5 7的倍数
    2020 排序相减
    isset()和empty()区别
    图像渲染
    Leetcode 328. 奇偶链表
  • 原文地址:https://www.cnblogs.com/embedded-linux/p/13285154.html
Copyright © 2011-2022 走看看