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的是输出到客户端的
})

界面如下

image.png

包管理工具

上面我们go get了mysql 跟redis 的库。这个库放到了我配置的第一个gopath下面了。

vendor目录。

现在我在代码中import里面引入一个随便写的类库github.comgo-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:iProjectxiaotianquansrcvendorgithub.comgo-d (vendor tree)
    C:Gosrcgithub.comgo-d (from GOROOT)
    F:iProjectgopathsrcgithub.comgo-d (fromGOPATH)
    F:iProjectxiaotianquansrcgithub.comgo-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"] = "astaxie@gmail.com"

    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 dbdefault, 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.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节依赖管理

文章来源于互联网,如有雷同请联系站长删除:【轻知识】Go入门学习整理——第五节,数据入mysql、入redis、包管理glide、beego框架略览

发表评论