我们已经了解了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)
}
使用sql.Open方法会创建一个数据库连接池db。这个db不是数据库连接,它是一个连接池,只有当真正数据库通信的时候才创建连接。例如这里的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的更多相关文章

  1. Gin实战:Gin+Mysql简单的Restful风格的API(二)

    上一篇介绍了Gin+Mysql简单的Restful风格的API,但代码放在一个文件中,还不属于restful风格,接下来将进行进一步的封装. 目录结构 ☁ gin_restful2 tree . ├─ ...

  2. 使用webpy创建一个简单的restful风格的webservice应用

    下载:wget http://webpy.org/static/web.py-0.38.tar.gz解压并进入web.py-0.38文件夹安装:easy_install web.py 这是一个如何使用 ...

  3. PHP实现Restful风格的API

    Restful是一种设计风格而不是标准,比如一个接口原本是这样的: http://www1.qixoo.com/user/view/id/1表示获取id为1的用户信息,如果使用Restful风格,可以 ...

  4. [01] 浅谈RESTful风格的API

    1.什么是RESTful风格的API REST,即Representational State Transfer,可以理解为"(资源的)表现层状态转化". 在网络上,我们通过浏览器 ...

  5. Dubbo 03 Restful风格的API

    目录 Dubbo03 restful风格的API 根路径 协议 版本 用HTTP协议里的动词来实现资源的增删改查 用例 swagger(丝袜哥) OpenAPI 资源 编写API文档 整合Spring ...

  6. 测开大佬告诉你:如何5分钟快速创建restful风格的API接口-使用django restframework框架

    一.思考❓❔ 1.创建API接口难吗? 软件测试工程师: 只测过API接口, 从没创建过 应该需要掌握一门后端开发语言和后端开发框架吧!? 脑容量有限,想想就可怕 2.如何创建API接口呢? 使用Dj ...

  7. PHP实现Restful风格的API(转)

    Restful是一种设计风格而不是标准,比如一个接口原本是这样的: http://www1.qixoo.com/user/view/id/1表示获取id为1的用户信息,如果使用Restful风格,可以 ...

  8. PHP实现RESTful风格的API实例(三)

    接前一篇PHP实现RESTful风格的API实例(二) .htaccess :重写URL,使URL以 /restful/class/1 形式访问文件 Options +FollowSymlinks R ...

  9. PHP实现RESTful风格的API实例(二)

    接前一篇PHP实现RESTful风格的API实例(一) Response.php :包含一个Request类,即输出类.根据接收到的Content-Type,将Request类返回的数组拼接成对应的格 ...

随机推荐

  1. [多线程] Thread

    多线程 概述 单任务处理:一个任务完成后才能进行下一个任务. 多任务处理:CPU分时操作,每个任务看似同时运行. 进程 应用程序的一个运行实例,包含程序所需资源的内存区域,是操作系统进行资源分配的单元 ...

  2. ASP.NET中Onclick和OnserverClick事件的区别 (转)

    对于服务器按钮控件(即<asp:Button>类型的按钮): 服务器响应事件:OnClick 客户端响应属性:OnClientClick 对于html按钮控件(即<input typ ...

  3. CSS文字大小单位PX、EM的区别

    ◆px像素(Pixel)是相对长度单位,像素px是相对于显示器屏幕分辨率而言的.(引自CSS2.0手册)◆em是相对长度单位,相对于当前对象内文本的字体尺寸.如当前对行内文本的字体尺寸未被人为设置,则 ...

  4. iOS ItunesStore 首页推荐

    ItunesStore 首页推荐需要发给苹果一些 app 的相关信息,以及制作一个符合要求的图片. 图片要求可能经过过修改,要求会变化. 以下内容用于参考: 例子 1: Hello, My name ...

  5. Docker 修改镜像源地址

    Docker 官方中国区 https://registry.docker-cn.com 网易 http://hub-mirror.c.163.com ustc https://docker.mirro ...

  6. 【OCP-12c】2019年CUUG OCP 071考试题库(73题)

    73.Which statement correctly grants a system privilege? A. GRANT CREATE VIEW ON table1 TO user1; B. ...

  7. Struts2、SpringMVC、Servlet(Jsp)性能对比 测试

    Struts2.SpringMVC.Servlet(Jsp)性能对比 测试 . Servlet的性能应该是最好的,可以做为参考基准,其它测试都要向它看齐,参照它. 做为一个程序员,对于各个框架的性能要 ...

  8. php防止网站被刷新

    在实际应用中,总会遇到某些页面被恶意用户刷新.当你的系统在某些模块没有使用缓存的时候,频繁的刷新会导致数据库吃紧.下面附上一段代码,防止频繁的刷新造成的死机情况. 主要是从 session方面进行限制 ...

  9. extjs Tree中避免连续单击会连续请求服务器

    应用场景:在项目中我要做一个左边是tree,右边是panel的界面.当我单击tree中的一条记录时,发送请求,并将结果显示在右边的panel中.做完之后发现,如果连续单击就会连续请求两次服务器,毕竟用 ...

  10. 阿里云服务器之hexo环境搭建

    上一步主要主要讲解云服务器购买和连接云服务器,以及文件的操作.本文主要讲解利用hexo搭建自己的静态博客,在服务器中建立自己的hexo博客环境,最后达到可以远程访问,以及远程git推送到github. ...