Gin实战:Gin+Mysql简单的Restful风格的API
我们已经了解了Golang的Gin框架。对于Webservice服务,restful风格几乎一统天下。Gin也天然的支持restful。下面就使用gin写一个简单的服务,麻雀虽小,五脏俱全。我们先以一个单文件开始,然后再逐步分解模块成包,组织代码。
Hello World
使用Gin的前提是安装,我们需要安装gin和mysql的驱动,具体的安装方式就不在赘述。
创建一个文件夹用来为项目,新建一个文件main.go:
☁ newland tree
.
└── main.go
main.go
package main import (
"gopkg.in/gin-gonic/gin.v1"
"net/http"
) func main() {
router := gin.Default() router.GET("/", func(c *gin.Context) {
c.String(http.StatusOK, "Hello world")
}) router.Run(":8801")
}
编译运行

数据库
安装完毕框架,完成一次请求响应之后。接下来就是安装数据库驱动和初始化数据相关的操作了。首先,我们需要新建数据表。一个及其简单的数据表:
CREATE TABLE `users` (
`id` int() unsigned NOT NULL AUTO_INCREMENT,
`name` varchar() DEFAULT NULL,
`telephone` varchar() DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT= DEFAULT CHARSET=utf8mb4;
创建数据表之后,初始化数据库连接池:
db, err := sql.Open("mysql", "root:@tcp(127.0.0.1:3306)/test?parseTime=true")
if err != nil{
log.Fatalln(err)
}
defer db.Close()
db.SetMaxIdleConns()
db.SetMaxOpenConns()
if err := db.Ping(); err != nil{
log.Fatalln(err)
}
db.Ping的操作。db.SetMaxIdleConns(20)和db.SetMaxOpenConns(20)分别设置数据库的空闲连接和最大打开连接,即向Mysql服务端发出的所有连接的最大数目。如果不设置,默认都是0,表示打开的连接没有限制。我在压测的时候,发现会存在大量的TIME_WAIT状态的连接,虽然mysql的连接数没有上升。设置了这两个参数之后,不在存在大量TIME_WAIT状态的连接了。而且qps也没有明显的变化,出于对数据库的保护,最好设置这连个参数。
CURD 增删改查
Restful的基本就是对资源的curd操作。下面开启我们的第一个api接口,增加一个资源。
增
var db *sql.DB
type Person struct {
Id int `json:"id" form:"id"`
Name string `json:"name" form:"name"`
Telephone string `json:"telephone" form:"telephone"`
}
func main() {
...
//增加一条记录
router.POST("/add", func(c *gin.Context) {
name := c.Request.FormValue("name")
telephone := c.Request.FormValue("telephone")
person := Person{
Name:name,
Telephone:telephone,
}
id := person.Create()
msg := fmt.Sprintf("insert successful %d", id)
c.JSON(http.StatusOK, gin.H{
"msg": msg,
})
})
...
}
//插入
func (person *Person) Create() int64 {
rs, err := db.Exec("INSERT into users (name, telephone) value (?,?)", person.Name, person.Telephone)
if err != nil{
log.Fatal(err)
}
id, err := rs.LastInsertId()
if err != nil{
log.Fatal(err)
}
return id
}
func checkErr(err error) {
if err != nil{
panic(err)
}
}
执行非query操作,使用db的Exec方法,在mysql中使用?做占位符。最后我们把插入后的id返回给客户端。请求得到的结果如下:

查
查询列表 Query
上面我们增加了一条记录,下面就获取这个记录,查一般有两个操作,一个是查询列表,其次就是查询具体的某一条记录。两种大同小异。
为了给查询结果绑定到golang的变量或对象,我们需要先定义一个结构来绑定对象。
router.GET("/users", func(c *gin.Context) {
rs, _ := getRows()
c.JSON(http.StatusOK, gin.H{
"list": rs,
})
})
//查询所有记录
func getRows() (persons []Person, err error) {
rows, err := db.Query("select id,name,telephone from users")
for rows.Next(){
person := Person{}
err := rows.Scan(&person.Id, &person.Name, &person.Telephone)
if err != nil {
log.Fatal(err)
}
persons = append(persons, person)
}
rows.Close()
return
}
返回结果如下:

查询单条记录 QueryRow
查询列表需要使用迭代rows对象,查询单个记录,就没这么麻烦了。虽然也可以迭代一条记录的结果集。因为查询单个记录的操作实在太常用了,因此golang的database/sql也专门提供了查询方法
router.GET("/users/:id", func(c *gin.Context) {
id_string := c.Param("id")
id, _ := strconv.Atoi(id_string)
rs, _ := getRow(id)
c.JSON(http.StatusOK, gin.H{
"result": rs,
})
})
//查询一条记录
func getRow(id int) (person Person, err error) {
person = Person{}
err = db.QueryRow("select id,name,telephone from users where id = ?", id).Scan(&person.Id, &person.Name, &person.Telephone)
return
}
返回结果如下:

改
增删改查,下面进行更新的操作。
router.POST("/users/update", func(c *gin.Context) {
ids := c.Request.FormValue("id")
id, _ := strconv.Atoi(ids)
telephone := c.Request.FormValue("telephone")
person := Person{
Id:id,
Telephone:telephone,
}
row := person.Update()
msg := fmt.Sprintf("updated successful %d", row)
c.JSON(http.StatusOK, gin.H{
"msg": msg,
})
})
/修改
func (person *Person) Update() int64{
rs, err := db.Exec("update users set telephone = ? where id = ?", person.Telephone, person.Id)
if err != nil {
log.Fatal(err)
}
rows, err := rs.RowsAffected()
if err != nil {
log.Fatal(err)
}
return rows
}
返回结果如下:

删
最后一个操作就是删除了,删除所需要的功能特性,上面的例子都覆盖了。实现删除也就特别简单了:
//删除一条记录
router.POST("/users/del", func(c *gin.Context) {
ids := c.Request.FormValue("id")
id, _ := strconv.Atoi(ids)
row := Delete(id)
msg := fmt.Sprintf("delete successful %d", row)
c.JSON(http.StatusOK, gin.H{
"msg": msg,
})
}) func Delete(id int) int64 {
rs, err := db.Exec("delete from users where id = ?", id)
if err != nil {
log.Fatal()
}
rows, err := rs.RowsAffected()
if err != nil {
log.Fatal()
}
return rows
}
返回结果:

至此,基本的CURD操作的restful风格的API已经完成。内容其实不复杂,甚至相当简单。
Gin实战:Gin+Mysql简单的Restful风格的API的更多相关文章
- Gin实战:Gin+Mysql简单的Restful风格的API(二)
上一篇介绍了Gin+Mysql简单的Restful风格的API,但代码放在一个文件中,还不属于restful风格,接下来将进行进一步的封装. 目录结构 ☁ gin_restful2 tree . ├─ ...
- 使用webpy创建一个简单的restful风格的webservice应用
下载:wget http://webpy.org/static/web.py-0.38.tar.gz解压并进入web.py-0.38文件夹安装:easy_install web.py 这是一个如何使用 ...
- PHP实现Restful风格的API
Restful是一种设计风格而不是标准,比如一个接口原本是这样的: http://www1.qixoo.com/user/view/id/1表示获取id为1的用户信息,如果使用Restful风格,可以 ...
- [01] 浅谈RESTful风格的API
1.什么是RESTful风格的API REST,即Representational State Transfer,可以理解为"(资源的)表现层状态转化". 在网络上,我们通过浏览器 ...
- Dubbo 03 Restful风格的API
目录 Dubbo03 restful风格的API 根路径 协议 版本 用HTTP协议里的动词来实现资源的增删改查 用例 swagger(丝袜哥) OpenAPI 资源 编写API文档 整合Spring ...
- 测开大佬告诉你:如何5分钟快速创建restful风格的API接口-使用django restframework框架
一.思考❓❔ 1.创建API接口难吗? 软件测试工程师: 只测过API接口, 从没创建过 应该需要掌握一门后端开发语言和后端开发框架吧!? 脑容量有限,想想就可怕 2.如何创建API接口呢? 使用Dj ...
- PHP实现Restful风格的API(转)
Restful是一种设计风格而不是标准,比如一个接口原本是这样的: http://www1.qixoo.com/user/view/id/1表示获取id为1的用户信息,如果使用Restful风格,可以 ...
- PHP实现RESTful风格的API实例(三)
接前一篇PHP实现RESTful风格的API实例(二) .htaccess :重写URL,使URL以 /restful/class/1 形式访问文件 Options +FollowSymlinks R ...
- PHP实现RESTful风格的API实例(二)
接前一篇PHP实现RESTful风格的API实例(一) Response.php :包含一个Request类,即输出类.根据接收到的Content-Type,将Request类返回的数组拼接成对应的格 ...
随机推荐
- Codeforces Beta Round #75 (Div. 1 Only) B. Queue 二分
B. Queue Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 codeforces.com/problemset/problem/91/B Descrip ...
- pkuwc 前的任务计划
菜鸡 wxw 的计划(肯定会咕咕咕 12.27 luogu P4244 [SHOI2008]仙人掌图 II(咕咕咕 luogu P4246 [SHOI2008]堵塞的交通 (没有咕! luogu P1 ...
- LOJ#3085. 「GXOI / GZOI2019」特技飞行(KDtree+坐标系变换)
题面 传送门 前置芝士 请确定您会曼哈顿距离和切比雪夫距离之间的转换,以及\(KDtree\)对切比雪夫距离的操作 题解 我们发现\(AB\)和\(C\)没有任何关系,所以关于\(C\)可以直接暴力数 ...
- BZOJ4766: 文艺计算姬(Prufer序列)
题面 传送门 题解 结,结论题? 答案就是\(n^{m-1}m^{n-1}\) 我们考虑它的\(Prufer\)序列,最后剩下的两个点肯定是一个在左边一个在右边,设左边\(n\)个点,右边\(m\)个 ...
- 干货 | 精选《SQL注入、渗透、反病毒》学习总结集锦给你们~
学到手的都是本事,如果觉得对你有帮助也欢迎分享给身边的基友们吧! 分享干货,手留余香哦~ 本次“开学季拜师活动”的徒弟们在师父的精心指导下,在短短5天内得到了迅速地成长,以前或当时遇到的问题都能够柳暗 ...
- apollo配置中心初探
近在搞微服务框架的开发,需要有一个配置中心来满足统一管理业务应用以及组件的配置,在此期间也使用了多个配置中心比如:spring cloud config,自研的配置中心,当然还有apollo. spr ...
- tf入门-池化函数 tf.nn.max_pool 的介绍
转载自此大神 http://blog.csdn.net/mao_xiao_feng/article/details/53453926 max pooling是CNN当中的最大值池化操作,其实用法和卷积 ...
- 我把阿里云centos gcc从4.4.7升级到4.8.2的经历
我有试着去手动编译安装gcc,可是make的速度实在太慢,最后还直接失败了. 最后在csdn找到了个博客,说是使用yum来安装,网址为: http://blog.csdn.net/ppdouble/a ...
- c++之选择排序和冒泡排序实现
1.冒泡排序 冒泡排序就是通过对比前一个和后一个数的大小,按照规则进行顺序的调换.每一轮对比之后最大或者最小值都会浮到最上面或者沉到最低下. 如:对这一数组进行冒泡排序:int a[5]{34,12 ...
- C#-一维数组——★★冒泡排序★★
////★★★★★冒泡排序 ; i < a - ; i++) { ; j < a; j++) { if (age[i] < age[j]) { int zhong = age[i]; ...