上篇文章中我们在使用的开发环境中增加了MySQL容器,然后介绍了使用database/sql标准库结合数据库驱动包进行数据库操作的方法。不过它们是相对偏底层的软件包。实际开发经常会使用一些在它的基础上封装的 ORM库。ORM的查询使用起来更简单些,语法更富表达力。这篇文章我们主要探究下面这些内容。

  • gorm的基本用法
  • 如何管理ORM的使用
  • 如何合理规划项目目录结构

安装gorm包

gorm是一个出色的,对开发人员友好的 Golang ORM 库,其支持的特性包括:

  • 全特性 ORM (几乎包含所有特性)
  • 模型关联 (一对一, 一对多,一对多(反向), 多对多, 多态关联)
  • 钩子 (Before/After Create/Save/Update/Delete/Find)
  • 预加载
  • 事务
  • 复合主键
  • SQL 构造器
  • 自动迁移
  • 日志

使用如下命令进行安装:

go get -u github.com/jinzhu/gorm

将gorm加入项目中

规划数据模型目录结构

我们在项目根目录下新建如下目录:

http_demo
|
└───model
│   └───dao
│   │   init.go
│   └───────table
│           │   user.go

在 Go 中包以目录的形式来组织,所以model包中存放所有数据模型,dao代表数据访问对象,存放数据库CRUD 方法的封装,其中的init.go存放dao包的初始化函数主要是用来在加载包后连接上数据库。table包里放与数据表对应的模型定义(使用 ORM 之前要先定义模型与数据库中的表对应),在示例里我们会定义一个User模型放在user.go文件中。

规划完目录后就可以在各部分写相应的代码了,首先来看使用gorm连接数据库。

连接数据库

我们在dao包的init.go中加入包的初始化逻辑进行数据库连接,初始化函数会在dao包第一次被导入时执行,由于gorm文档连接数据库的例子太简单,参考价值不大,我们根据项目需要做些简单封装,init.go中的代码如下所示:

package daoimport (_ "github.com/go-sql-driver/mysql""github.com/jinzhu/gorm""time"
)var _DB *gorm.DBfunc DB() *gorm.DB {return _DB
}func init() {_DB = initDB()
}func initDB() *gorm.DB {// In our docker dev environment use// db, err := gorm.Open("mysql", "go_web:go_web@tcp(database:3306)/go_web?charset=utf8&parseTime=True&loc=Local")db, err := gorm.Open("mysql", "go_web:go_web@tcp(localhost:33063)/go_web?charset=utf8&parseTime=True&loc=Local")if err != nil {panic(err)}db.DB().SetMaxOpenConns(100)db.DB().SetMaxIdleConns(10)db.DB().SetConnMaxLifetime(time.Second * 300)if err = db.DB().Ping(); err != nil {panic(err)}return db
}

代码很简单,大家实操的时候根据自己的MySQL配置更改代码里面的配置就行了。唯一说明一点的是,如果使用了我们提提供的Docker环境,在连接数据库时host要改为database:3306,因为我在容器环境里将MySQL容器的服务名定义成了database,在运行了Goapp容器需要用服务名访问容器网络中的其他容器。关于容器环境的详细配置请大家查看Go Web编程--应用数据库 中的描述。

定义模型

使用模型访问数据库的表之前我们需要先定义对应的模型。我们示例中现在只有一个users表,接下来我们在table包中添加users表的模型定义并放置在user.go文件中。

package tableimport "time"type User struct {Id        int64     `gorm:"column:id;primary_key"`UserName  string    `gorm:"column:username"`Secret    string    `gorm:"column:secret;type:varchar(1000)"`CreatedAt time.Time `gorm:"column:created_at"`UpdatedAt time.Time `gorm:"column:updated_at"`
}// TableName sets the insert table name for this struct type
func (m *User) TableName() string {return "users"
}

模型 CRUD

关于模型的 CRUD,建议将单个模型的CRUD放在dao包的单个文件中,这样方便以后代码的管理。这里多说一点,建议不要直接用controller或者叫handler包直接访问dao包,而是在中间加一层logic包,把逻辑放在这一层。这样对代码的管理、复用性都有帮助。

