文章目录
- 原生SQL操作
- XORM
- GORM
本文演示在Gin框架中通过三种方式实现增删改查的操作,数据表结构如下:
CREATE TABLE `users` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`user_no` bigint(20) unsigned NOT NULL COMMENT '用户编号',
`name` varchar(255) NOT NULL DEFAULT '' COMMENT '用户姓名',
`age` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '用户年龄',
`address` varchar(255) NOT NULL DEFAULT '' COMMENT '地址',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '添加时间',
`update_time` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `key_user_no` (`user_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
原生SQL操作
在Gin框架中使用MySQL的最简单的方式就是直接处理SQL语句,记得引入 _ "github.com/go-sql-driver/mysql"
。
代码如下:
//公共方法封装
package dbUtil
import (
"database/sql"
"fmt"
"github.com/gin-gonic/gin"
_ "github.com/go-sql-driver/mysql"
"net/http"
"strconv"
)
var tableName = "users" //数据表名
var result ResponseData //响应结果数据
// 统一返回数据的结构体
type ResponseData struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data"`
}
func showSuccess(c *gin.Context, data interface{}) {
result.Code = http.StatusOK
result.Message = "操作成功"
result.Data = data
c.JSON(http.StatusOK, result)
return
}
func showError(c *gin.Context, message string) {
result.Code = http.StatusBadRequest
result.Message = message
result.Data = nil
c.JSON(http.StatusOK, result)
return
}
// 使用原生SQL语句
// go-sql-driver地址:https://github.com/go-sql-driver/mysql
var sqlDb *sql.DB //数据库连接db
// 初始化
func init() {
//打开数据库
//parseTime:时间格式转换(查询结果为时间时,是否自动解析为时间);
//loc=Local:MySQL的时区设置
sqlStr := "root:rx123456@tcp(127.0.0.1:3306)/gin_demo?charset=utf8&parseTime=true&loc=Local"
var err error
sqlDb, err = sql.Open("mysql", sqlStr)
if err != nil {
fmt.Println("数据库打开失败:", err)
return
}
//测试与数据库建立的连接,非必要(校验连接是否正确)
err = sqlDb.Ping()
if err != nil {
fmt.Println("数据库连接失败:", err)
return
}
}
// 用户结构体
type sqlUserData struct {
Id int `json:"id"`
UserNo int `json:"user_no"`
Name string `json:"name"`
Age int `json:"age"`
Address string `json:"address"`
Remarks string `json:"remarks"`
}
func MysqlInsertData(c *gin.Context) {
/*
//请求参数
{
"user_no":1001,
"name":"张三",
"age":18,
"address":"北京昌平"
}
*/
var user sqlUserData
err := c.Bind(&user)
if err != nil {
showError(c, fmt.Sprint(err))
return
}
sqlStr := "insert into " + tableName + "(user_no, name, age, address) values (?,?,?,?)"
ret, err := sqlDb.Exec(sqlStr, user.UserNo, user.Name, user.Age, user.Address)
if err != nil {
fmt.Printf("insert failed, err:%v\n", err)
showError(c, fmt.Sprint(err))
return
}
newDataId, _ := ret.LastInsertId()
showSuccess(c, "新增的结果id:"+strconv.Itoa(int(newDataId)))
}
func MysqlGetUserList(c *gin.Context) {
name := c.Query("name")
sqlStr := "select id,user_no,name,age,address from " + tableName + " where name=?"
rows, err := sqlDb.Query(sqlStr, name)
if err != nil {
showError(c, fmt.Sprint(err))
return
}
defer rows.Close()
userList := make([]sqlUserData, 0)
for rows.Next() {
var user sqlUserData
rows.Scan(&user.Id, &user.UserNo, &user.Name, &user.Age, &user.Address)
if user.Age >= 18 {
user.Remarks = "已成年"
} else {
user.Remarks = "未成年"
}
userList = append(userList, user)
}
showSuccess(c, userList)
}
func MysqlGetUserInfo(c *gin.Context) {
id := c.Query("id")
sqlStr := "select id,user_no,name,age,address from " + tableName + " where id=?"
var user sqlUserData
err := sqlDb.QueryRow(sqlStr, id).Scan(&user.Id, &user.UserNo, &user.Name, &user.Age, &user.Address)
if err != nil {
showError(c, fmt.Sprint(err))
return
}
showSuccess(c, user)
}
func MysqlUpdateData(c *gin.Context) {
/*
//请求参数
{
"id":1,
"age":13,
"address":"河北"
}
*/
var user sqlUserData
err := c.Bind(&user)
if err != nil {
showError(c, fmt.Sprint(err))
return
}
sqlStr := "update " + tableName + " set age=? ,address=? where id=?"
ret, err := sqlDb.Exec(sqlStr, user.Age, user.Address, user.Id)
if err != nil {
fmt.Printf("update failed, err:%v\n", err)
showError(c, fmt.Sprint(err))
return
}
res, _ := ret.RowsAffected()
showSuccess(c, "受影响的行数:"+strconv.Itoa(int(res)))
}
func MysqlDeleteData(c *gin.Context) {
id := c.Query("id")
var count int
//先查询
sqlStr := "select count(*) from " + tableName + " where id=?"
err := sqlDb.QueryRow(sqlStr, id).Scan(&count)
if count <= 0 || err != nil {
showError(c, "数据不存在")
return
}
//再删除
delStr := "delete from " + tableName + " where id=?"
ret, err := sqlDb.Exec(delStr, id)
if err != nil {
fmt.Printf("delete failed, err:%v\n", err)
showError(c, fmt.Sprint(err))
return
}
res, _ := ret.RowsAffected()
showSuccess(c, "受影响的行数:"+strconv.Itoa(int(res)))
}
XORM
xorm是一个Go语言的ORM库,通过它可以很方便的操作数据库。它的设计重点是高性能和易用性。XORM支持多种数据库,包括MySQL、PostgreSQL、SQLite、Oracle和SQL Server,并提供了丰富的查询语言。XORM还支持事务和缓存机制,可以提高数据库操作的性能。添加依赖:go get github.com/go-xorm/xorm
ORM,即pobject-RelationlMapping,它的作用是在关系型数据库和对象之间作一个映射,这样我们在具体操作数据库的时候,就不需要再去和复杂的SQL语句打交道,只要像平时操作对象一样操作它就可以了。
比较好的Go语言ORM包括:xorm与gorm
下面是代码实现:
package dbUtil
import (
"fmt"
"github.com/gin-gonic/gin"
_ "github.com/go-sql-driver/mysql"
"github.com/go-xorm/xorm"
"strconv"
"time"
)
var myXorm *xorm.Engine
// 定义结构体(xorm支持双向映射);如果表不存在,则会自动创建
type users struct {
Id int64 `xorm:"pk autoincr" json:"id"` //指定主键并自增
UserNo int `xorm:"unique" json:"user_no"`
Name string `json:"name"`
Age int `json:"age"`
Address string `json:"address"`
CreateTime time.Time `xorm:"created" json:"create_time"`
UpdateTime time.Time `xorm:"updated" json:"update_time"`
}
func init() {
sqlStr := "root:rx123456@tcp(127.0.0.1:3306)/gin_demo?charset=utf8&parseTime=true&loc=Local"
var err error
//创建数据库引擎
myXorm, err = xorm.NewEngine("mysql", sqlStr)
if err != nil {
fmt.Println("数据库连接失败:", err)
}
//创建或者同步表,表名称是users
//如果数据表不存在,会根据users结构体自动创建
err = myXorm.Sync(new(users))
if err != nil {
fmt.Println("数据表同步失败:", err)
}
}
func XormGetUserList(c *gin.Context) {
name := c.Query("name")
var user []users
err := myXorm.Where("name=?", name).And("age>20").Limit(10, 0).Asc("age").Find(&user)
if err != nil {
showError(c, fmt.Sprint(err))
return
}
showSuccess(c, user)
}
func XormGetUserInfo(c *gin.Context) {
id := c.Query("id")
var user []users
err := myXorm.Where("id=?", id).Find(&user)
if err != nil {
showError(c, fmt.Sprint(err))
return
}
if len(user) == 0 {
showSuccess(c, nil)
}
showSuccess(c, user[0])
}
func XormInsertData(c *gin.Context) {
/*
//请求参数
{
"user_no":1001,
"name":"张三",
"age":18,
"address":"北京昌平"
}
*/
var user users
err := c.Bind(&user)
if err != nil {
showError(c, fmt.Sprint(err))
return
}
affected, err := myXorm.Insert(user)
if err != nil || affected <= 0 {
fmt.Printf("insert failed, err:%v\n", err)
showError(c, fmt.Sprint(err))
return
}
showSuccess(c, "受影响的行数:"+strconv.Itoa(int(affected)))
}
func XormUpdateData(c *gin.Context) {
/*
//请求参数
{
"id":1,
"age":13,
"address":"河北"
}
*/
var u users
err := c.Bind(&u)
if err != nil {
showError(c, fmt.Sprint(err))
return
}
//先查找
var user []users
err = myXorm.Where("id=?", u.Id).Find(&user)
//fmt.Println(myXorm.NewSession().LastSQL())
if err != nil {
showError(c, fmt.Sprint(err))
return
}
if len(user) == 0 {
showError(c, "数据不存在")
return
}
//再修改
affected, err := myXorm.Where("id=?", u.Id).Update(&users{
Age: u.Age,
Address: u.Address,
})
if err != nil {
showError(c, fmt.Sprint(err))
return
}
showSuccess(c, "受影响的行数:"+strconv.Itoa(int(affected)))
}
func XormDeleteData(c *gin.Context) {
id := c.Query("id")
//先查找
var user []users
err := myXorm.Where("id=?", id).Find(&user)
if err != nil {
showError(c, fmt.Sprint(err))
return
}
if len(user) == 0 {
showError(c, "数据不存在")
return
}
//再删除
affected, err := myXorm.Where("id=?", id).Delete(&users{})
if err != nil {
showError(c, fmt.Sprint(err))
return
}
showSuccess(c, "受影响的行数:"+strconv.Itoa(int(affected)))
}
GORM
GORM是Go语言中最受欢迎的ORM框架之一。它具有易于使用的API和灵活的查询语言,支持多种类型的数据库,包括MySQL、PostgreSQL、SQLite和SQL Server。GORM还提供了自动迁移功能,可以在应用程序启动时自动创建数据库表和字段。
使用方法:添加依赖 go get gorm.io/gorm
和 go get gorm.io/driver/mysql
实现代码如下:
package dbUtil
import (
"fmt"
"github.com/gin-gonic/gin"
_ "github.com/go-sql-driver/mysql"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"time"
)
var gormDB *gorm.DB
// 定义结构体
// 特别注意:结构体名称为:user,创建的表的名称为:users
type user struct {
Id int `gorm:"primaryKey;autoIncrement" json:"id"` //指定主键并自增
UserNo int `gorm:"unique" json:"user_no"`
Name string `gorm:"type:varchar(256);not null" json:"name"`
Age int `gorm:"type:tinyint(4);not null" json:"age"`
Address string `gorm:"type:varchar(256);not null" json:"address"`
CreateTime time.Time `json:"create_time"`
UpdateTime time.Time `json:"update_time"`
}
func init() {
var err error
sqlStr := "root:rx123456@tcp(127.0.0.1:3306)/gin_demo?charset=utf8mb4&parseTime=true&loc=Local"
gormDB, err = gorm.Open(mysql.Open(sqlStr), &gorm.Config{}) //配置项中预设了连接池 ConnPool
if err != nil {
fmt.Println("数据库连接出错:", err)
return
}
}
// 捕获异常
func catchException(c *gin.Context) {
err := recover()
if err != nil {
showError(c, fmt.Sprint(err))
}
}
func GormGetUserList(c *gin.Context) {
defer func() {
catchException(c)
}()
name := c.Query("name")
myUser := make([]user, 10)
tx := gormDB.Where("name=?", name).Find(&myUser).Limit(10) //查询到的有可能为多行,所以采用结构体切片
if tx.Error != nil {
showError(c, fmt.Sprint(tx.Error))
return
}
showSuccess(c, myUser)
}
func GormGetUserInfo(c *gin.Context) {
defer func() {
catchException(c)
}()
id := c.Query("id")
myUser := user{}
tx := gormDB.Where("id=?", id).First(&myUser)
if tx.Error != nil {
showError(c, fmt.Sprint(tx.Error))
return
}
showSuccess(c, myUser)
}
func GormInsertData(c *gin.Context) {
/*
//请求参数
{
"user_no":1001,
"name":"张三",
"age":18,
"address":"北京昌平"
}
*/
defer func() {
catchException(c)
}()
var myUser user
err := c.Bind(&myUser)
if err != nil {
showError(c, fmt.Sprint(err))
}
fmt.Println("myUser", myUser)
tx := gormDB.Create(&myUser)
fmt.Println(tx)
if tx.RowsAffected > 0 {
showSuccess(c, tx.RowsAffected)
return
} else {
fmt.Printf("insert failed, err:%v\n", err)
showError(c, fmt.Sprint(tx.Error))
}
}
func GormUpdateData(c *gin.Context) {
/*
//请求参数
{
"id":1,
"age":13,
"address":"河北"
}
*/
defer func() {
catchException(c)
}()
var myUser user
err := c.Bind(&myUser)
if err != nil {
showError(c, fmt.Sprint(err))
}
fmt.Println("myUser", myUser)
//先查找
var count int64
gormDB.Model(&user{}).Where("id=?", myUser.Id).Count(&count)
if count == 0 {
showError(c, "数据不存在")
return
}
//再更新
tx := gormDB.Model(&user{}).Where("id=?", myUser.Id).Updates(&myUser)
fmt.Println(tx) //打印结果
if tx.RowsAffected > 0 {
showSuccess(c, tx.RowsAffected)
} else {
showError(c, fmt.Sprint(tx.Error))
}
}
func GormDeleteData(c *gin.Context) {
defer func() {
catchException(c)
}()
id := c.Query("id")
//先查找
var count int64
gormDB.Model(&user{}).Where("id=?", id).Count(&count)
if count == 0 {
showError(c, "数据不存在")
return
}
//再删除
tx := gormDB.Where("id=?", id).Delete(&user{})
fmt.Println(tx) //打印结果
if tx.RowsAffected > 0 {
showSuccess(c, tx.RowsAffected)
} else {
showError(c, fmt.Sprint(tx.Error))
}
}
GORM和XORM都是优秀的ORM框架,它们之间的一些区别:
- 查询语言:GORM使用链式查询语法,而XORM使用结构体作为查询条件。XORM的查询语言更为灵活,可以支持更复杂的查询。
- 性能:XORM的性能比GORM更高,在大量数据的情况下,XORM能够更快地进行数据库操作。
- 易用性:GORM的API比XORM更易用,特别是对于没有ORM经验的开发者来说。
- 社区支持:GORM的社区比XORM更大,因此有更多的文档、示例和插件可以使用。
源代码:https://gitee.com/rxbook/gin-demo/tree/master/dbUtil