我们已经了解了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(11) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(64) DEFAULT NULL, `telephone` varchar(12) DEFAULT '', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=13 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(20) db.SetMaxOpenConns(20) if err := db.Ping(); err != nil{ log.Fatalln(err) }
使用sql.Open方法会创建一个数据库连接池db。这个db不是数据库连接,它是一个连接池,只有当真正数据库通信的时候才创建连接。例如这里的
如果不设置,默认都是0,表示打开的连接没有限制。我在压测的时候,发现会存在大量的TIME_WAIT状态的连接,虽然mysql的连接数没有上升。设置了这两个参数之后,不在存在大量TIME_WAIT状态的连接了。而且qps也没有明显的变化,出于对数据库的保护,最好设置这连个参数。
db.Ping
的操作。
db.SetMaxIdleConns(20)
和
db.SetMaxOpenConns(20)
分别设置数据库的空闲连接和最大打开连接,即向Mysql服务端发出的所有连接的最大数目。
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返回给客户端。请求得到的结果如下:
扫描二维码关注公众号,回复:
1786443 查看本文章
查
查询列表 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 }
返回结果如下: