redis缓存数据库安装与golang中使用

redis缓存数据库安装与golang中使用

二月 22, 2019

最近公司在写数据可视化平台的一个项目,提供给公司运营内部使用。关于运营用户这方面,打算直接使用对应app的运营管理平台(另外一个使用java服务端)调用登陆接口,java服务端已经编写好接口,这边golang直接调用他们那的接口,这边处理存储请求获取到的用户信息和存储token的功能,就有了redis缓存相关的操作。在测试中,本来是用的运营管理平台的redis缓存服务器,不过我打算在我自己的服务器,直接搭建个redis缓存数据库。仅记此文章,作为查询和学习的记录。

安装

  • 在redis官网中下载tar.gz压缩包,保证最新版,在你当前的目录下(我的是在/home/download/中)
    1
    2
    3
    4
    5
    # 解压缩
    tar xzf redis-x.x.xx.tar.gz
    # cd进去进行编译
    cd redis-x.x.xx.tar.gz
    make
  • 编译完,在当前目录下会生成src的目录,编译完成的所有项都在这里面(redis-server、redis-cli)
    1
    2
    3
    4
    5
    # 当前目录:/home/download/redis-x.x.xx
    # 将redis文件移动到/usr/local/目录下,不移动也可以,我不打算做环境变量,保证我每次都能记得文件包在哪
    # 请务必记得也移动redis.conf配置文件
    cp -r ./src /usr/local/redis
    cp ./redis.conf /usr/local/redis/config/

    配置

  • 修改redis.conf配置文件
    1
    2
    3
    4
    5
    6
    7
    # /usr/local/redis/config/redis.conf
    vi redis.conf

    # 关于redis.conf中的项,可以去查询文档,这边修改这些项
    requirepass xxxxxxxx # 开启auth密码验证(如果在服务端中设置了密码登陆,这边不设置的话,会出现“ERR Client sent AUTH, but no password is set”)
    bind 0.0.0.0 # 如果在服务器厂商那开放了6379端口,任然不能从本地连接服务器redis的话,可以进行设置
    daemon yes # 设置为守护进程,这个不多说

使用

  • 开启持久化和配置文件启动
    1
    2
    # /usr/local/redis
    ./redis-server ./config/redis.conf --appendonly yes
  • 关于redis持久化的文章:谈谈Redis持久化(下)——AOF(Append Only File)
    1
    2
    3
    # 接上
    # 使用redis终端进行测试
    ./redis-cli
  • 在本地中的使用,本地使用的是windwos端的RedisDesktopManager

Golang代码编写

直接上代码吧

1
2
3
4
5
# Config/config.ini
[redis]
ADDR = your server address:6379
PASSWORD = 123456
DB = 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// Middlewares/Cache/redis.go
package Cache

import (
"fmt"
"sync"
"github.com/go-redis/redis"
"time"
"virtual-data/Middlewares/setting"
)

type RedisStorage struct {
}

var (
instance *RedisStorage
once sync.Once
client *redis.Client
err error
)

func Instance() *RedisStorage {
once.Do(func() {
instance = &RedisStorage{}
})
return instance
}

func (r *RedisStorage) Init() (issue error) {
var (
addr, password string
db int
)
sec, err := setting.Cfg.GetSection("redis")
if err != nil {
fmt.Errorf("Fial to get config section 'redis': %s\n", err)
}
addr = sec.Key("ADDR").String()
password = sec.Key("PASSWORD").String()
db, _ = sec.Key("DB").Int()

client = redis.NewClient(&redis.Options{
Addr: addr,
Password: password,
DB: db,
})

_, err = client.Ping().Result()
if err != nil {
return err
}

return nil
}

// 存
func (r *RedisStorage) Set(key, value string, expiration time.Duration) error {
err := client.Set(key, value, expiration).Err()
return err
}

// 查
func (r *RedisStorage) Get(key string) (string, error) {
result, err := client.Get(key).Result()
return result, err
}

// 删
func (r *RedisStorage) Del(key string) error {
err := client.Del(key).Err()
return err
}

在登陆控制器中使用

  • ViewModel 返回数据格式声明
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    // ViewModel/Login/v_login.go
    package Login

    type ResultData struct {
    CreateTime int64 `json:"createTime"`
    UserId int `json:"userId"`
    Token string `json:"token"`
    RealName string `json:realName`
    }

    type Vresult struct {
    Code int `json:"code"`
    Data ResultData `json:"data"`
    }

    type Verror struct {
    Code int `json:"code"`
    ThrowType string `json:"throwType"`
    Message string `json:"message"`
    }
  • LoginController 登陆接口方法编写
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    // Controllers/LoginController.go
    package Controllers

    import (
    "encoding/json"
    "fmt"
    "github.com/astaxie/beego/validation"
    "github.com/kataras/iris"
    "io/ioutil"
    "net/http"
    "net/url"
    "strconv"
    "strings"
    "time"
    "virtual-data/Middlewares/Cache"
    "virtual-data/Middlewares/setting"
    VMlogin "virtual-data/ViewModel/Login"
    )

    func Login(ctx iris.Context) {
    userName := ctx.Request().FormValue("username")
    passWord := ctx.Request().FormValue("password")

    valid := validation.Validation{}
    valid.Required(userName, "username").Message("账号不能为空")
    valid.Required(passWord, "password").Message("密码不能为空")

    if !valid.HasErrors() {
    result, err := requestJavaServerService(userName, passWord)
    if err != nil {
    ctx.JSON(Result(http.StatusBadGateway, err))
    } else {
    ctx.JSON(result)
    }
    } else {
    ctx.JSON(Result(http.StatusBadRequest, valid.Errors[0].Message))
    }
    }

    /**
    * 请求java服务端接口,返回请求成功或错误的值
    * @method requestJavaServerService
    * @param username string
    * @param password string
    * @return interface{}
    * @return error
    */
    func requestJavaServerService(username, password string) (interface{}, error) {
    client := &http.Client{}
    var err error
    var urlAddr string
    userInfo := url.Values{}
    userInfo.Add("userName", username)
    userInfo.Add("password", password)

    sec, err := setting.Cfg.GetSection("request")
    if err != nil {
    fmt.Errorf("Fial to get config section 'request': %s\n", err)
    }
    // 在配置文件中配置好的请求地址
    urlAddr = sec.Key("url").String()

    request, err := http.NewRequest(
    "POST",
    urlAddr,
    strings.NewReader(userInfo.Encode()),
    )
    request.Header.Set("Content-type", "application/x-www-form-urlencoded")
    request.Header.Set("cms-token", "null")
    request.Header.Set("cms-channel", "0")
    if err != nil {
    return nil, err
    }

    parseObj, err := parseResponseBody(client, request)
    if err != nil {
    return nil, err
    }

    return parseObj, nil
    }


    type tempBody struct {
    Code int `json:"code"`
    Data interface{} `json:"data"`
    }
    /**
    * 处理请求成功的body
    * @method parseResponseBody
    * @param client *http.Client
    * @param request *http.Request
    * @return obj interface{}
    * @return err error
    */
    func parseResponseBody(client *http.Client, request *http.Request) (obj interface{}, err error) {
    var resultObj VMlogin.Vresult
    var errorObj VMlogin.Verror
    var tempObj tempBody
    resp, err := client.Do(request)
    if err != nil {
    return nil, err
    }
    defer resp.Body.Close()

    body, _ := ioutil.ReadAll(resp.Body)
    err = json.Unmarshal(body, &tempObj)
    if err != nil {
    return nil, err
    }
    if tempObj.Code == 200 {
    _ = json.Unmarshal(body, &resultObj)
    obj = resultObj
    if err = cacheManagerService(resultObj); err != nil {
    return nil, err
    }
    } else {
    _ = json.Unmarshal(body, &errorObj)
    obj = errorObj
    }
    return obj, nil
    }

    /**
    * 设置处理缓存的工厂
    * @method cacheManagerService
    * @param resultObj VMlogin.Vresult
    * @return error
    */
    func cacheManagerService(resultObj VMlogin.Vresult) error {
    var oldResultObj VMlogin.Vresult
    var redisKey string
    var redisValue string
    var err error

    // 组合查询用户信息的声明和赋值
    redisKey = FormatRedisString(REDIS_KEY_USER, resultObj.Data.UserId)
    redisJsonValue, _ := json.Marshal(resultObj.Data)
    redisValue = string(redisJsonValue)

    // 查询是否存在此用户
    infoVal, _ := Cache.Instance().Get(redisKey)

    // json反序列化查询到的json字符串,将存储在缓存中的值赋值到一个变量上
    _ = json.Unmarshal([]byte(infoVal), &oldResultObj.Data)
    // 如果返回空字符串,则是新用户,创建新的缓存
    // 否则根据缓存的token组合去将旧的缓存删除,覆盖新的用户信息和创建新的token
    if infoVal == "" {
    // 设置新的用户信息缓存
    err = Cache.Instance().Set(redisKey, redisValue, 744 * time.Hour)
    if err != nil {
    return err
    }

    // 设置新的token信息缓存
    redisKey = FormatRedisString(REDIS_KEY_TOKEN, resultObj.Data.Token)
    redisValue = strconv.Itoa(resultObj.Data.UserId)
    err = Cache.Instance().Set(redisKey, redisValue, 744 * time.Hour)
    if err != nil {
    return err
    }
    } else {
    // 声明并赋值旧的token信息
    oldToken := oldResultObj.Data.Token
    // 删除旧的token
    err = Cache.Instance().Del(FormatRedisString(REDIS_KEY_TOKEN, oldToken))
    if err != nil {
    return err
    }

    // 设置覆盖新的用户信息
    err = Cache.Instance().Set(redisKey, redisValue, 744 * time.Hour)
    if err != nil {
    return err
    }

    // 设置新的token
    redisKey = FormatRedisString(REDIS_KEY_TOKEN, resultObj.Data.Token)
    redisValue = strconv.Itoa(resultObj.Data.UserId)
    err = Cache.Instance().Set(redisKey, redisValue, 744 * time.Hour)
    if err != nil {
    return err
    }
    }
    return nil
    }