Gorm连接以及CURD实战+测试

Gorm CRUD

前言

Gormgo的一个ORM框架,官方文档地址为-> GORM 指南

本文将介绍与gorm有关的CRUD操作,操作数据库类型为mysql数据库

数据库连接

func Open(dialector Dialector, opts …Option) (db *DB, err error)

该函数用于进行gorm连接对应数据库

输入 go get -u "gorm.io/gorm" 下载gorm库
输入 go get -u gorm.io/driver/mysql 即可下载mysql驱动

对于mysql的连接,还需要引入gorm的mysql驱动,否则没有Open这个函数

var gormDb *gorm.DB

func initGormDB() {
	var err error
	gormDb, err = gorm.Open(
		mysql.Open("root:xxxxxx@tcp(127.0.0.1:3306)/go_db?charset=utf8mb4&parseTime=True&loc=Local"),
		&gorm.Config{
			PrepareStmt:            true, //缓存预编译命令
			SkipDefaultTransaction: true, //禁用默认事务操作
		},
	)
	if err != nil {
		// 这里因为是panic所以可以直接进行赋值操作,如果不是panic需要在错误之后才能进行赋值给全局变量
		panic(err)
	}
	fmt.Println("gormDb connection success~")
}
下图将给出gormConfig的配置

在这里插入图片描述

支持自定义logger,但是需要实现对应接口的方法

// Interface logger interface
type Interface interface {
   LogMode(LogLevel) Interface
   Info(context.Context, string, ...interface{})
   Warn(context.Context, string, ...interface{})
   Error(context.Context, string, ...interface{})
   Trace(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error)
}

因为gorm底层是通过使用 database/sql 维护连接池

因此可以获取sqlDB,然后设置连接池

sqlDB, err := gormDb.DB()

// SetMaxIdleConns 设置空闲连接池中连接的最大数量
sqlDB.SetMaxIdleConns(10)

// SetMaxOpenConns 设置打开数据库连接的最大数量。
sqlDB.SetMaxOpenConns(100)

// SetConnMaxLifetime 设置了连接可复用的最大时间。
sqlDB.SetConnMaxLifetime(time.Hour)

数据库迁移

下图是gorm中关于数据库迁移的源代码,给出了自动迁移和手动迁移两种方案,而自动迁移其实和手动迁移没有区别。

// Migrator returns migrator
func (db *DB) Migrator() Migrator {
   tx := db.getInstance()

   // apply scopes to migrator
   for len(tx.Statement.scopes) > 0 {
      scopes := tx.Statement.scopes
      tx.Statement.scopes = nil
      for _, scope := range scopes {
         tx = scope(tx)
      }
   }

   return tx.Dialector.Migrator(tx.Session(&Session{}))
}

// AutoMigrate run auto migration for given models
func (db *DB) AutoMigrate(dst ...interface{}) error {
   return db.Migrator().AutoMigrate(dst...)
}

迁移数据库

结构体中要嵌套gorm的Model结构体,用于管理软删除和时间

type Model struct {
   ID        uint `gorm:"primarykey"`
   CreatedAt time.Time
   UpdatedAt time.Time
   DeletedAt DeletedAt `gorm:"index"`
}
type GormUser struct {
   gorm.Model
	Age      int    `gorm:"age"`
	Name     string `gorm:"name"`
	Password string `gorm:"password"`
}

// Migrant 数据库迁移
func Migrant() error {
   return gormDb.AutoMigrate(&GormUser{})
}

在tag处可以选择gorm中的字段名,我这里只做演示操作,数据与实际开发并不相符

测试

使用 go test -run=Migrant -v 该命令可以详细打印出测试结果

func TestMain(m *testing.M) {
   initGormDB()
   code := m.Run()
   os.Exit(code)
}

func TestMigrant(t *testing.T) {
   err := Migrant()
   if err != nil {
      t.Errorf("Migrant fail,%v", err)
   }
}

在这里插入图片描述

CRUD实战

创建

func (db *DB) Create(value interface{}) (tx *DB)

增加一条用户信息
// GormCreate gorm 创建数据
func GormCreate() error {
   u := GormUser{
      Name:     "张三",
      Age:      15,
      Password: "qwer",
   }
   return gormDb.Create(&u).Error
}

在这里插入图片描述

测试

go test -run=GormCreate -v

func TestGormCreate(t *testing.T) {
   err := GormCreate()
   if err != nil {
      t.Errorf("Migrant fail,%v", err)
   }
}

在这里插入图片描述

增加多条用户信息

通过切片或者数组的方式插入多条数据

// GormCreateMore gorm 创建多条数据
func GormCreateMore() error {
   u := GormUser{
      Name:     "张三",
      Age:      15,
      Password: "qwer",
   }
   u2 := GormUser{
      Name:     "李四",
      Age:      16,
      Password: "qwer",
   }
   u3 := GormUser{
      Name:     "王五",
      Age:      17,
      Password: "qwer",
   }
   uu := [...]GormUser{u, u2, u3}
   return gormDb.Create(&uu).Error
}
测试
func TestGormCreateMore(t *testing.T) {
   err := GormCreateMore()
   if err != nil {
      t.Errorf("Migrant fail,%v", err)
   }
}