因为数据库的 CRUD 有很多种操作,本文的目的是帮助大家快速开始使用gorm所以我就只放简单的 CRUD 做演示了。大家按照这里步骤引入gorm后用到其他的数据库操作了直接去官方文档里查一查就好。

dao包中新建user.go用来存放User模型的操作方法。

package daoimport "example.com/http_demo/model/dao/table"func CreateUser(user *table.User) (err error) {err = DB().Create(user).Errorreturn
}func GetUserById(userId int64) (user *table.User, err error) {user = new(table.User)err = DB().Where("id = ?", userId).First(user).Errorreturn
}func GetAllUser() (users []*table.User, err error) {err = DB().Find(&users).Errorreturn
}func UpdateUserNameById(userName string, userId int64) (err error) {user := new(table.User)err = DB().Where("id = ?", userId).First(user).Errorif err != nil {return}user.UserName = userNameerr = DB().Save(user).Errorreturn
}func DeleteUserById(userId int64) (err error) {user := new(table.User)err = DB().Where("id = ?", userId).First(user).Errorif err != nil {return}err = DB().Delete(user).Errorreturn
}

验证ORM 方法

经过上面几步的设置后我们就可以在项目里使用gorm访问数据库了,由于我们项目的main goroutine中运行了http服务,所以我们使用测试用例对上面dao包中定义的几个方法进行一下测试。

篇幅原因我就只贴一个GetAllUsers方法的测试用例了:

func TestGetAllUser(t *testing.T) {tests := []struct {name      stringwantErr   bool}{{name: "test",wantErr: false,},}for _, tt := range tests {t.Run(tt.name, func(t *testing.T) {gotUsers, err := GetAllUser()if (err != nil) != tt.wantErr {t.Errorf("GetAllUser() error = %v, wantErr %v", err, tt.wantErr)return}for _, user := range gotUsers {log.Info("user: %v", user)}})}
}

运行测试后,可以看到结果:

INFO user: &{1   2020-02-15 14:14:46 +0800 CST 2020-02-15 06:44:17 +0800 CST}
--- PASS: TestGetAllUsers (0.00s)--- PASS: TestGetAllUsers/test (0.00s)
PASSProcess finished with exit code 0

关注文末的公众号回复gohttp05可以得到完整的测试用例代码,建议这些CRUD都要写好测试用例进行自测,使用GoLand可以很容易的生成测试函数和运行测试。

重新规划项目目录

引入ORM后,我们项目中的代码就比较多了,都放在根目录下的main包中有点杂乱,所以我们根据各部分的功能和职责对项目目录进行了简单的划分,划分后的目录结构如下:

http_demo
|
└───handler//route handler
|
└───logic//business logic
|
└───middleware
│
└───model
│   └───dao
│   │   init.go
│   └───table
│       │   user.go
└───router// router
|
|   main.go

感觉今天的内容还是挺多的,尤其对于刚入门Go的同学们一定要把今天的代码下载下来实操一遍才能掌握。gorm提供的功能还是很多的,每个功能在官方文档里都有讲解,我们这里就不做过多介绍了。这篇文章的目的主要是让大家能快速入门,同时把ORM相关的代码管理和初始化流程做的规范些,这些组织方式完全可以应用到生产级别的项目中的。

关注文末的公众号回复gohttp05获取文章中完整的源代码,喜欢我的文章请点赞和收藏。

前文回顾

深入学习用Go编写HTTP服务器

Web服务器路由

用Docker快速搭建Go开发环境

十分钟学会用Go编写Web中间件

Go Web编程--应用数据库

