使用 GORM(Go 的 ORM 库)连接数据库,并实现增删改查操作 | 青训营

221 阅读5分钟

GORM 连接数据库,实现增删改查操作

1. gorm

gorm是Golang语言中一个已经迭代数十年且功能强大、性能极好的ORM框架。

ORM: Object–relational mapping,即对象关系映射,是一种用于在关系数据库和面向对象的编程语言堆之间转换数据的编程技术。通过 ORM 技术,我们可以将关系数据库中某个数据表的结构关联到某个类/结构体上,并通过修改类/结构体实例的方式轻易的完成数据库增删改查(CRUD)的任务。通过 ORM 技术,我们得以用一种更加友好且高效的方式,在尽量不接触 SQL 语句的情况下操作数据库

设计简洁、功能强大、自由扩展的全功能ORM

  • 设计原则: API精简、测试优先、最小惊讶、灵活扩展、无依赖可信赖
  • 功能完善:
    • 关联:一对一、一对多、单表自关联、多态;Preload、 Joins 预加载、级联删除;关联模式;自定义关联表
    • 事务:事务代码块、嵌套事务、Save Point
    • 多数据库、读写分离、命名参数、Map、子查询、分组条件、代码共享、SQL表达式(查询、创建、更新)、自动选字段、查询优化器
    • 字段权限、软删除、批量数据处理、Prepared Stmt、自定义类型、命名策略、虚拟字段、自动track时间、SQL Builder、Logger
    • 代码生成、复合主键、Constraint、 Prometheus、 Auto Migration、真 跨数据库兼容...
    • 多模式灵活自由扩展
    • Developer Friendly

2. 环境配置

  • linux虚拟机:Ubuntu2004

  • Vscode SSH 连接虚拟机

  • Docker 安装: 更新apt:

    sudo apt-get update
    sudo apt-get upgrade
    

    使用官方脚本自动安装配置Docker (这里注意使用了Aliyun镜像,官方的源感觉下不动 换源之后很快就好了)

    curl -fsSL get.docker.com -o get-docker.sh
    sudo sh get-docker.sh --mirror Aliyun
    
  • Docker内安装mysql

    docker pull mysql 
    #默认拉取 latest 8.x 可以指定
    
    docker images 
    #查看mysql镜像是否已安装
    

    运行镜像:

    docker run -p 3306:3306 --name mysql --restart=always --privileged=true \
    -v /usr/local/mysql/log:/var/log/mysql \
    -v /usr/local/mysql/data:/var/lib/mysql \
    -v /usr/local/mysql/conf:/etc/mysql \
    -v /etc/localtime:/etc/localtime:ro \
    -e MYSQL_ROOT_PASSWORD=123456 -d mysql:latest
    

    使用docker-compose.yml配置启动更加方便:

    docker compose --profile dev up -d
    # 启动
    docker compose down
    # 关闭
    

    docker-compose.yml:

    version: '3'
    services:
      mysql:
      image: 'mysql:latest'
      container_name: tiktok_mysql
      volumes:
        - ./docker/mysql/sql:/docker-entrypoint-initdb.d
      ports:
        - "12000:3306"
      environment:
        - MYSQL_DATABASE=mini_tiktok
        - MYSQL_USER=mini_tiktok_user
        - MYSQL_PASSWORD=mini_tiktok_pass
        - MYSQL_RANDOM_ROOT_PASSWORD="yes"
      restart: always
      profiles:
        - dev
        - release
    
  • gorm 安装

3. gorm基本使用

juejin.cn/post/726613…

4. gorm实践

项目需求是使用MySql存储user对于video的点赞数据,点赞即增加一条记录,取消点赞即删除一条记录,需要提供增删查的功能

4.1 实现代码

连接数据库与初始化:

package db

import (
	"github.com/HUST-MiniTiktok/mini_tiktok/pkg/conf"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	gormopentracing "gorm.io/plugin/opentracing"
)

var DB       *gorm.DB

// Init Mysql DB
func Init() {
	var err error
	DB, err = gorm.Open(mysql.Open(conf.GetConf().GetString("db.mysql.dsn")),
		&gorm.Config{
			PrepareStmt:            true,
			SkipDefaultTransaction: true,
		},
	)
	if err != nil {
		panic(err)
	}

	if err = DB.Use(gormopentracing.New()); err != nil {
		panic(err)
	}

	DB.AutoMigrate(&Favorite{}) // 建表
}

点赞数据的结构:也可以使用gorm.model

type Favorite struct {
	ID        int64          `json:"id"`
	UserId    int64          `json:"user_id"`
	VideoId   int64          `json:"video_id"`
	CreatedAt time.Time      `json:"create_at"`
	DeletedAt gorm.DeletedAt `gorm:"index" json:"delete_at"`
}