在这里插入图片描述

删除

func (db *DB) Delete(value interface{}, conds …interface{}) (tx *DB)

gorm中有两种删除方法

  • 硬删除,直接通过结构体中的字段值进行删除
  • 条件删除,先进行where查询然后删除
// GormDelete gorm 删除数据
func GormDelete() error {
   // 直接删除
   gormDb.Delete(&GormUser{Name: "张三"})
   // 条件删除 
   return gormDb.Where("name = ?", "张三").Delete(&GormUser{}).Error
}
测试

这里出错是因为我删除了两次

func TestGormDelete(t *testing.T) {
   err := GormDelete()
   if err != nil {
      t.Errorf("Migrant fail,%v", err)
   }
}

在这里插入图片描述

gorm中删除使用的是软删除,好处是不会产生碎片化数据,方便维护。
在这里插入图片描述

修改

修改的方法起码有四种,两种批量修改,两种单行修改。还可以进行保存

在这里插入图片描述

保存修改
u := GormUser{}
//先查询一条记录, 保存在模型变量u
//等价于: SELECT * FROM `gorm_users`  WHERE (id = '2') LIMIT 1
db.Where("id = ?", 3).Take(&u)
u.age = 100
db.Save(&u)
直接修改

Model用于绑定操作的数据库

gormDb.Model(&GormUser{}).Update("age", 25).Where("id", 3).Error

在这里插入图片描述

显然该操作不行,报错说该操作没有where,因此可以得出where语句必须要在Update之前。所以我们可以再尝试一次

gormDb.Model(&GormUser{}).Where("id", 3).Update("age", 25).Error

在这里插入图片描述

测试成功

查询

func (db *DB) First(dest interface{}, conds …interface{}) (tx *DB)
First finds the first record ordered by primary key, matching given conditions conds

First 用来查询单条数据,对所有数据进行正序排序并且放回第一条

等价于:SELECT * FROM gorm_users ORDER BY gorm_users.id ASC LIMIT 1

// GormQuery gorm 查询数据
func GormQuery(u *GormUser) error {
   return gormDb.First(u).Error
    // gormDb.Last(u).Error Last与First刚好相反(逆序排列),就不再测试了
}
测试
func TestGormQuery(t *testing.T) {
   u := GormUser{}
   err := GormQuery(&u)
   if err != nil {
      t.Errorf("gormQuery fail,%v", err)
   }
   t.Logf("gormUser first, data: %v", u)
}

在这里插入图片描述

func (db *DB) Take(dest interface{}, conds …interface{}) (tx *DB)
Take finds the first record returned by the database in no specified order, matching given conditions conds

Take 查询单条

等价于:SELECT * FROM gorm_users LIMIT 1

指定查询单条数据并返回查询行数
// GormQuery gorm 查询数据
func GormQuery(u *GormUser) (cnt int64, err error) {
   err = gormDb.Where("age = ?", 18).Count(&cnt).First(u).Error
   return
}

在这里插入图片描述

查询失败的原因是需要Model,或者Table,提前指定表名。因此我们加上之后可以再次尝试

// GormQuery gorm 查询数据
func GormQuery(u *GormUser) (cnt int64, err error) {
   err = gormDb.Model(&GormUser{}).Where("age = ?", 18).Count(&cnt).First(u).Error
   return
}
测试
func TestGormQuery(t *testing.T) {
   u := GormUser{}
   rowNum, err := GormQuery(&u)
   if err != nil {
      t.Errorf("gormQuery fail,%v", err)
   }
   t.Logf("gormUser first, data: %v\n", u)
   t.Logf("gormQuery method queryRows = %d", rowNum)
}

在这里插入图片描述

查到了三条数据,但我用的First,因此只返回一条数据。

查询多条数据

func (db *DB) Find(dest interface{}, conds …interface{}) (tx *DB)

Find finds all records matching given conditions conds

Find 用于查询多条数据

// GormQueryMore gorm 查询多条数据
func GormQueryMore(u []*GormUser) (cnt int64, err error) {
   err = gormDb.Model(&GormUser{}).Where("age = ?", 18).Count(&cnt).Find(u).Error
   return
}
测试
func TestGormQueryMore(t *testing.T) {
   u := make([]*GormUser, 3)
   rowNum, err := GormQueryMore(u)
   if err != nil {
      t.Errorf("gormQuery fail,%v", err)
   }
   for i, v := range u {
      t.Logf("gormUser first,第%d条数据, data: %v\n", i, v)
   }
   t.Logf("gormQuery method queryRows = %d", rowNum)
}

在这里插入图片描述

小结

gorm底层仍然是database/sql,因此原生的sql方法仍然能够被使用。对于gorm的CRUD简单操作就介绍到这里了。如果感兴趣的话可以到gorm的官网更深入的研究。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

捶捶自己

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值