使用 GORM(Go 的 ORM 库)连接数据库,并实现增删改查操作 | 青训营

前置

Gin是Go语言的一套WEB框架,在学习一种陌生语言的陌生框架,最好的方式,就是用我们熟悉的思维去学。作为一名后端Java开发,在最初入门时,最熟悉的莫过于MVC分层结构,可以简单归纳成controller层,model层,dao层,而在SpringBoot框架里,大概也经常看到以下的分层结构------

这个包含着java根目录和resours资源目录,那么同样go语言我们也可以照这样的架构做一套前后端分离系统。

接下来,我们就按照这个MVC分层结构,搭建一套基于Gin+Gorm框架的Go语言后端。

搭建之前,先简单介绍一下Gin和Gorm分别是什么。

Gin是一个golang的WEB框架,很轻量,依赖到很少,有些类似Java的SpringMVC,通过路由设置,可以将请求转发到对应的处理器上。

Gorm是Go语言的ORM框架,提供一套对数据库进行增删改查的接口,使用它,就可以类似Java使用Hibernate框架一样,可对数据库进行相应操作。

首先,我们要用到这两个框架,得先需要import依赖进来,依赖前。需要go命令安装Gin和Gorm

js 复制代码
go get -u github.com/gin-gonic/gin 
go get -u github.com/jinzhu/gorm

下面,我们可以参考springboot的分层架构,搭建一套MVC分层结构系统:

先新建两个目录go和resource,在go下面新建controller,service,dao,entity层,这里注意的是go语言中还需要一个router包,用于存放路由文件,可能你对路由文件不是很理解,那么,你可以简单理解为,这个路由的作用,就类似SpringMVC的@RequestMapping("/user")和@GetMapping("/list")注解组合起到的作用,通过路由,就可以找到需要调用的后端方法。

然后,在resources目录下新建配置文件,文件名随意。

js 复制代码
url: 127.0.0.1 
userName: root 
password: root 
dbname: example
post: 3306

基础工作做好,下面就开始敲代码了。

dao层搭建

在dao层下,建立一个mysql.go文件,这个文件在dao的包下,最初的效果如下

这里注意,新建的文件是普通文件并非application文件。

js 复制代码
package dao  
  
import (  
"fmt"  
"github.com/jinzhu/gorm"  
_ "github.com/jinzhu/gorm/dialects/mysql"  
"gopkg.in/yaml.v2"  
"io/ioutil"  
)  
  
// DRIVER 指定驱动  
const DRIVER = "mysql"  
  
var SqlSession *gorm.DB  
  
type conf struct {  
Url string `yaml:"url"`  
UserName string `yaml:"userName"`  
Password string `yaml:"password"`  
DbName string `yaml:"dbname"`  
Port string `yaml:"post"`  
}  
  
func (c *conf) getConf() *conf {  
//读取resources/application.yaml文件  
yamlFile, err := ioutil.ReadFile("resources/application.yaml")  
//若出现错误,打印错误提示  
if err != nil {  
fmt.Println(err.Error())  
}  
//将读取的字符串转换成结构体conf  
err = yaml.Unmarshal(yamlFile, c)  
if err != nil {  
fmt.Println(err.Error())  
}  
return c  
}  
  
func InitMySql() (err error) {  
var c conf  
//获取yaml配置参数  
conf := c.getConf()  
//将yaml配置参数拼接成连接数据库的url  
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",  
conf.UserName,  
conf.Password,  
conf.Url,  
conf.Port,  
conf.DbName,  
)  
//连接数据库  
SqlSession, err = gorm.Open(DRIVER, dsn)  
if err != nil {  
panic(err)  
}  
//验证数据库连接是否成功,若成功,则无异常  
return SqlSession.DB().Ping()  
}  
  
func Close() {  
SqlSession.Close()  
}
  • Goland会自动导包,当然,你自己导包更好了
  • 创建一个类似旧版mybatis全局的SqlSession变量,就取名为SqlSession即可,该变量起到作用于mybatis的SqlSession实例类似,在数据库驱动连接成功后,即可提供select/insert/update/delete方法。
  • 定义一个用于接收yaml配置参数的struct结构体,你可以简单将它理解为Java的类。
  • 然后提供一个读取解析该yaml配置的方法,将读取到的配置参数数据转换成上边的结构体conf
  • 定义一个初始化连接数据库的方法,该方法用于在启动项目时执行。
  • 最后,还需要提供一个可以关闭数据库连接的方法。

entity层定义模型

