• 使用Goland操作Redis详解


    String 操作

    redis 的 String 操作有:

    set(key, value):给数据库中名称为key的string赋予值value
    get(key):返回数据库中名称为key的string的value
    getset(key, value):给名称为key的string赋予上一次的value
    mget(key1, key2,…, key N):返回库中多个string的value
    setnx(key, value):添加string,名称为key,值为value
    setex(key, time, value):向库中添加string,设定过期时间time
    mset(key N, value N):批量设置多个string的值
    msetnx(key N, value N):如果所有名称为key i的string都不存在
    incr(key):名称为key的string增1操作
    incrby(key, integer):名称为key的string增加integer
    decr(key):名称为key的string减1操作
    decrby(key, integer):名称为key的string减少integer
    append(key, value):名称为key的string的值附加value
    substr(key, start, end):返回名称为key的string的value的子串

    在 go-redis 中, 我们可以直接找到对应的操作方法, 直接上代码:

    // String 操作
    func stringOperation(client *redis.Client) {
        // 第三个参数是过期时间, 如果是0, 则表示没有过期时间.
        err := client.Set("name", "xys", 0).Err()
        if err != nil {
            panic(err)
        }
    
        val, err := client.Get("name").Result()
        if err != nil {
            panic(err)
        }
        fmt.Println("name", val)
    
    
        // 这里设置过期时间.
        err = client.Set("age", "20", 1 * time.Second).Err()
        if err != nil {
            panic(err)
        }
    
        client.Incr("age") // 自增
        client.Incr("age") // 自增
        client.Decr("age") // 自减
    
        val, err = client.Get("age").Result()
        if err != nil {
            panic(err)
        }
        fmt.Println("age", val) // age 的值为21
    
        // 因为 key "age" 的过期时间是一秒钟, 因此当一秒后, 此 key 会自动被删除了.
        time.Sleep(1 * time.Second)
        val, err = client.Get("age").Result()
        if err != nil {
            // 因为 key "age" 已经过期了, 因此会有一个 redis: nil 的错误.
            fmt.Printf("error: %v
    ", err)
        }
        fmt.Println("age", val)
    }

    list 操作

    redis 的 list 操作有:

    rpush(key, value):在名称为key的list尾添加一个值为value的元素
    lpush(key, value):在名称为key的list头添加一个值为value的 元素
    llen(key):返回名称为key的list的长度
    lrange(key, start, end):返回名称为key的list中start至end之间的元素
    ltrim(key, start, end):截取名称为key的list
    lindex(key, index):返回名称为key的list中index位置的元素
    lset(key, index, value):给名称为key的list中index位置的元素赋值
    lrem(key, count, value):删除count个key的list中值为value的元素
    lpop(key):返回并删除名称为key的list中的首元素
    rpop(key):返回并删除名称为key的list中的尾元素
    blpop(key1, key2,… key N, timeout):lpop命令的block版本。
    brpop(key1, key2,… key N, timeout):rpop的block版本。
    rpoplpush(srckey, dstkey):返回并删除名称为srckey的list的尾元素,并将该元素添加到名称为dstkey的list的头部

    同样地, 在 go-redis 中也可以找到对应的方法, 下面是一个简单的示例:

    // list 操作
    func listOperation(client *redis.Client) {
        client.RPush("fruit", "apple") //在名称为 fruit 的list尾添加一个值为value的元素
        client.LPush("fruit", "banana") //在名称为 fruit 的list头添加一个值为value的 元素
        length, err := client.LLen("fruit").Result() //返回名称为 fruit 的list的长度
        if err != nil {
            panic(err)
        }
        fmt.Println("length: ", length) // 长度为2
    
        value, err := client.LPop("fruit").Result() //返回并删除名称为 fruit 的list中的首元素
        if err != nil {
            panic(err)
        }
        fmt.Println("fruit: ", value)
    
        value, err = client.RPop("fruit").Result() // 返回并删除名称为 fruit 的list中的尾元素
        if err != nil {
            panic(err)
        }
        fmt.Println("fruit: ", value)
    }

    set 操作

    redis 的 set 操作:

    sadd(key, member):向名称为key的set中添加元素member
    srem(key, member) :删除名称为key的set中的元素member
    spop(key) :随机返回并删除名称为key的set中一个元素
    smove(srckey, dstkey, member) :移到集合元素
    scard(key) :返回名称为key的set的基数
    sismember(key, member) :member是否是名称为key的set的元素
    sinter(key1, key2,…key N) :求交集
    sinterstore(dstkey, (keys)) :求交集并将交集保存到dstkey的集合
    sunion(key1, (keys)) :求并集
    sunionstore(dstkey, (keys)) :求并集并将并集保存到dstkey的集合
    sdiff(key1, (keys)) :求差集
    sdiffstore(dstkey, (keys)) :求差集并将差集保存到dstkey的集合
    smembers(key) :返回名称为key的set的所有元素
    srandmember(key) :随机返回名称为key的set的一个元素

    接下来是 go-redis 的 set 操作:

    // set 操作
    func setOperation(client *redis.Client) {
        client.SAdd("blacklist", "Obama") // 向 blacklist 中添加元素
        client.SAdd("blacklist", "Hillary") // 再次添加
        client.SAdd("blacklist", "the Elder") // 添加新元素
    
        client.SAdd("whitelist", "the Elder") // 向 whitelist 添加元素
    
        // 判断元素是否在集合中
        isMember, err := client.SIsMember("blacklist", "Bush").Result()
        if err != nil {
            panic(err)
        }
        fmt.Println("Is Bush in blacklist: ", isMember)
    
    
        // 求交集, 即既在黑名单中, 又在白名单中的元素
        names, err := client.SInter("blacklist", "whitelist").Result()
        if err != nil {
            panic(err)
        }
        // 获取到的元素是 "the Elder"
        fmt.Println("Inter result: ", names)
    
    
        // 获取指定集合的所有元素
        all, err := client.SMembers("blacklist").Result()
        if err != nil {
            panic(err)
        }
        fmt.Println("All member: ", all)
    }

    hash 操作

    redis 的 hash 操作:

    hset(key, field, value):向名称为key的hash中添加元素field
    hget(key, field):返回名称为key的hash中field对应的value
    hmget(key, (fields)):返回名称为key的hash中field i对应的value
    hmset(key, (fields)):向名称为key的hash中添加元素field 
    hincrby(key, field, integer):将名称为key的hash中field的value增加integer
    hexists(key, field):名称为key的hash中是否存在键为field的域
    hdel(key, field):删除名称为key的hash中键为field的域
    hlen(key):返回名称为key的hash中元素个数
    hkeys(key):返回名称为key的hash中所有键
    hvals(key):返回名称为key的hash中所有键对应的value
    hgetall(key):返回名称为key的hash中所有的键(field)及其对应的value

    go-redis 中的 hash 操作:

    // hash 操作
    func hashOperation(client *redis.Client) {
        client.HSet("user_xys", "name", "xys"); // 向名称为 user_xys 的 hash 中添加元素 name
        client.HSet("user_xys", "age", "18"); // 向名称为 user_xys 的 hash 中添加元素 age
    
        // 批量地向名称为 user_test 的 hash 中添加元素 name 和 age
        client.HMSet("user_test", map[string]string{"name": "test", "age":"20"})
        // 批量获取名为 user_test 的 hash 中的指定字段的值.
        fields, err := client.HMGet("user_test", "name", "age").Result()
        if err != nil {
            panic(err)
        }
        fmt.Println("fields in user_test: ", fields)
    
    
        // 获取名为 user_xys 的 hash 中的字段个数
        length, err := client.HLen("user_xys").Result()
        if err != nil {
            panic(err)
        }
        fmt.Println("field count in user_xys: ", length) // 字段个数为2
    
        // 删除名为 user_test 的 age 字段
        client.HDel("user_test", "age")
        age, err := client.HGet("user_test", "age").Result()
        if err != nil {
            fmt.Printf("Get user_test age error: %v
    ", err)
        } else {
            fmt.Println("user_test age is: ", age) // 字段个数为2
        }
    }

    关于连接池

    redis.v4 包实现了 redis 的连接池管理, 因此我们就不需要自己手动管理 redis 的连接了.
    默认情况下, redis.v4 的 redis 连接池大小是10, 不过我们可以在初始化 redis 客户端时自行设置连接池的大小, 例如:

    client := redis.NewClient(&redis.Options{
        Addr:     "localhost:6379",
        Password: "",
        DB:       0,
        PoolSize: 5,
    })

    通过 redis.Options 的 PoolSize 属性, 我们设置了 redis 连接池的大小为5.
    那么接下来我们来看一下这个设置有什么效果吧:

    // redis.v4 的连接池管理
    func connectPool(client *redis.Client) {
        wg := sync.WaitGroup{}
        wg.Add(10)
    
        for i := 0; i < 10; i++ {
            go func() {
                defer wg.Done()
    
                for j := 0; j < 100; 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, FreeConns: %d
    ", client.PoolStats().TotalConns, client.PoolStats().FreeConns);
            }()
        }
    
        wg.Wait()
    }

    上面的例子启动了10个 routine 来不断向 redis 读写数据, 然后我们通过 client.PoolStats() 获取连接池的信息. 运行这个例子, 输出如下:

    PoolStats, TotalConns: 5, FreeConns: 1
    PoolStats, TotalConns: 5, FreeConns: 1
    PoolStats, TotalConns: 5, FreeConns: 1
    PoolStats, TotalConns: 5, FreeConns: 1
    PoolStats, TotalConns: 5, FreeConns: 1
    PoolStats, TotalConns: 5, FreeConns: 2
    PoolStats, TotalConns: 5, FreeConns: 2
    PoolStats, TotalConns: 5, FreeConns: 3
    PoolStats, TotalConns: 5, FreeConns: 4
    PoolStats, TotalConns: 5, FreeConns: 5

    通过输出可以看到, 此时最大的连接池数量确实是 5 了, 并且一开始时, 因为 coroutine 的数量大于5, 会造成 redis 连接不足的情况(反映在 FreeConns 上就是前几次的输出 FreeConns 一直是1), 当某个 coroutine 结束后, 会释放此 redis 连接, 因此 FreeConns 会增加.

    完整示例

    //
    // author xiongyongshun
    // project go_redis
    // version 1.0
    // created 16/10/6 03:49
    //
    package main
    
    import (
        "fmt"
        "gopkg.in/redis.v4"
        "time"
        "sync"
    )
    
    func main() {
        client := createClient()
        defer client.Close()
    
        stringOperation(client)
        listOperation(client)
        setOperation(client)
        hashOperation(client)
    
        connectPool(client)
    
    }
    
    // 创建 redis 客户端
    func createClient() *redis.Client {
        client := redis.NewClient(&redis.Options{
            Addr:     "localhost:6379",
            Password: "",
            DB:       0,
            PoolSize: 5,
        })
    
        pong, err := client.Ping().Result()
        fmt.Println(pong, err)
    
        return client
    }
    
    
    // String 操作
    func stringOperation(client *redis.Client) {
        // 第三个参数是过期时间, 如果是0, 则表示没有过期时间.
        err := client.Set("name", "xys", 0).Err()
        if err != nil {
            panic(err)
        }
    
        val, err := client.Get("name").Result()
        if err != nil {
            panic(err)
        }
        fmt.Println("name", val)
    
    
        // 这里设置过期时间.
        err = client.Set("age", "20", 1 * time.Second).Err()
        if err != nil {
            panic(err)
        }
    
        client.Incr("age") // 自增
        client.Incr("age") // 自增
        client.Decr("age") // 自减
    
        val, err = client.Get("age").Result()
        if err != nil {
            panic(err)
        }
        fmt.Println("age", val) // age 的值为21
    
        // 因为 key "age" 的过期时间是一秒钟, 因此当一秒后, 此 key 会自动被删除了.
        time.Sleep(1 * time.Second)
        val, err = client.Get("age").Result()
        if err != nil {
            // 因为 key "age" 已经过期了, 因此会有一个 redis: nil 的错误.
            fmt.Printf("error: %v
    ", err)
        }
        fmt.Println("age", val)
    }
    
    // list 操作
    func listOperation(client *redis.Client) {
        client.RPush("fruit", "apple") //在名称为 fruit 的list尾添加一个值为value的元素
        client.LPush("fruit", "banana") //在名称为 fruit 的list头添加一个值为value的 元素
        length, err := client.LLen("fruit").Result() //返回名称为 fruit 的list的长度
        if err != nil {
            panic(err)
        }
        fmt.Println("length: ", length) // 长度为2
    
        value, err := client.LPop("fruit").Result() //返回并删除名称为 fruit 的list中的首元素
        if err != nil {
            panic(err)
        }
        fmt.Println("fruit: ", value)
    
        value, err = client.RPop("fruit").Result() // 返回并删除名称为 fruit 的list中的尾元素
        if err != nil {
            panic(err)
        }
        fmt.Println("fruit: ", value)
    }
    
    // set 操作
    func setOperation(client *redis.Client) {
        client.SAdd("blacklist", "Obama") // 向 blacklist 中添加元素
        client.SAdd("blacklist", "Hillary") // 再次添加
        client.SAdd("blacklist", "the Elder") // 添加新元素
    
        client.SAdd("whitelist", "the Elder") // 向 whitelist 添加元素
    
        // 判断元素是否在集合中
        isMember, err := client.SIsMember("blacklist", "Bush").Result()
        if err != nil {
            panic(err)
        }
        fmt.Println("Is Bush in blacklist: ", isMember)
    
    
        // 求交集, 即既在黑名单中, 又在白名单中的元素
        names, err := client.SInter("blacklist", "whitelist").Result()
        if err != nil {
            panic(err)
        }
        // 获取到的元素是 "the Elder"
        fmt.Println("Inter result: ", names)
    
    
        // 获取指定集合的所有元素
        all, err := client.SMembers("blacklist").Result()
        if err != nil {
            panic(err)
        }
        fmt.Println("All member: ", all)
    }
    
    
    // hash 操作
    func hashOperation(client *redis.Client) {
        client.HSet("user_xys", "name", "xys"); // 向名称为 user_xys 的 hash 中添加元素 name
        client.HSet("user_xys", "age", "18"); // 向名称为 user_xys 的 hash 中添加元素 age
    
        // 批量地向名称为 user_test 的 hash 中添加元素 name 和 age
        client.HMSet("user_test", map[string]string{"name": "test", "age":"20"})
        // 批量获取名为 user_test 的 hash 中的指定字段的值.
        fields, err := client.HMGet("user_test", "name", "age").Result()
        if err != nil {
            panic(err)
        }
        fmt.Println("fields in user_test: ", fields)
    
    
        // 获取名为 user_xys 的 hash 中的字段个数
        length, err := client.HLen("user_xys").Result()
        if err != nil {
            panic(err)
        }
        fmt.Println("field count in user_xys: ", length) // 字段个数为2
    
        // 删除名为 user_test 的 age 字段
        client.HDel("user_test", "age")
        age, err := client.HGet("user_test", "age").Result()
        if err != nil {
            fmt.Printf("Get user_test age error: %v
    ", err)
        } else {
            fmt.Println("user_test age is: ", age) // 字段个数为2
        }
    }
    
    // redis.v4 的连接池管理
    func connectPool(client *redis.Client) {
        wg := sync.WaitGroup{}
        wg.Add(10)
    
        for i := 0; i < 10; i++ {
            go func() {
                defer wg.Done()
    
                for j := 0; j < 100; 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, FreeConns: %d
    ", client.PoolStats().TotalConns, client.PoolStats().FreeConns);
            }()
        }
    
        wg.Wait()
    }
     

    本文来自:Segmentfault

    感谢作者:永顺

  • 相关阅读:
    6.Spark streaming技术内幕 : Job动态生成原理与源码解析
    5.Spark Streaming流计算框架的运行流程源码分析2
    4.Spark Streaming事务处理
    2.Spark Streaming运行机制和架构
    1.Spark Streaming另类实验与 Spark Streaming本质解析
    3.spark streaming Job 架构和容错解析
    35.Spark系统运行内幕机制循环流程
    unity3d 扩展NGUI Tweener —— TweenFillAmount
    unity3d 赛车游戏——复位点检测
    unity3d CarWaypoints插件
  • 原文地址:https://www.cnblogs.com/Flower-Z/p/10448739.html
Copyright © 2020-2023  润新知