使用 GORM(Go 的 ORM 库)连接数据库,并实现增删改查操作,把实现过程整理成文章;

146 阅读3分钟

一、gorm简介

golang使用数据库服务一般要到标准库的database/sql 和 database/sqldrivers,标准库的使用一般涉及到写sql语句、Query可以查询多行、QueryRow查询特定的行、Exec 执行更新插入删除操作等。使用传统的方法需要先在database中创建好表,而gorm可以通过定义Model的形式很方便的创建或修改数据库表的结构。 除了封装以外,gorm添加了自己独特的特性:

  • 全功能 ORM
  • 关联 (Has One,Has Many,Belongs To,Many To Many,多态,单表继承)
  • Create,Save,Update,Delete,Find 中钩子方法
  • 支持 PreloadJoins 的预加载
  • 事务,嵌套事务,Save Point,Rollback To Saved Point
  • Context、预编译模式、DryRun 模式
  • 批量插入,FindInBatches,Find/Create with Map,使用 SQL 表达式、Context Valuer 进行 CRUD
  • SQL 构建器,Upsert,数据库锁,Optimizer/Index/Comment Hint,命名参数,子查询
  • 复合主键,索引,约束
  • Auto Migration
  • 自定义 Logger
  • 灵活的可扩展插件 API:Database Resolver(多数据库,读写分离)、Prometheus…
  • 每个特性都经过了测试的重重考验
  • 开发者友好

本文通过实践介绍gorm的基本使用方法

二、安装gorm

go get -u gorm.io/gorm 
go get -u gorm.io/driver/sqlite 

三、定义表结构

使用gorm实现一个简单的场景:某主播喜欢通过vlog记录自己的生活,他会上传自己的视频,而其他用户可以看到该视频并且可以给他点赞。他希望使用数据库查询自己发布了哪些视频,并且自己的总点赞数是多少。

定义:


type Video struct {
   ID          int64     `json:"id"`
   AuthorID    int64     `json:"author_id"`
   PublishTime time.Time `json:"publish_time"`
   Title       string    `json:"title"`
}

// 表示某用户给某个视频点赞
type Favorites struct {
   ID        int64          `json:"id"`
   UserId    int64          `json:"user_id"`
   VideoId   int64          `json:"video_id"`
}

四、连接数据库并创建表

// 打开数据库连接
dbConn, err = gorm.Open(mysql.Open(MySQLDSN), &gorm.Config{
   PrepareStmt:            true,
   SkipDefaultTransaction: true,
})
if err != nil {
   panic(err)
}

// 创建数据库表
if !dbConn.Migrator().HasTable(&Favorites{}) {
   err = dbConn.Migrator().CreateTable(&Favorites{})
   if err != nil {
      panic(err)
   }
}

if !DB.Migrator().HasTable(&Video{}) {
   err = DB.Migrator().CreateTable(&Video{})
   if err != nil {
      panic(err)
   }
}

五、 CRUD

添加数据

此时我们可以适当向Video表和Favorite表添加几条信息, 表示用户1 发布了两条视频(id分别为1 和 2), 用户2 发布视频(id为3)。用户1 视频3点赞,用户2给视频1和2点赞。

videos := []*Video{
    {AuthorID: 1, PublishTime: time.Now().Unix(), Title: "test1"},
    {AuthorID: 1, PublishTime: time.Now().Unix(), Title: "test2"},
    {AuthorID: 2, PublishTime: time.Now().Unix(), Title: "test3"},
}

favorites := []*Favorite{
    {UserId: 1, VideoId: 3},
    {UserId: 2, VideoId: 1},
    {UserId: 2, VideoId: 2},
}

查询数据

查询id为2的视频 查询单个对象:

var video Video
方法一:
err := DB.First(&video, 2).Error
// 注意该方法在找不到记录时会返回gorm.ErrRecordNotFound, 因此我们要先检查该类型的错误

if err == gorm.ErrRecordNotFound {
    // 找不到记录时的逻辑
}

if err != nil {...}

方法二:
err := DB.Limit(1).Find(&video, 2).Error
if err != nil {...}

查询多个对象:

var videos []*Video
err := DB.Where("AuthorId = ?", 1).Find(&videos).Error
if err != nil {...}

多表查询:


子查询方式:
err := dbConn.WithContext(ctx).Where("video_id in (?)",
   dbConn.WithContext(ctx).Table(constants.VideoTableName).Where("author_id = ?", authorId).Select("video_id")).Find(&favorites).Error
if err != nil {...}

join方式:
  err := dbConn.WithContext(ctx).Table(constants.FavoriteTableName).
    Joins("JOIN videos ON favorites.video_id = videos.id").
    Where("videos.author_id = ?", authorId).Count(&sum).Error
if err != nil {...}

删除数据

var video Video
err := dbConn.Where("AuthorId = ?", 1).Delete(&video)

更新数据


方法一:
video := Video{ID: 1, AuthorID: 4, PublishTime: time.Now().Unix(), Title: "test4"}
DB.Model(&Video{}).Updates(video)
// 该方式下不会更新零值字段

方法二:
DB.Model(&video).Updates(map[string]interface{}{"AuthorId": 3}

结语

官网地址:GORM 指南 | GORM - The fantastic ORM library for Golang, aims to be developer friendly.