Gorm是全特性的ORM框架,即对象关系映射,这样,就需要类似Java那样建立与数据库映射的类,在Go语言当中,我们称之为结构体。

js 复制代码
type User struct {  
Id int `json:"id"`  
Name string `json:"name"`  
NickName string `json:"nickName"`  
Avatar string `json:"avatar"`  
Password string `json:"password"`  
Email string `json:"email"`  
Mobile string `json:"mobile"`  
DelStatus int `json:"delStatus"`  
CreateTime int64 `json:"createTime"`  
}

创建一个User.go文件,里边定义一个User结构体

js 复制代码
// TableName 数据库表明自定义,默认为model的复数形式,比如这里默认为 users  
func (User) TableName() string {  
return "sys_user"  
}

注意一点,这里需要明确指出,其struct结构体映射到哪一张表,如果没有显示指出,它会默认生成一张命名为users的数据库表。

service层建立增删改查逻辑

接下来,就可以基于SqlSession获取到的API接口,对数据库进行简单的增删改查操作了。

js 复制代码
/*  
*  
新建User信息  
*/  
func CreateUser(user *entity.User) (err error) {  
if err = dao.SqlSession.Create(user).Error; err != nil {  
return err  
}  
return  
}  
  
/*  
*  
获取user集合  
*/  
func GetAllUser() (userList []*entity.User, err error) {  
if err := dao.SqlSession.Find(&userList).Error; err != nil {  
return nil, err  
}  
return  
}  
  
/*  
*  
根据id删除user  
*/  
func DeleteUserById(id string) (err error) {  
err = dao.SqlSession.Where("id=?", id).Delete(&entity.User{}).Error  
return  
}  
  
/*  
*  
根据id查询用户User  
*/  
func GetUserById(id string) (user *entity.User, err error) {  
if err = dao.SqlSession.Where("id=?", id).First(user).Error; err != nil {  
return nil, err  
}  
return  
}  
  
/*  
*  
更新用户信息  
*/  
func UpdateUser(user *entity.User) (err error) {  
err = dao.SqlSession.Save(user).Error  
return  
}
  1. CreateUser :该函数用于User在数据库中创建一条新记录。它采用指向实体的指针作为参数,并尝试使用(可能是数据库会话对象)的方法User将其插入数据库。如果操作成功,则返回(无错误)。否则,它会返回一个错误,指出失败的原因。Create``dao.SqlSession``nil
  2. GetAllUser User :此函数从数据库中检索所有记录的列表。User它返回一个指向实体 ( )的指针切片userList和一个错误。它使用Find的方法从数据库中dao.SqlSession获取所有记录并将它们存储在切片中。如果没有错误,则返回用户列表;否则,它返回一个错误。User``userList
  3. DeleteUserById :该函数用于User根据提供的信息从数据库中删除一条记录id。它以id为字符串参数,并使用Delete的方法dao.SqlSession来执行删除操作。它使用方法指定删除的条件Where,相当于SQLWHERE子句。如果操作成功,则返回nil;否则,它返回一个错误。
  4. GetUserById User :此函数根据提供的信息从数据库中检索单个记录id。它将作为id字符串参数,并使用First方法来dao.SqlSession查找与该Where方法指定的条件匹配的第一条记录(基于提供的id)。它将检索到的记录存储在user指针中。如果操作成功,则返回user实体;否则,它返回一个错误。
  5. UpdateUser :此函数用于更新User数据库中的现有记录。它以指向实体的指针作为User参数,并使用 的Save方法dao.SqlSession来更新数据库中相应的记录。该Save方法根据主键自动执行插入(如果记录不存在)或更新(如果记录存在)。如果操作成功,则返回nil;否则,它返回一个错误。

controller层建立User的controller类。

在controller层建立一个UserController.go类,类似Java的controller,主要用于根据url跳转执行到对应路径的方法。

js 复制代码
func CreateUser(c *gin.Context) {  
//定义一个User变量  
var user entity.User  
//将调用后端的request请求中的body数据根据json格式解析到User结构变量中  
c.BindJSON(&user)  
//将被转换的user变量传给service层的CreateUser方法,进行User的新建  
err := service.CreateUser(&user)  
//判断是否异常,无异常则返回包含200和更新数据的信息  
if err != nil {  
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})  
} else {  
c.JSON(http.StatusOK, gin.H{  
"code": 200,  
"msg": "success",  
"data": user,  
})  
}  
}  
  
// GetUserList chax  
func GetUserList(c *gin.Context) {  
todoList, err := service.GetAllUser()  
if err != nil {  
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})  
} else {  
c.JSON(http.StatusOK, gin.H{  
"code": 200,  
"msg": "success",  
"data": todoList,  
})  
}  
}  
  
