gorm基础使用及解决部分疑惑
这是我参与「第三届青训营 -后端场」笔记创作活动的第4篇笔记。
01 简介
本文主要介绍在项目中集成 gorm 的大致方法、一些错误的解决方法、规范包及目录。
02 规范包及目录
这只是其中的一种分包方式,具体使用哪种可以根据自己需求。
controller //处理函数
dao //数据库相关,gorm相关接口
router //路由
model //生成数据表相关的结构体
assets //静态资源
templates //模板文件、HTML
03 集成gorm
这里分两种情况:
- 如果还未建表,可以先声明结构体数据之后再使用 gorm 自动建表功能。
- 若已经建好表了,则可以使用一些便捷的网站快速生成相应的结构体,然后再根据实际需求更改(比如外键)。
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.