zoukankan      html  css  js  c++  java
  • go之gorm

    1、简介

    ORM

    Object-Relationl Mapping, 它的作用是映射数据库和对象之间的关系,方便我们在实现数据库操作的时候不用去写复杂的sql语句,把对数据库的操作上升到对于对象的操作。

    gorm

    gorm就是基于Go语言实现的ORM库。

    类似于Java生态里大家听到过的Mybatis、Hibernate、SpringData等。

    Github

    https://github.com/jinzhu/gorm

    官方文档

    https://gorm.io/

    2、如何使用Gorm

    只要四步就能上手gorm,可以尽情的沉浸在毫无技术含量的CRUD世界。

    2.1 下载gorm库

    下载gorm库

    github.com/jinzhu/gorm v1.9.10
    

      

    go get -u github.com/jinzhu/gorm

    这是比较原始的方式,现在有了go mod,我们可以更方便的配置,甚至不用配置。

    写好代码,在文件下执行go build,go.mod会自动添加对于gorm的依赖包


    当然,也可以手动添加这个依赖。

    具体参见go-demo项目(https://github.com/DMinerJackie/go-demo

    2.2 创建DB连接

    建立数据库连接

     1 package main
     2 
     3 import (
     4   "github.com/jinzhu/gorm"
     5     _ "github.com/jinzhu/gorm/dialects/mysql"
     6 )
     7 
     8 func main() {
     9     var err error
    10     db, connErr := gorm.Open("mysql", "root:rootroot@/dqm?charset=utf8&parseTime=True&loc=Local")
    11     if connErr != nil {
    12         panic("failed to connect database")
    13     }
    14     defer db.Close()
    15   db.SingularTable(true)
    16 }

    gorm支持很多数据源包括PostgreSQL、MySQL等。

    这里连接的是MySQL,所以需要引用"github.com/jinzhu/gorm/dialects/mysql"驱动。

    通过上面声明,已经获取数据库的连接。

    db.SingularTable(true)这句的作用后面会提到。

    2.3 创建映射表结构的struct

    定义数据库表结构对应的struct

    比如这里我们要操作的是表test表,表结构如下

    CREATE TABLE `test` (
      `id` bigint(20) NOT NULL,
      `name` varchar(5) DEFAULT NULL,
      `age` int(11) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
    

      

    于是我们对应可以定义struct结构如下

    type Test struct {
        ID   int64  `gorm:"type:bigint(20);column:id;primary_key"`
        Name string `gorm:"type:varchar(5);column:name"`
        Age  int    `gorm:"type:int(11);column:age"`
    }
    

      

    每个字段后面的gorm是结构标记,可以用于声明对应数据库字段的属性。

    比如ID后面的约束为该字段为bigint(20)类型,对应列表为id,且该字段为主键。

    除此以外,还有更加丰富的标签定义参见官方文档:http://gorm.io/zh_CN/docs/models.html

    2.4 CRUD

    有了前面三步的铺垫,下面就可以执行真正写数据库操作了。

    比如"增"

    test := &Test{
            ID:3,
            Name:"jackie",
            Age:18,
        }
        db.Create(test)

    比如"删"

    test := &Test{
            ID:3,
            Name:"jackie",
            Age:18,
        }
    db.Delete(test)
    

      

    比如"改"

    test := &Test{
            ID:   3,
            Name: "hello",
            Age:  18,
        }
    db.Model(&test).Update("name", "world")
    

      


    比如"查"

    var testResult Test
    db.Where("name = ?", "hello").First(&testResult)
    fmt.Println("result: ", testResult)
    

      

    如果只是想做个纯粹的CRUDer,掌握上面四步就算是会用gorm了。

    如果还想来点花式的,更深入的,继续往下看~~~

    3、表名和结构体如何映射

    从上面四步,我们只看到在创建DB链接的时候,提供的信息仅仅到数据库,那么gorm是如何做到将表结构和你定义的struct映射起来的呢?

    有三种方式可以实现,如果以下三种方式都没有实现,如果你是创建表,则gorm默认会在你定义的struct名后面加上”s“,比如上面就会创建tests表。

    3.1 db.SingularTable(true)

    通过db.SingularTable(true),gorm会在创建表的时候去掉”s“的后缀

    3.2 实现TableName方法

    func (Test) TableName() string {
        return "test"
    }
    

      

    TableName方法定义在scope.go的tabler接口中

    type tabler interface {
        TableName() string
    }
    

      

    3.3 通过Table API声明

    db.Table("test").Where("name = ?", "hello").First(&testResult)
    

      

    在CRUD前,指明需要操作的表名也是OK的。

    4、其他花式操作

    下面花式API操作使用表dqm_user_role,对应struct如下

    type DqmUserRole struct {
        ID        int64     `gorm:"column:id;primary_key" json:"id"`
        UserId    string    `gorm:"column:user_id" json:"user_id"`
        RoleId    string    `gorm:"column:role_id" json:"role_id"`
        CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
        UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
    }
    

      

    表中初始数据如下

     
    image.png

    以下API均亲测可用

    First

    var dqmUserRole DqmUserRole
    // 按照主键顺序的第一条记录
    db.First(&dqmUserRole)
    fmt.Println("roleId: ", dqmUserRole.RoleId)
    

      


    Last

    var dqmUserRole1 DqmUserRole
    // 按照主键顺序的最后一条记录
    db.Last(&dqmUserRole1)
    fmt.Println("roleId: ", dqmUserRole1.RoleId)
    

      

    Find

    var dqmUserRoels []DqmUserRole
    // 所有记录
    db.Find(&dqmUserRoels)
    fmt.Println("dqmUserRoles: ", dqmUserRoels)
    

      


    Where

    var dqmUserRole3 DqmUserRole
    // 根据条件查询得到满足条件的第一条记录
    db.Where("role_id = ?", "2").First(&dqmUserRole3)
    fmt.Println("where roleId: ", dqmUserRole3.RoleId)
    
    var dqmUserRoles4 []DqmUserRole
    // 根据条件查询得到满足条件的所有记录
    db.Where("user_id = ?", "1").Find(&dqmUserRoles4)
    fmt.Println("where dqmUserRoles: ", dqmUserRoles4)
    
    var dqmUserRole5 []DqmUserRole
    // like模糊查询
    db.Where("role_id like ?", "%2").Find(&dqmUserRole5)
    fmt.Println("where dqmUserRoles: ", dqmUserRole5)
    
    var dqmUserRole6 []DqmUserRole
    db.Where("updated_at > ?", "2019-02-08 18:08:27").Find(&dqmUserRole6)
    fmt.Println("where dqmUserRoles: ", dqmUserRole6)
    
    var dqmUserRole7 DqmUserRole
    // struct结构查询条件
    db.Where(&DqmUserRole{RoleId: "1,2", UserId: "1"}).First(&dqmUserRole7)
    fmt.Println("where dqmUserRole: ", dqmUserRole7)
    
    var dqmUserRole8 DqmUserRole
    // map结构查询条件
    db.Where(map[string]interface{}{"role_id": "1,2", "user_id": "1"}).Find(&dqmUserRole8)
    fmt.Println("where dqmUserRole: ", dqmUserRole8)
    

      

    Not

    var dqmUserRole9 DqmUserRole
    db.Not([]int64{1}).First(&dqmUserRole9)
    fmt.Println("not dqmUserRole: ", dqmUserRole9)
    

      

    Or

    var dqmUserRole10 []DqmUserRole
    db.Where(&DqmUserRole{RoleId: "1,2"}).Or(map[string]interface{}{"user_id": "2"}).Find(&dqmUserRole10)
    fmt.Println("or dqmUserRoles: ", dqmUserRole10)
    

      

    FirstOrInit和Attrs

    var dqmUserRole11 DqmUserRole
    // 查不到该条记录,则使用attrs值替换
    db.Where("user_id = ?", "0").Attrs("role_id", "12").FirstOrInit(&dqmUserRole11)
    fmt.Println("after FirstOrInit: ", dqmUserRole11)
    
    var dqmUserRole12 DqmUserRole
    // 查到记录,则使用数据库中的值
    db.Where("user_id = ?", "1").Attrs("role_id", "2").FirstOrInit(&dqmUserRole12)
    fmt.Println("after FirstOrInit: ", dqmUserRole12)
    

      

    FirstOrInit和Assign

    var dqmUserRole13 DqmUserRole
    // 不管是否找到对应记录,使用Assign值替代查询到的值
    db.Where("role_id = ?", "1,2").Assign(DqmUserRole{UserId: "15"}).FirstOrInit(&dqmUserRole13)
    fmt.Println("assign dqmUserRole: ", dqmUserRole13)
    

      

    FirstOrCreate

    var dqmUserRole14 DqmUserRole
    // 如果记录存在则返回结果,如果不存在则创建
    db.Where(&DqmUserRole{UserId: "3", RoleId: "3"}).FirstOrCreate(&dqmUserRole14)
    fmt.Println("firstOrCreate dqmUserRole: ", dqmUserRole14)
    

      

    Order

    var dqmUserRole16 []DqmUserRole
    db.Order("user_id desc").Find(&dqmUserRole16) // 注意这里的order要在find前面,否则不生效
    fmt.Println("order dqmUserRoles: ", dqmUserRole16)
    

      

    Limit和Offset

    var dqmUserRole18 []DqmUserRole
    db.Limit(10).Offset(2).Find(&dqmUserRole18) // 如果只有offset没有limit则不会生效
    fmt.Println("offset dqmUserRoles: ", dqmUserRole18)
    

      

    Scan

    type Result struct {
            Id int64
        }
    var results []Result
    db.Select("id").Where("user_id in (?)", []string{"1", "2"}).Find(&dqmUserRole20).Scan(&results)
    fmt.Println("ids: ", results)
    

      

    支持执行原生sql

    var dqmUserRole24 []DqmUserRole
    db.Exec("select * from dqm_user_role").Find(&dqmUserRole24)
    fmt.Println("sql dqmUserRole: ", dqmUserRole24)

    事务

    tx := db.Begin()
    defer func() {
        if r := recover(); r != nil {
        tx.Rollback()
    }
    if err != nil {
        tx.Rollback()
    } else {
        tx.Commit()
    }
    }()
    if err = tx.Create(&DqmUserRole{UserId: "8", RoleId: "8"}).Error; err != nil {
      //tx.Rollback()
        //return
    }
    
    if err = tx.Create(&DqmUserRole{UserId: "9", RoleId: "9"}).Error; err != nil {
        //tx.Rollback()
        //return
    }
    

      

    错误处理

    var dqmUserRole25 DqmUserRole
    err = db.Where("role_id = ?", 54321).First(&dqmUserRole25).Error
    if err == gorm.ErrRecordNotFound {
      fmt.Println("ErrRecordNotFound, record not found")
    } else {
      fmt.Println("err: ", err)
    }
    fmt.Println("err dqmUserRole: ", dqmUserRole25)
    

      

    5、总结

    gorm作为一款orm库,几乎满足了一个CRUDer的一切想象。实现灵活,花样繁多。

    有了gorm,就不需要再在代码中维护sql语句了。


    链接:https://www.jianshu.com/p/1513f55f8192

  • 相关阅读:
    PAT B1045 快速排序 (25 分)
    PAT B1042 字符统计 (20 分)
    PAT B1040 有几个PAT (25 分)
    PAT B1035 插入与归并 (25 分)
    PAT B1034 有理数四则运算 (20 分)
    PAT B1033 旧键盘打字 (20 分)
    HDU 1231 最大连续子序列
    HDU 1166 敌兵布阵
    HDU 1715 大菲波数
    HDU 1016 Prime Ring Problem
  • 原文地址:https://www.cnblogs.com/akidongzi/p/11949813.html
Copyright © 2011-2022 走看看