// DeleteUserHandler handles the DELETE request to delete a user by ID.  
func DeleteUserById(c *gin.Context) {  
id := c.Param("id")  
  
err := service.DeleteUserById(id)  
if err != nil {  
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete user"})  
return  
}  
  
c.JSON(http.StatusOK, gin.H{  
"code": 200,  
"msg": "success",  
"data": nil,  
})  
}  
  
// GetUserHandler handles the GET request to retrieve a user by ID.  
func GetUserById(c *gin.Context) {  
id := c.Param("id")  
  
user, err := service.GetUserById(id)  
if err != nil {  
c.JSON(http.StatusNotFound, gin.H{  
"code": 200,  
"msg": "success",  
"data": user,  
})  
return  
}  
  
c.JSON(http.StatusOK, user)  
}  
  
// UpdateUserHandler handles the PUT request to update user information.  
func UpdateUser(c *gin.Context) {  
var user entity.User  
  
if err := c.BindJSON(&user); err != nil {  
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request payload"})  
return  
}  
  
err := service.UpdateUser(&user)  
if err != nil {  
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update user"})  
return  
}  
c.JSON(http.StatusOK, gin.H{  
"code": 200,  
"msg": "success",  
"data": user,  
})  
}
  1. CreateUser :此函数是创建新用户的 HTTP POST 请求处理程序。它首先使用 ,从 JSON 请求正文中提取用户数据c.BindJSON(&user),其中user是类型为 的变量entity.User。然后,它将用户数据传递给函数service.CreateUser以在数据库中创建新用户。如果用户创建成功,则会返回状态码200的JSON响应以及创建的用户数据。如果在用户创建过程中出现错误,它会返回带有状态代码 400(错误请求)和错误消息的 JSON 响应。
  2. GetUserList :此函数是一个 HTTP GET 请求处理程序,用于检索所有用户的列表。它调用该service.GetAllUser函数从数据库中获取所有用户。如果检索成功,它将返回带有状态代码 200 的 JSON 响应和用户列表。如果检索过程中出现错误,它会返回带有状态代码 400 的 JSON 响应和错误消息。
  3. DeleteUserById :此函数是一个 HTTP DELETE 请求处理程序,可按 ID 删除用户。它使用 .url 从 URL 路径中提取用户 ID c.Param("id")。然后它调用该service.DeleteUserById函数从数据库中删除用户。如果删除成功,它将返回带有状态代码 200 的 JSON 响应和成功消息。如果删除过程中出现错误,它会返回带有状态代码 500(内部服务器错误)和错误消息的 JSON 响应。
  4. GetUserById :此函数是一个 HTTP GET 请求处理程序,可按 ID 检索用户。它使用 .url 从 URL 路径中提取用户 ID c.Param("id")。然后,它调用该service.GetUserById函数根据提供的 ID 从数据库中获取用户。如果找到用户,它会返回带有状态代码 200 和用户数据的 JSON 响应。如果未找到用户,它将返回带有状态代码 404(未找到)的 JSON 响应和成功消息。
  5. UpdateUser :此函数是更新用户信息的 HTTP PUT 请求处理程序。它使用 .json 从 JSON 请求正文中提取更新的用户数据c.BindJSON(&user)。然后它调用该service.UpdateUser函数来更新数据库中的用户数据。如果更新成功,它将返回带有状态代码 200 的 JSON 响应和更新后的用户数据。如果更新过程中出现错误,它会返回带有状态代码 500 的 JSON 响应和错误消息。

总之,这些函数共同创建了一个基本的用户管理 API,允许创建、检索、更新和删除用户。API 使用 Gin 进行路由和请求处理,并将业务逻辑委托给包service,包与数据库交互以对用户数据执行 CRUD 操作。

routes层增加路由文件,用于根据请求url进行转发。

