33

【轻知识】Go入门学习整理——第五节,数据入mysql、入redis、包管理、beego框架略览

 5 years ago
source link: https://studygolang.com/articles/20178?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

界面如下

NbUrAnI.png!web

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里面找。

但使用的过程中报错了。我找到了一条issue https://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的方式。

参考资料:


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK