go gin学习记录4

Posted 梁吉林

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go gin学习记录4相关的知识,希望对你有一定的参考价值。

环境

环境:mac m1,go version 1.17.2, goland, mysql

除了原生sql,和orm操作之外,go还有一类包,只用于生成sql,典型的如sqlbuilder,今天就来研究一下它。

安装sqlbuilder

首先需要安装:

$ go get github.com/huandu/go-sqlbuilder
go: downloading github.com/huandu/go-sqlbuilder v1.19.0
go get: added github.com/huandu/go-sqlbuilder v1.19.0
go get: added github.com/huandu/xstrings v1.3.2

测试准备

为了实验,需要准备一个测试数据表,这里就按照第一节的user来复制一个worker表出来:

mysql> create table worker like user;
Query OK, 0 rows affected (0.02 sec)

接下来就到了创建controller和router group的节点了,第二节和第三节已经做了两遍,这里就直接贴代码了。
main.go:

	worker := r.Group("/worker")
	
		workerCtrl := controller.WorkerController
		worker.POST("/createWorker", workerCtrl.CreateWorker)
		worker.GET("/getWorkerInfo", workerCtrl.GetWorkerInfo)
		worker.POST("/updateWorkerInfo", workerCtrl.UpdateWorkerInfo)
	

controller/worker.go:

package controller

import (
	"github.com/gin-gonic/gin"
)

type WorkerController struct 
	ID    int    `json:"id"`
	Name  string `json:"name"`
	Birth string `json:"birth"`


func (w *WorkerController) CreateWorker(c *gin.Context) 
	


func (w *WorkerController) GetWorkerInfo(c *gin.Context) 



func (w *WorkerController) UpdateWorkerInfo(c *gin.Context) 


好的,前面这些重复的流程都搞定了。

sqlbuilder-插入操作

接下来我们开始完善代码,同样先从插入操作开始完善。

func (w *WorkerController) CreateWorker(c *gin.Context) 
	name := c.PostForm("name")
	birth := c.PostForm("birth")

	sb := sqlbuilder.NewInsertBuilder()
	sb.InsertInto("worker")
	sb.Cols("name", "birth")
	sb.Values(name, birth)

	sqlString, args := sb.Build()
	log.Println(sqlString, args)

	db, err := sql.Open("mysql", "root:@tcp(127.0.0.1:3306)/t_gin?charset=utf8&parseTime=true")
	if err != nil 
		log.Panic(err.Error())
	

	_, err = db.Exec(sqlString, args)
	if err != nil 
		log.Panic(err.Error())
	

	c.JSON(http.StatusOK, gin.H
		"code": 0,
		"data": true,
	)

运行一下看看

出错了。
好吧,看看是什么问题。
查一下terminal,能够看到打印出来的sql语句,已经一条错误信息:

2023/02/20 16:53:36 INSERT INTO worker (name, birth) VALUES (?, ?) [tata 2008-1-1]
2023/02/20 16:53:36 sql: converting argument $1 type: unsupported type []interface , a slice of interface

定位一下错误,发现是exec操作给的参数有点问题,因为Exec操作接收的参数是这样的:

func (db *DB) Exec(query string, args ...interface) (Result, error) 
	return db.ExecContext(context.Background(), query, args...)

我们调整一下代码:

	_, err = db.Exec(sqlString, args...)

重新运行项目,这次是成功了
看一下数据库,数据正确插入了

mysql> select * from worker;
+----+------+----------+
| id | name | birth    |
+----+------+----------+
|  2 | tata | 2008-1-1 |
+----+------+----------+
1 row in set (0.00 sec)

sqlbuilder-查询操作

好的,接下来再完善查询操作。

func (w *WorkerController) GetWorkerInfo(c *gin.Context) 
	id := c.Query("id")

	sb := sqlbuilder.NewSelectBuilder()
	sb.From("worker")
	sb.Select("name,birth")
	sb.Where(sb.Equal("id", id))

	sqlString, args := sb.Build()
	log.Println(sqlString, args)

	db, err := sql.Open("mysql", "root:@tcp(127.0.0.1:3306)/t_gin?charset=utf8&parseTime=true")
	if err != nil 
		log.Panic(err.Error())
	

	result := db.QueryRow(sqlString, args...)

	var worker Worker
	err = result.Scan(&worker.ID, &worker.Name, &worker.Birth)
	if err != nil 
		log.Panic(err.Error())
	

	c.JSON(http.StatusOK, gin.H
		"code": 0,
		"data": worker,
	)

运行看看

又出错了
看下终端的输出:

2023/02/20 17:13:44 SELECT name,birth FROM worker WHERE id = ? [2]
2023/02/20 17:13:44 sql: expected 2 destination arguments in Scan, not 3

错误指向scan操作,说是只需要两个,却给了3个
检查代码后发现,是在生成sql时,select只查了name、birth两个字段,scan的时候却给了id、name、birth3个。
我们调整一下代码,将scan中的id去掉:

	err = result.Scan(&worker.Name, &worker.Birth)

然后我们再运行:

好的,这次是成功的。
但是,有没有发现返回的数据是有问题的,id是0。
因为返回的是定义的struct,而查询时只查询了指定的字段,并没给id赋值,所以id字段用了一个默认值。
通过查询指定和结果绑定,就可以解决这个问题了。

sqlbuilder-更新操作

继续完善更新操作

func (w *WorkerController) UpdateWorkerInfo(c *gin.Context) 
	id := c.PostForm("id")
	name := c.PostForm("name")

	sb := sqlbuilder.NewUpdateBuilder()
	sb.Update("worker")
	sb.Where(sb.Equal("id", id))
	sb.SetMore(sb.Assign("name", name))

	sqlString, args := sb.Build()
	log.Println(sqlString, args)

	db, err := sql.Open("mysql", "root:@tcp(127.0.0.1:3306)/t_gin?charset=utf8&parseTime=true")
	if err != nil 
		log.Panic(err.Error())
	

	_, err = db.Exec(sqlString, args...)
	if err != nil 
		log.Panic(err.Error())
	

	c.JSON(http.StatusOK, gin.H
		"code": 0,
		"data": true,
	)

运行一下看看

运行成功了,我们看看数据表中的数据:

mysql> select * from worker;
+----+-----------+----------+
| id | name      | birth    |
+----+-----------+----------+
|  2 | this name | 2008-1-1 |
+----+-----------+----------+
1 row in set (0.03 sec)

也没有问题,符合预期。

然后呢?

sqlbuilder作为原生sql和orm之间的地带,适合什么样子的场景呢?我暂时还没有想到。

sqlbuilder比原生的多了一些复合操作,但它的功能就是用来生成SQL语句,具体的执行还是需要原生的db操作去执行。

而相比于gorm,它又显得过于简陋。当然好处是更浅显一些。
需求当中怎么选择,看个人的倾向吧。

今天就到这。

以上是关于go gin学习记录4的主要内容,如果未能解决你的问题,请参考以下文章

go gin学习记录2

go gin学习记录4

Go语言web框架 gin

go gin学习记录5

学习go gin框架

学习go gin框架