无心是美蛆 發表於 2020-12-30 14:44:00

Go-连接Redis-学习go-redis包

<h3 id="redis介绍">Redis介绍</h3>
<p>Redis是一个开源的内存数据结构存储,常用作数据库、缓存和消息代理。目前它支持的数据结构有诸如string、hash、list、set、zset、bitmap、hyperloglog、geospatial index和stream。Redis内置了复制、Lua脚本、LRU清除、事务和不同级别的磁盘持久性,并通过Redis Sentinel提供高可用性,通过Redis Cluster自动分区。</p>
<h3 id="go-redis库">go-redis库</h3>
<h4 id="安装">安装</h4>
<p>区别于另一个比较常用的Go语言redis client库:redigo,我们这里采用https://github.com/go-redis/redis连接Redis数据库并进行操作,因为go-redis支持连接哨兵及集群模式的Redis。</p>
<p>使用以下命令下载并安装:</p>
<pre><code>go get -u github.com/go-redis/redis
</code></pre>
<h4 id="连接">连接</h4>
<h5 id="普通连接">普通连接</h5>
<pre><code>// 声明一个全局的rdb变量
var rdb *redis.Client

// 初始化连接
func initClient() (err error) {
      // 通过 redis.NewClient 函数即可创建一个 redis 客户端, 这个方法接收一个 redis.Options 对象参数, 通过这个参数, 我们可以配置 redis 相关的属性, 例如 redis 服务器地址, 数据库名, 数据库密码等。
        rdb = redis.NewClient(&amp;redis.Options{
                Addr:   "localhost:6379",
                Password: "", // no password set
                DB:       0,// use default DB
        })
      // 通过 cient.Ping() 来检查是否成功连接到了 redis 服务器
        _, err = rdb.Ping().Result()
        if err != nil {
                return err
        }
        return nil
}
</code></pre>
<h5 id="连接redis哨兵模式">连接Redis哨兵模式</h5>
<pre><code>func initClient()(err error){
        rdb := redis.NewFailoverClient(&amp;redis.FailoverOptions{
                MasterName:    "master",
                SentinelAddrs: []string{"x.x.x.x:26379", "xx.xx.xx.xx:26379", "xxx.xxx.xxx.xxx:26379"},
        })
        _, err = rdb.Ping().Result()
        if err != nil {
                return err
        }
        return nil
}
</code></pre>
<h5 id="连接redis集群">连接Redis集群</h5>
<pre><code>func initClient()(err error){
        rdb := redis.NewClusterClient(&amp;redis.ClusterOptions{
                Addrs: []string{":7000", ":7001", ":7002", ":7003", ":7004", ":7005"},
        })
        _, err = rdb.Ping().Result()
        if err != nil {
                return err
        }
        return nil
}
</code></pre>
<h4 id="连接池">连接池</h4>
<p>go-redis 已经实现了 redis 的连接池管理, 因此我们不需要自己手动管理 redis 的连接。<br>
默认情况下,连接池大小是10, 可以通过 redis.Options 的 PoolSize 属性, 我们设置了 redis 连接池的大小为5。</p>
<pre><code>func GetRedisClientPool() *Client{
    redisdb := NewClient(&amp;Options{
      Addr: "127.0.0.1:6379",
      Password: "",
      DB: 0,
      PoolSize: 5,})

    pong, err := redisdb.Ping().Result()
    if err != nil {
      fmt.Println(pong, err)
    }
    return redisdb
}

// 连接池测试
func connectPoolTest() {
    fmt.Println("-----------------------welcome to connect Pool Test-----------------------")
    client :=GetRedisClientPool()
    wg := sync.WaitGroup{}
    wg.Add(10)

    for i := 0; i &lt; 10; i++ {
      go func() {
            defer wg.Done()

            for j := 0; j &lt; 1000; j++ {
                client.Set(fmt.Sprintf("name%d", j), fmt.Sprintf("xys%d", j), 0).Err()
                client.Get(fmt.Sprintf("name%d", j)).Result()
            }

            fmt.Printf("PoolStats, TotalConns: %d, IdleConns: %d\n", client.PoolStats().TotalConns, client.PoolStats().IdleConns);
      }()
    }

    wg.Wait()
}
</code></pre>
<h4 id="基本使用">基本使用</h4>
<h5 id="string-操作">String 操作</h5>
<ul>
<li>Set(key, value):给数据库中名称为key的string赋予值valueget(key):返回数据库中名称为key的string的value</li>
<li>GetSet(key, value):给名称为key的string赋予上一次的value</li>
<li>MGet(key1, key2,…, key N):返回库中多个string的value</li>
<li>SetNX(key, value):添加string,名称为key,值为value</li>
<li>SetXX(key, time, value):向库中添加string,设定过期时间time</li>
<li>MSet(key N, value N):批量设置多个string的值</li>
<li>MSetNX(key N, value N):如果所有名称为key i的string都不存在</li>
<li>Incr(key):名称为key的string增1操作</li>
<li>Incrby(key, integer):名称为key的string增加integer</li>
<li>Decr(key):名称为key的string减1操作</li>
<li>Decrby(key, integer):名称为key的string减少integer</li>
<li>Append(key, value):名称为key的string的值附加valuesubstr(key, start, end):返回名称为key的string的value的子串<br>
 </li>
