Golang 集成 gorm 简单使用 | 青训营笔记

170 阅读5分钟

gorm基础使用及解决部分疑惑

这是我参与「第三届青训营 -后端场」笔记创作活动的第4篇笔记。

01 简介

本文主要介绍在项目中集成 gorm 的大致方法、一些错误的解决方法、规范包及目录。

02 规范包及目录

这只是其中的一种分包方式,具体使用哪种可以根据自己需求。

 controller //处理函数
 ​
 dao //数据库相关,gorm相关接口
 ​
 router //路由
 ​
 model //生成数据表相关的结构体
 ​
 assets //静态资源
 ​
 templates //模板文件、HTML

03 集成gorm

这里分两种情况:

  1. 如果还未建表,可以先声明结构体数据之后再使用 gorm 自动建表功能。
  2. 若已经建好表了,则可以使用一些便捷的网站快速生成相应的结构体,然后再根据实际需求更改(比如外键)。

1.自动建表

1、go get 一下

我这里使用 mysql 所以执行go get -u gorm.io/driver/mysql.

如果你们使用其他数据库可以参考gorm官方文档:GORM 指南 | GORM - The fantastic ORM library for Golang, aims to be developer friendly.

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

2、声明结构体

在这一个案例中是还没有建表的。这里后面的字段不需要指定数据库列。后边使用 db.AutoMigrate(&model.User{}) 就可以自动建表

model.go

 package model
 ​
 import "gorm.io/gorm"
 ​
 type User struct {
     gorm.Model
     Username string `json:"username"`
     Password string `json:"password"`
 }

在dsn记得换上自己的 数据库密码 。

dao.go

 package dao
 ​
 import (
     "blog/model"
     "gorm.io/driver/mysql"
     "gorm.io/gorm"
     "log"
 )
 ​
 type Manager interface {
     AddUser(user *model.User)
 }
 ​
 type manager struct {
     db *gorm.DB
 }
 ​
 func (mgr manager) AddUser(user *model.User) {
     mgr.db.Create(user)
 }
 ​
 var Mgr Manager
 ​
 func init() {
     // 在dsn记得换上自己的 数据库密码 
     dsn := "root:xxxxxx@tcp(127.0.0.1:3306)/golang_blog?charset=utf8mb4&parseTime=True&loc=Local"
     db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
     if err != nil {
         log.Fatal("Failed to init db:", err)
     }
     Mgr = &manager{db: db}
     err1 := db.AutoMigrate(&model.User{})
     if err1 != nil {
         log.Fatal(err1)
     }
 }

main.go

 package main
 ​
 import (
     "blog/dao"
     "blog/model"
 )
 ​
 func main() {
     user := model.User{
         Username: "tom",
         Password: "123456",
     }
     dao.Mgr.AddUser(&user)
 }

测试

测试AddUser是否成功

 mysql> use golang_blog
 Database changed
 mysql> show tables;
 +-----------------------+
 | Tables_in_golang_blog |
 +-----------------------+
 | users                 |
 +-----------------------+
 1 row in set (0.00 sec)
 ​
 mysql> select * from users;
 +----+-------------------------+-------------------------+------------+----------+----------+
 | id | created_at              | updated_at              | deleted_at | username | password |
 +----+-------------------------+-------------------------+------------+----------+----------+
 |  1 | 2022-05-22 09:13:22.688 | 2022-05-22 09:13:22.688 | NULL       | tom      | 123456   |
 +----+-------------------------+-------------------------+------------+----------+----------+
 1 row in set (0.00 sec)

2.手动建表

这种情况先把SQL建表语句复制到这个网站:在线sql转go, json转go - 球儿工具 (qetool.com)

然后就可以愉快根据需要转成相应的结构体。

SQL转struct

1、Navicat 直接粘贴过来的 t_video 表的SQL :

 CREATE TABLE `t_video` (
   `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '视频id',
   `author_id` int(11) NOT NULL COMMENT '作者id',
   `play_url` varchar(512) NOT NULL COMMENT '视频播放地址',
   `cover_url` varchar(255) NOT NULL COMMENT '视频封面地址',
   `favorite_count` int(11) unsigned DEFAULT NULL COMMENT '视频的点赞总数',
   `comment_count` int(11) unsigned DEFAULT NULL COMMENT '视频的评论总数',
   `title` varchar(255) CHARACTER SET utf8 NOT NULL COMMENT '视频标题',
   `created_at` datetime DEFAULT NULL COMMENT '投稿时间',
   `deleted_at` datetime DEFAULT NULL COMMENT '删除时间',
   `updated_at` datetime DEFAULT NULL COMMENT '更新时间',
   `is_favorite` tinyint(1) DEFAULT NULL,
   PRIMARY KEY (`id`),
   KEY `author_id` (`author_id`),
   KEY `normal_favorite_count` (`favorite_count`) USING BTREE,
   CONSTRAINT `author_id` FOREIGN KEY (`author_id`) REFERENCES `t_userinfo` (`id`)
 )

2、然后在网站勾选 json 、gorm ,就出现了:

 type Video struct {
     ID int64 `gorm:"column:id" json:"id"`  //  视频id
     AuthorId int64 `gorm:"column:author_id" json:"author_id"`  //  作者id
     PlayUrl string `gorm:"column:play_url" json:"play_url"`  //  视频播放地址
     CoverUrl string `gorm:"column:cover_url" json:"cover_url"`  //  视频封面地址
     FavoriteCount int64 `gorm:"column:favorite_count" json:"favorite_count"`  //  视频的点赞总数
     CommentCount int64 `gorm:"column:comment_count" json:"comment_count"`  //  视频的评论总数
     Title string `gorm:"column:title" json:"title"`  //  视频标题
     CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`  //  投稿时间
     DeletedAt time.Time `gorm:"column:deleted_at" json:"deleted_at"`  //  删除时间
     UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`  //  更新时间
     IsFavorite int64 `gorm:"column:is_favorite" json:"is_favorite"`
 }

3、修改

比如这里的需求是 t_video 表中需要携带作者 userinfo 的数据。

  • 这里新增 Author Userinfo 连接 Userinfo 结构体,并声明 gorm 字段为 "foreignKey:AuthorId;"
  • 把UpdatedAt、DeletedAt、CreatedAt字段删掉,新增 gorm.Model ,因为它自带这些参数。
 type Video struct {
     gorm.Model
     ID            int64     `gorm:"column:id" json:"id"` //  视频id
     Author        Userinfo  `json:"author" gorm:"foreignKey:AuthorId;"`         //  -新增-
     AuthorId      int64     `gorm:"column:author_id" json:"author_id"`           //  作者id
     PlayUrl       string    `gorm:"column:play_url" json:"play_url"`             //  视频播放地址
     CoverUrl      string    `gorm:"column:cover_url" json:"cover_url"`           //  视频封面地址
     FavoriteCount int64     `gorm:"column:favorite_count" json:"favorite_count"` //  视频的点赞总数
     CommentCount  int64     `gorm:"column:comment_count" json:"comment_count"`   //  视频的评论总数
     Title         string    `gorm:"column:title" json:"title"`                   //  视频标题
     // CreatedAt  time.Time `gorm:"column:created_at" json:"created_at"`         //  投稿时间
     // DeletedAt  time.Time `gorm:"column:deleted_at" json:"deleted_at"`         //  删除时间
     // UpdatedAt  time.Time `gorm:"column:updated_at" json:"updated_at"`         //  更新时间
     IsFavorite    int64     `gorm:"column:is_favorite" json:"is_favorite"`
 }
 ​

注意的问题

1、比如使用 Navicat 建表的表名是 t_video ,但是想关联的结构体名是 Video , 那 gorm 怎么知道关联想要的东西呢?

这里需要在连接数据库时进行一些配置,这里只需要使用前两个:

 dsn := "root:xxxxxx@tcp(127.0.0.1:3306)/golang_blog?charset=utf8mb4&parseTime=True&loc=Local"
 db, err := gorm.Open(mysql.Open("gorm.db"), &gorm.Config{
   NamingStrategy: schema.NamingStrategy{
     TablePrefix: "t_",   // table name prefix, table for `User` would be `t_users`
     SingularTable: true, // use singular table name, table for `User` would be `user` with this option enabled
     //NoLowerCase: true, // skip the snake_casing of names
     //NameReplacer: strings.NewReplacer("CID", "Cid"), // use name replacer to change struct/field name before convert it to db name
   },
 })

2、若需要的字段可能有中文,为了避免报错,建表时设置该字段的字符集为utf8,排序规则为utf8_general_ci。

3.Preload 预加载

在上述嵌套的情况下,此时直接查询返回一个 video 是没有 Userinfo 的信息的,需要使用 Preload

GORM 允许在 Preload 的其它 SQL 中直接加载关系。

比如:直接链式添加 .Preload("Author")

 func (mgr manager) GetAllVideo(latestTime int64) ([]model.Video, error) {
     var videos []model.Video
     timeLayout := "2006-01-02 15:04:05"
     
     result := mgr.db.Model(&model.Video{}).Where("created_at <= ?", time.Unix(latestTime, 0).Format(timeLayout)).
         Order("created_at DESC").Preload("Author").Limit(30).Count(&count).Find(&videos)
 ​
     return videos, result.Error
 }

04 总结

gorm使用下来是比较方便的orm工具,建议读者如果出问题了多看看官方文档。

参考资料:

gorm官方文档:GORM 指南 | GORM - The fantastic ORM library for Golang, aims to be developer friendly.