Go组件学习——gorm四步带你搞定DB增删改查

2019年8月4日 376点热度 0人点赞 0条评论

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库

  1. go get -u github.com/jinzhu/gorm

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

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

  1. github.com/jinzhu/gorm v1.9.10

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

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

2.2 创建DB连接

建立数据库连接

  1. package main

  2. import (

  3. "github.com/jinzhu/gorm"

  4. _ "github.com/jinzhu/gorm/dialects/mysql"

  5. )

  6. func main() {

  7. var err error

  8. db, connErr := gorm.Open("mysql", "root:rootroot@/dqm?charset=utf8&parseTime=True&loc=Local")

  9. if connErr != nil {

  10. panic("failed to connect database")

  11. }

  12. defer db.Close()

  13. db.SingularTable(true)

  14. }

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

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

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

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

2.3 创建映射表结构的struct

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

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

  1. CREATE TABLE `test` (

  2. `id` bigint(20) NOT NULL,

  3. `name` varchar(5) DEFAULT NULL,

  4. `age` int(11) DEFAULT NULL,

  5. PRIMARY KEY (`id`)

  6. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci

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

  1. type Test struct {

  2. ID int64 `gorm:"type:bigint(20);column:id;primary_key"`

  3. Name string `gorm:"type:varchar(5);column:name"`

  4. Age int `gorm:"type:int(11);column:age"`

  5. }

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

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

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

2.4 CRUD

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

比如"增"

  1. test := &Test{

  2. ID:3,

  3. Name:"jackie",

  4. Age:18,

  5. }

  6. db.Create(test)

比如"删"

  1. test := &Test{

  2. ID:3,

  3. Name:"jackie",

  4. Age:18,

  5. }

  6. db.Delete(test)

比如"改"

  1. test := &Test{

  2. ID: 3,

  3. Name: "hello",

  4. Age: 18,

  5. }

  6. db.Model(&test).Update("name", "world")

比如"查"

  1. var testResult Test

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

  3. 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方法

  1. func (Test) TableName() string {

  2. return "test"

  3. }

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

  1. type tabler interface {

  2. TableName() string

  3. }

3.3 通过Table API声明

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

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

4、其他花式操作

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

  1. type DqmUserRole struct {

  2. ID int64 `gorm:"column:id;primary_key" json:"id"`

  3. UserId string `gorm:"column:user_id" json:"user_id"`

  4. RoleId string `gorm:"column:role_id" json:"role_id"`

  5. CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`

  6. UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`

  7. }

表中初始数据如下 

图片

以下API均亲测可用

First

  1. var dqmUserRole DqmUserRole

  2. // 按照主键顺序的第一条记录

  3. db.First(&dqmUserRole)

  4. fmt.Println("roleId: ", dqmUserRole.RoleId)

Last

  1. var dqmUserRole1 DqmUserRole

  2. // 按照主键顺序的最后一条记录

  3. db.Last(&dqmUserRole1)

  4. fmt.Println("roleId: ", dqmUserRole1.RoleId)

Find

  1. var dqmUserRoels []DqmUserRole

  2. // 所有记录

  3. db.Find(&dqmUserRoels)

  4. fmt.Println("dqmUserRoles: ", dqmUserRoels)

Where

  1. var dqmUserRole3 DqmUserRole

  2. // 根据条件查询得到满足条件的第一条记录

  3. db.Where("role_id = ?", "2").First(&dqmUserRole3)

  4. fmt.Println("where roleId: ", dqmUserRole3.RoleId)

  5. var dqmUserRoles4 []DqmUserRole

  6. // 根据条件查询得到满足条件的所有记录

  7. db.Where("user_id = ?", "1").Find(&dqmUserRoles4)

  8. fmt.Println("where dqmUserRoles: ", dqmUserRoles4)

  9. var dqmUserRole5 []DqmUserRole

  10. // like模糊查询

  11. db.Where("role_id like ?", "%2").Find(&dqmUserRole5)

  12. fmt.Println("where dqmUserRoles: ", dqmUserRole5)

  13. var dqmUserRole6 []DqmUserRole

  14. db.Where("updated_at > ?", "2019-02-08 18:08:27").Find(&dqmUserRole6)

  15. fmt.Println("where dqmUserRoles: ", dqmUserRole6)

  16. var dqmUserRole7 DqmUserRole

  17. // struct结构查询条件

  18. db.Where(&DqmUserRole{RoleId: "1,2", UserId: "1"}).First(&dqmUserRole7)

  19. fmt.Println("where dqmUserRole: ", dqmUserRole7)

  20. var dqmUserRole8 DqmUserRole

  21. // map结构查询条件

  22. db.Where(map[string]interface{}{"role_id": "1,2", "user_id": "1"}).Find(&dqmUserRole8)

  23. fmt.Println("where dqmUserRole: ", dqmUserRole8)

Not

  1. var dqmUserRole9 DqmUserRole

  2. db.Not([]int64{1}).First(&dqmUserRole9)

  3. fmt.Println("not dqmUserRole: ", dqmUserRole9)

Or

  1. var dqmUserRole10 []DqmUserRole

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

  3. fmt.Println("or dqmUserRoles: ", dqmUserRole10)

FirstOrInit和Attrs

  1. var dqmUserRole11 DqmUserRole

  2. // 查不到该条记录,则使用attrs值替换

  3. db.Where("user_id = ?", "0").Attrs("role_id", "12").FirstOrInit(&dqmUserRole11)

  4. fmt.Println("after FirstOrInit: ", dqmUserRole11)

  5. var dqmUserRole12 DqmUserRole

  6. // 查到记录,则使用数据库中的值

  7. db.Where("user_id = ?", "1").Attrs("role_id", "2").FirstOrInit(&dqmUserRole12)

  8. fmt.Println("after FirstOrInit: ", dqmUserRole12)

FirstOrInit和Assign

  1. var dqmUserRole13 DqmUserRole

  2. // 不管是否找到对应记录,使用Assign值替代查询到的值

  3. db.Where("role_id = ?", "1,2").Assign(DqmUserRole{UserId: "15"}).FirstOrInit(&dqmUserRole13)

  4. fmt.Println("assign dqmUserRole: ", dqmUserRole13)

FirstOrCreate

  1. var dqmUserRole14 DqmUserRole

  2. // 如果记录存在则返回结果,如果不存在则创建

  3. db.Where(&DqmUserRole{UserId: "3", RoleId: "3"}).FirstOrCreate(&dqmUserRole14)

  4. fmt.Println("firstOrCreate dqmUserRole: ", dqmUserRole14)

Order

  1. var dqmUserRole16 []DqmUserRole

  2. db.Order("user_id desc").Find(&dqmUserRole16) // 注意这里的order要在find前面,否则不生效

  3. fmt.Println("order dqmUserRoles: ", dqmUserRole16)

Limit和Offset

  1. var dqmUserRole18 []DqmUserRole

  2. db.Limit(10).Offset(2).Find(&dqmUserRole18) // 如果只有offset没有limit则不会生效

  3. fmt.Println("offset dqmUserRoles: ", dqmUserRole18)

Scan

  1. type Result struct {

  2. Id int64

  3. }

  4. var results []Result

  5. db.Select("id").Where("user_id in (?)", []string{"1", "2"}).Find(&dqmUserRole20).Scan(&results)

  6. fmt.Println("ids: ", results)

支持执行原生sql

  1. var dqmUserRole24 []DqmUserRole

  2. db.Exec("select * from dqm_user_role").Find(&dqmUserRole24)

  3. fmt.Println("sql dqmUserRole: ", dqmUserRole24)

事务

  1. tx := db.Begin()

  2. defer func() {

  3. if r := recover(); r != nil {

  4. tx.Rollback()

  5. }

  6. if err != nil {

  7. tx.Rollback()

  8. } else {

  9. tx.Commit()

  10. }

  11. }()

  12. if err = tx.Create(&DqmUserRole{UserId: "8", RoleId: "8"}).Error; err != nil {

  13. //tx.Rollback()

  14. //return

  15. }

  16. if err = tx.Create(&DqmUserRole{UserId: "9", RoleId: "9"}).Error; err != nil {

  17. //tx.Rollback()

  18. //return

  19. }

错误处理

  1. var dqmUserRole25 DqmUserRole

  2. err = db.Where("role_id = ?", 54321).First(&dqmUserRole25).Error

  3. if err == gorm.ErrRecordNotFound {

  4. fmt.Println("ErrRecordNotFound, record not found")

  5. } else {

  6. fmt.Println("err: ", err)

  7. }

  8. fmt.Println("err dqmUserRole: ", dqmUserRole25)

5、总结

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

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

后面有时间会再看看gorm的实现,作为国人开源的第一个orm库,目前star已经超过15k,值得深入学习下。

14320Go组件学习——gorm四步带你搞定DB增删改查

root

这个人很懒,什么都没留下

文章评论