</ul>
<pre><code>func redisExample() {
        err := rdb.Set("score", 100, 0).Err()
        if err != nil {
                fmt.Printf("set score failed, err:%v\n", err)
                return
        }

        val, err := rdb.Get("score").Result()
        if err != nil {
                fmt.Printf("get score failed, err:%v\n", err)
                return
        }
        fmt.Println("score", val)

        val2, err := rdb.Get("name").Result()
        if err == redis.Nil {
                fmt.Println("name does not exist")
        } else if err != nil {
                fmt.Printf("get name failed, err:%v\n", err)
                return
        } else {
                fmt.Println("name", val2)
        }
}
</code></pre>
<pre><code>func StringDemo() {
    fmt.Println("-----------------------welcome to StringDemo-----------------------")
    redisClient:=GetRedisClient()
    if redisClient ==nil{
      fmt.Errorf("StringDemo redisClient is nil")
      return
    }

    name := "张三"
    key :="name:zhangsan"
    redisClient.Set(key , name,1 * time.Second)
    val := redisClient.Get(key)
    if val == nil {
      fmt.Errorf("StringDemo get error")
    }
    fmt.Println("name", val)
}
</code></pre>
<h5 id="list-操作">List 操作</h5>
<ul>
<li>RPush(key, value):在名称为key的list尾添加一个值为value的元素</li>
<li>LPush(key, value):在名称为key的list头添加一个值为value的元素</li>
<li>LLen(key):返回名称为key的list的长度</li>
<li>LRange(key, start, end):返回名称为key的list中start至end之间的元素</li>
<li>LTrim(key, start, end):截取名称为key的list</li>
<li>LIndex(key, index):返回名称为key的list中index位置的元素</li>
<li>LSet(key, index, value):给名称为key的list中index位置的元素赋值</li>
<li>LRem(key, count, value):删除count个key的list中值为value的元素</li>
<li>LPop(key):返回并删除名称为key的list中的首元素</li>
<li>RPop(key):返回并删除名称为key的list中的尾元素</li>
<li>BLPop(key1, key2,… key N, timeout):lpop命令的block版本。</li>
<li>BRPop(key1, key2,… key N, timeout):rpop的block版本。</li>
<li>RPopLPush(srckey, dstkey):返回并删除名称为srckey的list的尾元素,并将该元素添加到名称为dstkey的list的头部</li>
</ul>
<pre><code>func ListDemo(){
    fmt.Println("-----------------------welcome to ListDemo-----------------------")
    redisClient:=GetRedisClient()
    if redisClient == nil {
      fmt.Errorf("ListDemo redisClient is nil")
      return
    }
    articleKey := "article"
    result,err:=redisClient.RPush(articleKey, "a","b","c").Result() //
    if err!=nil {
      fmt.Println(err)
      return
    }
    fmt.Println("result:",result)

    result,err = redisClient.LPush(articleKey, "d").Result() //
    if err!=nil {
      fmt.Println(err)
      return
    }
    fmt.Println("result:",result)

    length, err := redisClient.LLen(articleKey).Result()
    if err != nil {
      fmt.Println("ListDemo LLen is nil")
    }
    fmt.Println("length: ", length) // 长度

    mapOut,err1:=redisClient.LRange(articleKey,0,100).Result()
    if err1!=nil {
      fmt.Println(err1)
      return
    }
    for inx, item := range mapOut {
      fmt.Printf("\n %s:%s", inx, item)
    }
}
</code></pre>
<h5 id="hash操作">Hash操作</h5>
<ul>
<li>HSet(key, field, value):向名称为key的hash中添加元素field</li>
<li>HGet(key, field):返回名称为key的hash中field对应的value</li>
<li>HMget(key, (fields)):返回名称为key的hash中field i对应的value</li>
<li>HMset(key, (fields)):向名称为key的hash中添加元素field</li>
<li>HIncrby(key, field, integer):将名称为key的hash中field的value增加integer</li>
<li>HExists(key, field):名称为key的hash中是否存在键为field的域</li>
<li>HDel(key, field):删除名称为key的hash中键为field的域</li>
<li>HLen(key):返回名称为key的hash中元素个数</li>
<li>HKeys(key):返回名称为key的hash中所有键</li>
<li>HVals(key):返回名称为key的hash中所有键对应的value</li>
<li>HGetall(key):返回名称为key的hash中所有的键(field)及其对应的value</li>
</ul>
<pre><code>func HashDemo() {
    fmt.Println("-----------------------welcome to HashDemo-----------------------")
    redisClient := GetRedisClient()
    if redisClient == nil {
      fmt.Errorf("HashDemo redisClient is nil")
      return
    }
    article := Article{18, "测试文章内容22222", "测试文章内容22222测试文章内容22222测试文章内容22222", 10, 0}
    articleKey := "article:18"

    redisClient.HMSet(articleKey, ToStringDictionary(&amp;article))
    mapOut := redisClient.HGetAll(articleKey).Val()
    for inx, item := range mapOut {
      fmt.Printf("\n %s:%s", inx, item)
    }
    fmt.Print("\n")

    redisClient.HSet(articleKey, "Content", "测试文章内容")
    mapOut = redisClient.HGetAll(articleKey).Val()
    for inx, item := range mapOut {
      fmt.Printf("\n %s:%s", inx, item)
    }
    fmt.Print("\n")

    view, err := redisClient.HIncrBy(articleKey, "Views", 1).Result()
    if err != nil {
      fmt.Printf("\n HIncrBy error=%s ", err)
    } else {
      fmt.Printf("\n HIncrBy Views=%d ", view)
    }
    fmt.Print("\n")

    mapOut = redisClient.HGetAll(articleKey).Val()
    for inx, item := range mapOut {
      fmt.Printf("\n %s:%s", inx, item)
    }
    fmt.Print("\n")
}
</code></pre>
<h5 id="zset示例">zset示例</h5>
<pre><code>func redisExample2() {
        zsetKey := "language_rank"
        languages := []*redis.Z{
                &amp;redis.Z{Score: 90.0, Member: "Golang"},
                &amp;redis.Z{Score: 98.0, Member: "Java"},
                &amp;redis.Z{Score: 95.0, Member: "Python"},
                &amp;redis.Z{Score: 97.0, Member: "JavaScript"},
                &amp;redis.Z{Score: 99.0, Member: "C/C++"},
        }
        // ZADD
        num, err := rdb.ZAdd(zsetKey, languages...).Result()
        if err != nil {
                fmt.Printf("zadd failed, err:%v\n", err)
                return
        }
        fmt.Printf("zadd %d succ.\n", num)

        // 把Golang的分数加10
        newScore, err := rdb.ZIncrBy(zsetKey, 10.0, "Golang").Result()
        if err != nil {
                fmt.Printf("zincrby failed, err:%v\n", err)
                return
        }
        fmt.Printf("Golang's score is %f now.\n", newScore)

        // 取分数最高的3个
        ret, err := rdb.ZRevRangeWithScores(zsetKey, 0, 2).Result()
        if err != nil {
                fmt.Printf("zrevrange failed, err:%v\n", err)
                return
        }
        for _, z := range ret {
                fmt.Println(z.Member, z.Score)
        }

        // 取95~100分的
        op := &amp;redis.ZRangeBy{
                Min: "95",
                Max: "100",
        }
        ret, err = rdb.ZRangeByScoreWithScores(zsetKey, op).Result()
        if err != nil {
                fmt.Printf("zrangebyscore failed, err:%v\n", err)
                return
        }
        for _, z := range ret {
                fmt.Println(z.Member, z.Score)
        }
}