js 复制代码
func SetRouter() *gin.Engine {  
r := gin.Default()  
  
/**  
用户User路由组  
*/  
userGroup := r.Group("user")  
{  
//增加用户User  
userGroup.POST("/users", controller.CreateUser)  
//查看所有的User  
userGroup.GET("/users", controller.GetUserList)  
//修改某个User  
userGroup.PUT("/users/:id", controller.UpdateUser)  
//删除某个User  
userGroup.DELETE("/users/:id", controller.DeleteUserById)  
  
userGroup.GET("/users/:id", controller.GetUserById)  
}  
  
return r  
}
  1. SetRouter功能 :该函数负责创建和配置 Gin 路由器 ( gin.Engine) 以及各种与用户相关的路由。

  2. r := gin.Default() :这一行创建了一个新的 Gin 路由器,其中包含一些默认的中间件,包括日志记录和恢复。返回的路由器r将用于定义和处理 HTTP 路由。

  3. userGroup := r.Group("user") :此行为与用户相关的端点创建路由组。所有以"/user"开头的路由都将分组在此前缀下,使代码更有组织性和可管理性。

  4. 用户路线

    A。userGroup.POST("/users", controller.CreateUser):此路由处理 HTTP POST 请求以创建新用户。当客户端发送controller.CreateUser函数,负责根据请求正文中的数据创建新用户。

    b. userGroup.GET("/users",controller.GetUseruserGroup.GET("/users", controller.GetUserList):此路由处理 HTTP GET 请求以获取所有用户的列表。当客户端向"/user/users"发送 GET 请求时controller.GetUserList`函数,它检索用户列表并将其作为 JSON 响应返回。

    C。userGroup.PUT("/users/:id", controller.UpdateUser):此路由处理 HTTP PUT 请求以通过 ID 更新特定用户。当客户端向"/user"发送 PUT 请求时controller.UpdateUser函数,它根据提供的 ID 和请求正文更新用户数据。

    d. userGroup.DELETE("/users/:id", controller.DeleteUserById):此路由处理 HTTP DELETE 请求以删除controller.DeleteUserById函数,根据提供的 ID 删除用户。

    e. userGroup.GET("/users/:id",controller.GetUseruserGroup.GET("/users/:id", controller.GetUserById):此路由处理 HTTP GET 请求以通过 ID 获取特定用户。当客户端向"/user/users/:id"发送 GET 请求时,它将被定向到该controller.GetUserById`函数,该函数根据提供的 ID 检索用户并将其作为 JSON 响应返回。

  5. Return :最后,该函数返回配置好的 Gin 路由器r,它可用于启动 Web 服务器并处理传入的 HTTP 请求。

此设置允许服务器通过向"/user"前缀下的指定路由发送适当的 HTTP 请求来处理与用户相关的操作,例如创建、检索、更新和删除用户。每个路由对应于一个特定的控制器功能,负责处理业务逻辑并与数据存储(例如数据库)交互以执行所需的操作。

main启动类以及运行。

最后一步,就是建立main的启动类了,需要注意一点是,go的启动类,必须命名在package main的包下,否则无法进行启动。

js 复制代码
func main() {  
//连接数据库  
err := dao.InitMySql()  
if err != nil {  
panic(err)  
}  
//程序退出关闭数据库连接  
defer dao.Close()  
//绑定模型  
dao.SqlSession.AutoMigrate(&entity.User{})  
//注册路由  
r := routes.SetRouter()  
//启动端口为8089的项目  
r.Run(":8089")  
}

下面运行一下

如果是这样就成功了。

到这一步,基于Gin+Gorm框架搭建MVC模式的Go后端系统,就初步搭建完成了。

感悟

gin+Gorm的开发和springboot相似,go的依赖需要通过命令下载,并且导入包的时候没用到的不会保留,这点有点别扭,go的路由也是一个特色,相当于java里面注解,但是这样我觉得反而更清晰明了,同时,后来对controller层进行了优化,让代码的复用性和健壮性更强,还有就是go告诉你的错误方式和java也不一样,熟练以后也挺好用的。这个增删改查让我对gin和gorm有了更加清晰的认识.

相关推荐
CallBack8 个月前
Typora+PicGo+阿里云OSS搭建个人图床,纵享丝滑!
前端·青训营笔记
Taonce1 年前
站在Android开发者的角度认识MQTT - 源码篇
android·青训营笔记
AB_IN1 年前
打开抖音会发生什么 | 青训营
青训营笔记
monster1231 年前
结营感受(go) | 青训营
青训营笔记
翼同学1 年前
实践记录:使用Bcrypt进行密码安全性保护和验证 | 青训营
青训营笔记
hu1hu_1 年前
Git 的正确使用姿势与最佳实践(1) | 青训营
青训营笔记
星曈1 年前
详解前端框架中的设计模式 | 青训营
青训营笔记
tuxiaobei1 年前
文件上传漏洞 Upload-lab 实践(中)| 青训营
青训营笔记
yibao1 年前
高质量编程与性能调优实战 | 青训营
青训营笔记
小金先生SG1 年前
阿里云对象存储OSS使用| 青训营
青训营笔记