mysql
继续上节的代码。上节的代码是把数据存到了数组中。相当于存到了内存中了。现在操作MySQL。添加数据到mysql中,从mysql中查询数据,并删除
一个类库的使用似乎没有什么太难的。
test库yan_user表。
CREATE TABLE `yan_user` (
`id` SMALLINT(5) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(60) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
操作库用这个https://github.com/go-sql-driver/mysql。go get -u github.com/go-sql-driver/mysql。
把添加的名字落入数据库。
db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/test")
defer db.Close()
if err != nil {
panic(err)
}
stmt, err := db.Prepare("INSERT INTO yan_user SET name=?")
if err != nil {
panic(err)
}
res, err := stmt.Exec(name)
if err != nil {
panic(err)
}
id, err := res.LastInsertId()
if err != nil {
panic(err)
}
查询的那块也从mysql中查询。
db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/test")
defer db.Close()
if err != nil {
panic(err)
}
rows, err := db.Query("SELECt * FROM yan_user")
if err != nil {
panic(err)
}
var nameList []map[string]interface{}
for rows.Next() {
var id int
var name string
err = rows.Scan(&id, &name)
if err != nil {
panic(err)
}
nameList = append(nameList, map[string]interface{}{"id": id, "name": name})
}
redis
类库使用的是https://github.com/go-redis/redis。
go get -u github.com/go-redis/redis
在添加名字,名字入库的时候,把id 跟name存入list中。
// 插入到redis中
client := redis.NewClient(&redis.Options{
Addr: "x.x.x.x:18000",
Password: "", // no password set
DB: 0, // use default DB
})
pong, err := client.Ping().Result()
fmt.Println(pong, err)
jsonRes, err := json.Marshal(map[string]interface{}{"id": id, "name": name})
if err != nil {
panic(err)
}
client.LPush("name_list", jsonRes)
然后再写一个接口是从redis查出来的数据。
http.HandleFunc("/search_from_redis", func(w http.ResponseWriter, r *http.Request) {
// 插入到redis中
client := redis.NewClient(&redis.Options{
Addr: "x0.x0.xx.15:18000",
Password: "", // no password set
DB: 0, // use default DB
})
pong, err := client.Ping().Result()
fmt.Println(pong, err)
res, err := client.LRange(nameListKey, 0, 100).Result()
if err != nil {
panic(err)
}
type Name struct {
Id int `json:"id"`
Name string `json:"name"`
}
var name Name
var nameList []Name
for _, value := range res {
json.Unmarshal([]byte(value), &name)
nameList = append(nameList, name)
}
data := map[string]interface{}{"name_list": nameList}
list, err := json.Marshal(data)
if err != nil {
fmt.Println("json.Marshal failed:", err)
return
}
w.Header().Add("Content-Type", "application/json")
fmt.Fprintf(w, string(list)) //这个写入到w的是输出到客户端的
})
界面如下
包管理工具
上面我们go get了mysql 跟redis 的库。这个库放到了我配置的第一个gopath下面了。
vendor目录。
现在我在代码中import里面引入一个随便写的类库github.com\go-d
。编辑器就会告诉你没有在gopath中找到。如果在src下面创建了一个vendor目录,报错信息的第一条就是vendor下面没有这个库。
vendor是1.5版本后加的。查找依赖包的解决方案如下(摘自极客时间):
1.当前包下的vendor目录
2.向上级目录查找,直到找到src下的vendor 目录
3.在GOPATH下面查找依赖包
4.在GOROOT目录下查找
但你看控制台从报错信息中就能看出规律。如下是我的:
cannot find package "github.com/go-d" in any of:
F:\iProject\xiaotianquan\src\vendor\github.com\go-d (vendor tree)
C:\Go\src\github.com\go-d (from $GOROOT)
F:\iProject\gopath\src\github.com\go-d (from $GOPATH)
F:\iProject\xiaotianquan\src\github.com\go-d
依赖管理的工具有好几个。文末参考资料中自行了解。
glide
安装方式去官方文档。
windows的话,因为我安装过gitbash
,所以在gitbash中执行curl https://glide.sh/get | sh
也就安装好了(安装到了go/bin目录下了)。(但我的版本有问题,下面会说到。不得不去github上找低版本的https://github.com/Masterminds/glide/releases)
我在之前的代码中又拷贝了一份目录(web3)。在main.go(我demo的文件)同级目录下。我执行glide init ,看到了glide.yaml文件,文件的内容。
package: web3
import:
- package: github.com/go-redis/redis
version: v6.15.2
- package: github.com/go-sql-driver/mysql
version: v1.4.1
是不是有种composer的感觉。
执行glide ,会在我web3(web3在src目录下)的目录下生成一个vendor目录(而不是在src)。那么下次引入其他的类库会在这个vendor里面找。
但使用的过程中报错了。我找到了一条issuehttps://github.com/Masterminds/glide/issues/873
。应该该版本在windows下的问题。我安装的版本是glide version v0.13.2。有人说这个版本0.12.3有效。
Unable to export dependencies to vendor directory: Error moving files: exit status 1. output: Access is denied.
0 dir(s) moved.
0.12.3 确实可以。我把下载glide 放到了go/bin下面替换了之前安装的版本。
然后执行glide install。vendor目录下就有了相关的类库了。这样以后依赖管理就方便了。我的包也不用去都放到一个gopath下了(甚至就放到我的项目目录下的vendor里面)。
更多使用glide版本管理的方式。请看官网:https://glide.readthedocs.io
beego框架略览
到现在细数下做到的功能。
1.模板渲染
2.mysql操作
3.redis操作
4.json操作
5.版本管理(glide)
OK,到现在我们已经具备了CURD的能力(虽然我没有写D跟U的代码)。来看一个框架beego。有人说这是go的ThinkPHP。
安装bee工具。go get github.com/beego/bee。
我拷贝一个文件夹起名为web4。进入其目录。创建一个项目bee new myproject
cd myproject,执行 bee run。提示我main.go:5:2: cannot find package "github.com/astaxie/beego
。OK,没关系。我开始安装下beego。这次就用glide去管理吧。
在myproject 执行glide init。然后glide install。
OK,bee run执行(由于我本地装了Jenkins,我需要到conf/app.conf改成其他端口,比如8081吧)
OK,http://127.0.0.1:8081/ 你看到了Welcome to Beego
。
beego 版 名单
controllers下面我们新建一个name.go。我就把整个代码贴下去了哈。
package controllers
import (
"encoding/json"
"fmt"
"github.com/astaxie/beego"
"github.com/astaxie/beego/orm"
"github.com/gomodule/redigo/redis"
)
type NameController struct {
beego.Controller
}
func (c *NameController) Get() {
c.Data["Website"] = "beego.me"
c.Data["Email"] = "[email protected]"
c.TplName = "name/index.tpl"
}
func (c *NameController) Add() {
name := c.Input().Get("name")
o := orm.NewOrm()
r := o.Raw("INSERT INTO yan_user SET name=?", name)
res, err := r.Exec()
if err != nil {
panic(err)
}
id, err := res.LastInsertId()
if err != nil {
panic(err)
}
c.Data["json"] = &id
conn, err := redis.Dial("tcp", "xx.x0.x.x5:18000")
if err != nil {
panic(err)
}
defer conn.Close()
jsonRes, err := json.Marshal(map[string]interface{}{"id": id, "name": name})
if err != nil {
panic(err)
}
conn.Do("lpush", "name_list", jsonRes)
c.ServeJSON()
}
func (c *NameController) Search() {
type Name struct {
Id int `json:"id"`
Name string `json:"name"`
}
var nameList []Name
o := orm.NewOrm()
num, err := o.Raw("SELECT * FROM yan_user").QueryRows(&nameList)
if err != nil {
panic(err)
}
fmt.Println("user nums: ", num)
data := map[string][]Name{"name_list": nameList}
c.Data["json"] = &data
c.ServeJSON()
}
func (c *NameController) SearchFromRedis() {
conn, err := redis.Dial("tcp", "xx.xx.x.xx:18000")
if err != nil {
panic(err)
}
defer conn.Close()
res, err := redis.Values(conn.Do("lrange", "name_list",0 ,100))
if err != nil {
panic(err)
}
type Name struct {
Id int `json:"id"`
Name string `json:"name"`
}
var name Name
var nameList []Name
for _, value := range res {
json.Unmarshal(value.([]byte), &name)
nameList = append(nameList, name)
}
data := map[string]interface{}{"name_list": nameList}
if err != nil {
fmt.Println("json.Marshal failed:", err)
return
}
c.Data["json"] = &data
c.ServeJSON()
}
配置路由
beego.Router("/", &controllers.MainController{})
beego.Router("/name/index", &controllers.NameController{})
beego.Router("/name/add", &controllers.NameController{},"post:Add")
beego.Router("/name/search", &controllers.NameController{},"post:Search")
beego.Router("/name/search_from_redis", &controllers.NameController{},"post:SearchFromRedis")
初始化的一些配置。在入口main.go,需要做下面的事情。
- 指定数据库 (一定别忘了指定数据库驱动github.com/go-sql-driver/mysql,不引入会报
register db
default, sql: unknown driver "mysql" (forgotten import?)
) - 模板解析的左右标签改下(因为会跟vue冲突)
package main
import (
_ "web4/myproject/routers"
"github.com/astaxie/beego"
_ "github.com/go-sql-driver/mysql"
"github.com/astaxie/beego/orm"
)
func init() {
orm.RegisterDriver("mysql", orm.DRMySQL)
orm.RegisterDataBase("default", "mysql", "root:root@/test?charset=utf8")
}
func main() {
beego.BConfig.WebConfig.TemplateLeft = "<<<"
beego.BConfig.WebConfig.TemplateLeft = ">>>"
beego.Run()
}
文档中redis 缓存
使用缓存别忘下载对应的文件。
glide get github.com/astaxie/beego/cache
glide get github.com/gomodule/redigo/redis
用法,头部先引入
"github.com/astaxie/beego/cache"
_ "github.com/astaxie/beego/cache/redis"
bm, err := cache.NewCache("redis", `{"conn":"xx.x.x.x:18000"}`)
if err != nil {
panic(err)
}
timeoutDuration := 100 * time.Second // 当然这里还需要引入time包。
err = bm.Put("aaaa", "2222", timeoutDuration)
看下配置
{"key":"collectionName","conn":":6039","dbNum":"0","password":"thePassWord"}
文档中说是key: Redis collection 的名称
。没搞明白是啥意思。追了下代码,看明白了。这个key就是前缀。比如你想在代码中Put("name","xiaoming", 100 * time.Second),实际上key如果你不指定默认就是beecacheRedis:name
。如果你指定了就是key:name。如果指定的key为空字符串。那么就是:name(不会因为你填的空白字符串,而把冒号去掉。)。所以当你纠结在中断找不get的不到的时候,别忘了前缀哈。
key的拼接在./github.com/astaxie/beego/cache/redis/redis.go
中。如下:
func (rc *Cache) associate(originKey interface{}) string {
return fmt.Sprintf("%s:%s", rc.key, originKey)
}
由于Cache 封装的方法太少。我想用redis list 的功能,只能直接用redigo方法了(代码参考上面的name.go代码)。
总结
这里没有提及到orm的使用。实际上,参考文档就会马上完成用orm的方式。
参考资料:
- 《build-web-application-with-golang》https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/preface.md
*《Go database/sql tutorial》http://go-database-sql.org/index.html - 《go依赖包管理工具对比》https://ieevee.com/tech/2017/07/10/go-import.html
- 《包管理工具 glide》https://learnku.com/articles/23503/package-management-tool-glide
- 《Go语言从入门到实战》极客时间,蔡超,22节依赖管理