// 输出结果如下:
$ ./06redis_demo
zadd 0 succ.
Golang's score is 100.000000 now.
Golang 100
C/C++ 99
Java 98
JavaScript 97
Java 98
C/C++ 99
Golang 100
</code></pre>
<h3 id="完整代码">完整代码</h3>
<pre><code>package main

import (
    "fmt"
    . "github.com/go-redis/redis"
    . "redisDemo/models"
    "time"
    "sync"
)

func main() {
    fmt.Println("-----------------------welcome to redisdemo-----------------------")
    //StringDemo()
    //ListDemo()
    //HashDemo()
    connectPoolTest()
}

func StringDemo() {
    fmt.Println("-----------------------welcome to StringDemo-----------------------")
    redisClient:=GetRedisClient()
    if redisClient ==nil{
      fmt.Errorf("StringDemo redisClient is nil")
      return
    }

    name := "张三"
    key :="name:zhangsan"
    redisClient.Set(key , name,1 * time.Second)
    val := redisClient.Get(key)
    if val == nil {
      fmt.Errorf("StringDemo get error")
    }
    fmt.Println("name", val)
}

func ListDemo(){
    fmt.Println("-----------------------welcome to ListDemo-----------------------")
    redisClient:=GetRedisClient()
    if redisClient == nil {
      fmt.Errorf("ListDemo redisClient is nil")
      return
    }
    articleKey := "article"
    result,err:=redisClient.RPush(articleKey, "a","b","c").Result() //在名称为 key 的list尾添加一个值为value的元素
    if err!=nil {
      fmt.Println(err)
      return
    }
    fmt.Println("result:",result)

    result,err = redisClient.LPush(articleKey, "d").Result() //在名称为 key 的list头添加一个值为value的元素
    if err!=nil {
      fmt.Println(err)
      return
    }
    fmt.Println("result:",result)

    length, err := redisClient.LLen(articleKey).Result()
    if err != nil {
      fmt.Println("ListDemo LLen is nil")
    }
    fmt.Println("length: ", length) // 长度

    mapOut,err1:=redisClient.LRange(articleKey,0,100).Result()
    if err1!=nil {
      fmt.Println(err1)
      return
    }
    for inx, item := range mapOut {
      fmt.Printf("\n %s:%s", inx, item)
    }
}