查找操作:检查是否已点赞。使用first时,没有找到记录时,它会返回 ErrRecordNotFound 错误。这里使用Limit(1).Find来检查记录是否已经存在

func CheckFavorite(ctx context.Context, user_id int64, video_id int64) (status bool, err error) {
	var db_favorite Favorite
	err = DB.WithContext(ctx).Model(&Favorite{}).Where("user_id = ? and video_id = ?", user_id, video_id).Limit(1).Find(&db_favorite).Error
	if err != nil {
		return false, err
	}
	return db_favorite != Favorite{}, nil
}

增操作:点赞操作即新增点赞数据记录。需要检查是否已经存在点赞记录,避免重复点赞

func NewFavorite(ctx context.Context, user_id int64, video_id int64) (status int32, err error) {
  favorite := Favorite{
      UserId:  user_id,
      VideoId: video_id}

  err = DB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
    status, err := CheckFavorite(ctx, user_id, video_id)
    if err != nil { 
      return err
    }
    if status { // 重复点赞
      return nil
    }

    if err := tx.WithContext(ctx).Model(&Favorite{}).Create(&favorite).Error; err != nil {
      return err
    }
    return nil
  })

  if err != nil {
    return 1, err
  }
  return 0, nil
}

删操作:取消点赞即删除点赞记录(软删除)

func CancelFavorite(ctx context.Context, user_id int64, video_id int64) (status int32, err error) {
	var favorite Favorite
	err = DB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		//通过user_id和video_id找到要删除的favorite记录
		if err := tx.WithContext(ctx).Model(&Favorite{}).Where(&Favorite{UserId: user_id, VideoId: video_id}).Scan(&favorite).Error; err != nil {
			return err
		}

		if err := tx.WithContext(ctx).Model(&Favorite{}).Delete(&favorite).Error; err != nil { //软删除这条favorite记录
			return err
		}
		return nil
	})

	if err != nil {
		return 1, err
	}
	return 0, nil
}

计数操作:获取一个视频的点赞数。计数VideoId字段为目标video的记录

func VideoFavoriteCount(ctx context.Context, video_id int64) (count int64, err error) {
	err = DB.WithContext(ctx).Model(&Favorite{}).Where(&Favorite{VideoId: video_id}).Count(&count).Error
	if err != nil {
		return 0, err
	}

	return count, nil
}

4.2 运行测试

编写测试函数,对db操作函数进行测试。

测试点赞检查

func TestCheckFavorite(t *testing.T) {
	ctx := context.Background()
	Init()
	exist, err := CheckFavorite(ctx, 1, 1)
	log.Println(exist)
	log.Println(err)
	NewFavorite(ctx, 1, 1)
	exist, err = CheckFavorite(ctx, 1, 1)
	log.Println(exist)
	log.Println(err)
	CancelFavorite(ctx, 1, 1)
	exist, err = CheckFavorite(ctx, 1, 1)
	log.Println(exist)
	log.Println(err)
}

根据打印结果可以判断点赞、取消点赞、检查点赞操作正确 2023-08-21-11-20-51.png

测试点赞计数

func TestVideoFavoriteCount(t *testing.T) {
	ctx := context.Background()
	Init()
	count, err := VideoFavoriteCount(ctx, 1)
	log.Println(count)
	log.Println(err)
	count, err = VideoFavoriteCount(ctx, 2)
	log.Println(count)
	log.Println(err)

	NewFavorite(ctx, 1, 1)
	NewFavorite(ctx, 1, 2)
	NewFavorite(ctx, 2, 1)
	NewFavorite(ctx, 2, 2)
	count, err = VideoFavoriteCount(ctx, 1)
	log.Println(count)
	log.Println(err)
	count, err = VideoFavoriteCount(ctx, 2)
	log.Println(count)
	log.Println(err)

	CancelFavorite(ctx, 1, 1)
	CancelFavorite(ctx, 2, 1)
	CancelFavorite(ctx, 1, 2)
	CancelFavorite(ctx, 2, 2)
	count, err = VideoFavoriteCount(ctx, 1)
	log.Println(count)
	log.Println(err)
	count, err = VideoFavoriteCount(ctx, 2)
	log.Println(count)
	log.Println(err)
	count, err = VideoFavoriteCount(ctx, 3)
	log.Println(count)
	log.Println(err)
}

根据打印结果可以判断点赞计数操作正确 2023-08-21-11-24-52.png

总结

在视频课程中学习了Gorm的基本使用和需要注意的点,做了一些笔记

这里结合项目实际需求,对 GORM 连接 MySql 数据库,实现增删改查操作进行了实践。整体感觉,Gorm的使用还是相当便利的。