Go Web 编程--应用 ORM相关推荐

  1. Go Web编程--应用ORM

    上篇文章中我们在使用的开发环境中增加了 MySQL容器,然后介绍了使用 database/sql标准库结合数据库驱动包进行数据库操作的方法.不过它们是相对偏底层的软件包.实际开发经常会使用一些在它的基 ...

  2. easyui datagrid url不请求请求_Go Web编程--深入学习解析HTTP请求

    之前这个系列的文章一直在讲用Go语言怎么编写HTTP服务器来提供服务,如何给服务器配置路由来匹配请求到对应的处理程序,如何添加中间件把一些通用的处理任务从具体的Handler中解耦出来,以及如何更规范 ...

  3. bootstrap网页模板源码_Go Web 编程--超详细的模板库应用指南

    如果你有过Web编程的经验,那么或多或少都听说过或者使用过模板.简而言之,模板是可用于创建动态内容的文本文件.例如,你有一个网站导航栏的模板,其中动态内容的一部分可能是根据当前用户是否登录显示登录还是 ...

  4. Go Web编程--解析JSON请求和生成JSON响应

    现在无论是网站.App.小程序还是移动端H5页面应用,都是采用前端与后端单独部署,相互之间以API接口交互的形式构建而成的.因为在结合可读性.编码数据大小和开发者使用难度上都JSON格式是一个比较好的 ...

  5. Go Web编程--SecureCookie实现客户端Session管理

    在Web应用开发中Session是在用户和服务器之间进行交换的非持久化交互信息.当用户登录时,可以在用户和服务器之间生成Session,然后来回交换数据,并在用户登出时销毁Session.gorill ...

  6. Go Web 编程--如何确保Cookie数据的安全传输

    什么是Cookie Cookie(也叫Web Cookie或浏览器Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上.通常, ...

  7. Go Web 编程--超详细的模板库应用指南

    如果你有过Web编程的经验,那么或多或少都听说过或者使用过模板.简而言之,模板是可用于创建动态内容的文本文件.例如,你有一个网站导航栏的模板,其中动态内容的一部分可能是根据当前用户是否登录显示登录还是 ...

  8. Go Web编程--深入学习解析HTTP请求

    之前这个系列的文章一直在讲用 Go语言怎么编写HTTP服务器来提供服务,如何给服务器配置路由来匹配请求到对应的处理程序,如何添加中间件把一些通用的处理任务从具体的Handler中解耦出来,以及如何更规 ...

  9. Go Web编程--应用数据库

    今天我们继续接着前几篇关于 GoWeb编程的文章往下延伸.在 Web应用程序中几乎每个应用场景都需要存储和检索数据库中的数据.当你处理动态内容,为用户提供表单以输入数据或存储登录名和密码凭据以供用户进 ...

最新文章

  1. Vim对中文编码的支持[转]
  2. 不知道这些,简历上千万不要说你会 Redis 持久化。。。
  3. python笔记2(函数 面向对象 文件编程 上下文管理器)
  4. 【Python学习系列四】Python程序通过hadoop-streaming提交到Hadoop集群执行MapReduce
  5. python 之 GIL(线程和进程的应用)
  6. 医学图像处理期末复习(一)
  7. unity3d软阴影和硬阴影的原理_Unity3D中两种默认阴影的实现
  8. 请查收 | 2021 阿里妈妈技术文章回顾
  9. 看了数百个PPT封面,我只想告诉你这两个套路!
  10. c++ stack 遍历_划重点啦!带你解读图的两种遍历方式
  11. 【项目经验】如何用TexturePacker Physicseditor开发游戏
  12. 你也许根本不需要 Kubernetes!
  13. c语言全文件操作函数,C语言文件操作函数大全
  14. filtic函数详解(附3个实例)
  15. 图音80系列车载导航/DVD分体机安装DSA
  16. 教你炒股票24:MACD对背弛的辅助判断
  17. 信创IT网管运维管理软件,信创运维服务平台
  18. matlab中clc什么意思,MATLAB中clc是什么意思
  19. 阿里云ECS服务器常用入门配置命令
  20. zblog mysql修改_手把手教修正zblog默认阅读量

热门文章

  1. How to enable nested virtualization in KVM
  2. 看了些关于rem的知识点,在这做个自我总结归纳
  3. 自动完成下拉框 Select2 关键字搜索的实例(本地数据与异步获取)
  4. InstallShield 2008 终止声明 (EOL)对最终客户意味着什么
  5. HDU 4547 CD操作
  6. Python 基础起步(一)写在开篇的话,写给同为小白的你
  7. centOS 7下安装与配置heartbeat高可用集群
  8. 1. JavaScript学习笔记——JS基础
  9. FastDFS 学习笔记
  10. 操作符!与操作符!!的区别