func HashDemo() {
    fmt.Println("-----------------------welcome to HashDemo-----------------------")
    redisClient := GetRedisClient()
    if redisClient == nil {
      fmt.Errorf("HashDemo redisClient is nil")
      return
    }
    article := Article{18, "测试文章内容22222", "测试文章内容22222测试文章内容22222测试文章内容22222", 10, 0}
    articleKey := "article:18"

    redisClient.HMSet(articleKey, ToStringDictionary(&amp;article))
    mapOut := redisClient.HGetAll(articleKey).Val()
    for inx, item := range mapOut {
      fmt.Printf("\n %s:%s", inx, item)
    }
    fmt.Print("\n")

    redisClient.HSet(articleKey, "Content", "测试文章内容")
    mapOut = redisClient.HGetAll(articleKey).Val()
    for inx, item := range mapOut {
      fmt.Printf("\n %s:%s", inx, item)
    }
    fmt.Print("\n")

    view, err := redisClient.HIncrBy(articleKey, "Views", 1).Result()
    if err != nil {
      fmt.Printf("\n HIncrBy error=%s ", err)
    } else {
      fmt.Printf("\n HIncrBy Views=%d ", view)
    }
    fmt.Print("\n")

    mapOut = redisClient.HGetAll(articleKey).Val()
    for inx, item := range mapOut {
      fmt.Printf("\n %s:%s", inx, item)
    }
    fmt.Print("\n")

}

func GetRedisClient() *Client {
    redisdb := NewClient(&amp;Options{
      Addr:   "127.0.0.1:6379",
      Password: "", // no password set
      DB:       0,               // use default DB
    })

    pong, err := redisdb.Ping().Result()
    if err != nil {
      fmt.Println(pong, err)
    }
    return redisdb
}

func GetRedisClientPool() *Client{
    redisdb := NewClient(&amp;Options{
      Addr: "127.0.0.1:6379",
      Password: "",
      DB: 0,
      PoolSize: 5,})

    pong, err := redisdb.Ping().Result()
    if err != nil {
      fmt.Println(pong, err)
    }
    return redisdb
}

// 连接池测试
func connectPoolTest() {
    fmt.Println("-----------------------welcome to connect Pool Test-----------------------")
    client :=GetRedisClientPool()
    wg := sync.WaitGroup{}
    wg.Add(10)

    for i := 0; i &lt; 10; i++ {
      go func() {
            defer wg.Done()

            for j := 0; j &lt; 1000; j++ {
                client.Set(fmt.Sprintf("name%d", j), fmt.Sprintf("xys%d", j), 0).Err()
                client.Get(fmt.Sprintf("name%d", j)).Result()
            }

            fmt.Printf("PoolStats, TotalConns: %d, IdleConns: %d\n", client.PoolStats().TotalConns, client.PoolStats().IdleConns);
      }()
    }
    wg.Wait()
}
</code></pre><br><br>
来源:https://www.cnblogs.com/Paul-watermelon/p/14211394.html
頁: [1]
查看完整版本: Go-连接Redis-学习go-redis包