美文网首页Golang 入门资料+笔记深入浅出golangGolang
【轻知识】Go入门学习整理——第五节,数据入mysql、入red

【轻知识】Go入门学习整理——第五节,数据入mysql、入red

作者: 言十年 | 来源:发表于2019-05-03 17:58 被阅读7次

    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.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"] = "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.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的方式。

    参考资料:

    相关文章

      网友评论

        本文标题:【轻知识】Go入门学习整理——第五节,数据入mysql、入red

        本文链接:https://www.haomeiwen.com/subject/nrponqtx.html