Go Web 编程--应用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 dao
import (
  _ "github.com/go-sql-driver/mysql"
  "github.com/jinzhu/gorm"
  "time"
)
var _DB *gorm.DB
func 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,在运行了Go的app容器需要用服务名访问容器网络中的其他容器。关于容器环境的详细配置请大家查看Go Web编程--应用数据库 中的描述。

定义模型

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

package table
import "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 dao
import "example.com/http_demo/model/dao/table"
func CreateUser(user *table.User) (err error) {
 err = DB().Create(user).Error
 return
}
func GetUserById(userId int64) (user *table.User, err error) {
 user = new(table.User)
 err = DB().Where("id = ?", userId).First(user).Error
 return
}
func GetAllUser() (users []*table.User, err error) {
 err = DB().Find(&users).Error
 return
}
func UpdateUserNameById(userName string, userId int64) (err error) {
 user := new(table.User)
 err = DB().Where("id = ?", userId).First(user).Error
 if err != nil {
 return
 }
 user.UserName = userName
 err = DB().Save(user).Error
 return
}
func DeleteUserById(userId int64) (err error) {
 user := new(table.User)
 err = DB().Where("id = ?", userId).First(user).Error
 if err != nil {
 return
 }
 err = DB().Delete(user).Error
 return
}

验证ORM 方法

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

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

func TestGetAllUser(t *testing.T) {
 tests := []struct {
 name      string
 wantErr  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)
PASS
Process finished with exit code 0

重新规划项目目录

引入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相关的代码管理和初始化流程做的规范些,这些组织方式完全可以应用到生产级别的项目中的

作者:kevinyan

链接:https://juejin.im/post/5e4896ef6fb9a07c8334d368

我来评几句
登录后评论

已发表评论数()

相关站点

热门文章