我们已经了解了Golang的Gin框架。对于Webservice服务,restful风格几乎一统天下。Gin也天然的支持restful。下面就使用gin写一个简单的服务,麻雀虽小,五脏俱全。我们先以一个单文件开始,然后再逐步分解模块成包,组织代码。
It works
使用Gin的前提是安装,我们需要安装gin和mysql的驱动,具体的安装方式就不在赘述。可以参考Golang 微框架Gin简介和Golang持久化。
创建一个文件夹用来为项目,新建一个文件main.go:
☁ newgin 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, "It works")
})
router.Run(":8000")
}
编译运行
☁ newgin go run main.go
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)
[GIN-debug] GET / --> main.main.func1 (3 handlers)
[GIN-debug] Listening and serving HTTP on :8000
访问 /
即可看见我们返回的字串It works
数据库
安装完毕框架,完成一次请求响应之后。接下来就是安装数据库驱动和初始化数据相关的操作了。首先,我们需要新建数据表。一个及其简单的数据表:
CREATE TABLE `person` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`first_name` varchar(40) NOT NULL DEFAULT '',
`last_name` varchar(40) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
创建数据表之后,初始化数据库连接池:
func main() {
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(20)
db.SetMaxOpenConns(20)
if err := db.Ping(); err != nil{
log.Fatalln(err)
}
router := gin.Default()
router.GET("/", func(c *gin.Context) {
c.String(http.StatusOK, "It works")
})
router.Run(":8000")
}
使用sql.Open方法会创建一个数据库连接池db。这个db不是数据库连接,它是一个连接池,只有当真正数据库通信的时候才创建连接。例如这里的db.Ping
的操作。db.SetMaxIdleConns(20)
和db.SetMaxOpenConns(20)
分别设置数据库的空闲连接和最大打开连接,即向Mysql服务端发出的所有连接的最大数目。
如果不设置,默认都是0,表示打开的连接没有限制。我在压测的时候,发现会存在大量的TIME_WAIT状态的连接,虽然mysql的连接数没有上升。设置了这两个参数之后,不在存在大量TIME_WAIT状态的连接了。而且qps也没有明显的变化,出于对数据库的保护,最好设置这连个参数。
CURD 增删改查
Restful的基本就是对资源的curd操作。下面开启我们的第一个api接口,增加一个资源。
增
func main() {
...
router.POST("/person", func(c *gin.Context) {
firstName := c.Request.FormValue("first_name")
lastName := c.Request.FormValue("last_name")
rs, err := db.Exec("INSERT INTO person(first_name, last_name) VALUES (?, ?)", firstName, lastName)
if err != nil {
log.Fatalln(err)
}
id, err := rs.LastInsertId()
if err != nil {
log.Fatalln(err)
}
fmt.Println("insert person Id {}", id)
msg := fmt.Sprintf("insert successful %d", id)
c.JSON(http.StatusOK, gin.H{
"msg": msg,
})
})
...
}
执行非query操作,使用db的Exec方法,在mysql中使用?
做占位符。最后我们把插入后的id返回给客户端。请求得到的结果如下:
☁ ~ curl -X POST http://127.0.0.1:8000/person -d "first_name=hello&last_name=world" | python -m json.tool
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 62 100 30 100 32 5054 5391 --:--:-- --:--:-- --:--:-- 6400
{
"msg": "insert