天天看點

go-redis

go-redis

0.基本使用

package main

import (
    "context"
    "fmt"
    "github.com/go-redis/redis/v8"
)

func main() {
    ctx := context.Background()
    rdb := redis.NewClient(&redis.Options{
        Addr:      "localhost:6379",
        Password: "", // no password set
        DB:          0, // use default DB
    })
    fmt.Println(rdb)
    // Redis<localhost:6379 db:0>

    // 執行指令
    err := rdb.Set(ctx, "key", "value", 0).Err()
    if err != nil {
        panic(err)
    }

    val, err := rdb.Get(ctx, "key").Result()
    if err != nil {
        panic(err)
    }
    fmt.Println("key", val)  // key value
    val2, err := rdb.Get(ctx, "key2").Result()
    if err == redis.Nil {
        fmt.Println("key2 does not exist")
    } else if err != nil {
        panic(err)
    } else {
        fmt.Println("key2", val2)
        //key2 does not exist
    }
}      

1.操作String類型

操作redis String類型

String 類型是 Redis 中最基本的資料類型,string 類型的值最大能存儲 512MB。

下面是go-redis操作String字元串類型的一些API:

  • Set:設定字元串的值
  • SetEX:設定并指定過期時間(set expire)
  • SetNX:設定并指定過期時間(if not exists) 如果key已經存在,則傳回err
  • Get:擷取字元串的值
  • GetRange:擷取字元串值的子字元

這些API的示範代碼如下:

package main

import (
    "context"
    "fmt"
    "time"

    "github.com/go-redis/redis/v8"
)

func main() {
    ctx := context.Background()

    rdb := redis.NewClient(&redis.Options{
        Addr:     "localhost:6379",
        Password: "",
        DB:       0,
    })
    _, err := rdb.Ping(ctx).Result() // PING, <nil>
    if err != nil {
        fmt.Println("connect redis failed:", err)
        return
    }

    // Set 設定
    err = rdb.Set(ctx, "key", "thisisavalue", 0).Err() // 0表示永不過期
    if err != nil {
        panic(err)
    }
    err = rdb.Set(ctx, "key2", "this is a value2", time.Minute*2).Err() // key2将會在兩分鐘後過期失效
    if err != nil {
        panic(err)
    }
    fmt.Println("set success")

    // SetEX 設定并指定過期時間
    err = rdb.SetEX(ctx, "key3", "this is a value3", time.Hour*2).Err()
    if err != nil {
        panic(err)
    }
    fmt.Println("SetEX success")

    // SetNX 設定并指定過期時間(如果key已經存在傳回err
    _, err = rdb.SetNX(ctx, "key4", "this is a value4", time.Minute).Result()
    if err != nil {
        fmt.Println("SetNX failed, key4已經存在", err)
    }
    fmt.Println("SetNX success")

    // Get 擷取
    result, err := rdb.Get(ctx, "key").Result()
    if err != nil {
        panic(err)
    }
    fmt.Println("key值:", result)

    result, err = rdb.Get(ctx, "key5").Result()
    // redis.Nil來區分空字元串應答和Nil應答(鍵不存在)
    if err == redis.Nil {
        fmt.Println("key5不存在")
    } else if err != nil {
        panic(err)
    } else {
        fmt.Println("key5值為:", result)
    }

    // GetRange 擷取字元串值的子字元
    result, err = rdb.GetRange(ctx, "key", 1, 4).Result()
    if err != nil {
        panic(err)
    }
    fmt.Printf("GetRange截取key值為: %v\n", result)
}

// 列印結果如下:
/*
set success
SetEX success
SetNX success
key值: thisisavalue
key5不存在
GetRange截取key值為: hisi
*/      

下面是增減量的API:

  • Incr:将 key 中儲存的數字值增加1
  • IncrBy:将 key 所儲存的值加上給定的增量值
  • Decr:将 key 中儲存的數字值減1
  • DecrBy:key 所儲存的值減去給定的減量值

這些API的示範代碼如下:

package main

import (
    "context"
    "fmt"

    "github.com/go-redis/redis/v8"
)

func main() {
    ctx := context.Background()

    rdb := redis.NewClient(&redis.Options{
        Addr:     "localhost:6379",
        Password: "",
        DB:       0,
    })
    _, err := rdb.Ping(ctx).Result()  // PING, <nil>
    if err != nil {
        fmt.Println("connect redis failed:", err)
        return
    }

    // Incr 增加+1
    result, err := rdb.Incr(ctx, "count").Result()
    if err != nil {
        panic(err)
    }
    fmt.Printf("count值為: %v\n", result)

    // IncrBy 按指定步長增加
    result, err = rdb.IncrBy(ctx, "count", 2).Result()
    if err != nil {
        panic(err)
    }
    fmt.Printf("count值為: %v\n", result)

    // Decr 減少-1
    result, err = rdb.Decr(ctx, "count").Result()
    if err != nil {
        panic(err)
    }
    fmt.Printf("count值為: %v\n", result)

    // DecrBy 按指定步長減少
    result, err = rdb.DecrBy(ctx, "count", 2).Result()
    if err != nil {
        panic(err)
    }
    fmt.Printf("count值為: %v\n", result)
}

// 列印結果如下:
/*
count值為: 1
count值為: 3
count值為: 2
count值為: 0
*/      

2.操作List類型

Redis 清單是簡單的字元串清單,按照插入順序排序。可以添加一個元素到清單的頭部(左邊)或者尾部(右邊)。

下面是go-redis操作redis List清單類型的一些API:

  • LPush:在清單的左側加入資料
  • LLen:擷取連結清單元素個數
  • LIndex:擷取清單某下标對應元素
  • LInsert:向某個索引位置插入一個元素
  • LSet:設定清單某個索引位置的值
  • Lpop:從清單左側彈出資料
  • LRange:擷取某個索引範圍裡的元素
  • LTrim:對一個清單進行修剪,隻讓清單保留指定區間内的元素,不在指定區間之内的元素都将被删除
package main

import (
    "context"
    "fmt"

    "github.com/go-redis/redis/v8"
)

func main() {
    ctx := context.Background()

    rdb := redis.NewClient(&redis.Options{
        Addr:     "localhost:6379",
        Password: "",
        DB:       0,
    })
    _, err := rdb.Ping(ctx).Result()  // PING, <nil>
    if err != nil {
        fmt.Println("connect redis failed:", err)
        return
    }
    result, err := rdb.Exists(ctx, "test_list").Result()
    if err != nil {
        return
    }
    if result == 1{
        fmt.Println("test_list have existed ")
        value, err := rdb.Del(ctx,"test_list").Result()
        if err != nil {
            return
        }
        if value ==1 {
            fmt.Println("test_list delete success!")
        }
    }
    // LPush(ctx, key, values...) 在清單的左側加入資料
    n, err := rdb.LPush(ctx, "test_list", 1, 2, 3, 4, 5, 6).Result()
    if err != nil {
        panic(err)
    }
    fmt.Println(n)

    // LLen(ctx, key) 擷取連結清單元素個數
    len, err := rdb.LLen(ctx, "test_list").Result()
    if err != nil {
        panic(err)
    }
    fmt.Println("test_list的長度:", len)

    // LIndex(ctx, key, index) 擷取清單某下标對應元素
    val, err := rdb.LIndex(ctx, "test_list", 2).Result()  // 索引從0數起。
    if err != nil {
        panic(err)
    }
    // 6 5 4 3 2 1
    fmt.Println("index是2的值:", val)

    // LInsert(ctx, key, op, pivot, value) 向某個索引位置插入一個元素
    err = rdb.LInsert(ctx, "test_list", "before", "2", 8).Err() // 在test_list清單的2的前面插入8。
    if err != nil {
        panic(err)
    }
    // 6 5 4 3 8 2 1
    fmt.Println("插入成功")

    // LSet(ctx, key, index, value) 設定清單某個索引位置的值
    err = rdb.LSet(ctx, "test_list", 1, 9).Err()  // 給索引為1 的位置設定為9。索引從0數起。
    if err != nil {
        panic(err)
    }
    fmt.Println("設定成功")
    fmt.Println(rdb.LRange(ctx,"test_list",0,-1).Result())
    // 6 9 4 3 8 2 1
    // LPop(ctx, key) 從清單左側彈出資料
    val, err = rdb.LPop(ctx, "test_list").Result()
    if err != nil {
        panic(err)
    }
    fmt.Println("從清單左側彈出元素:", val)
    // 9 4 3 8 2 1
    // LRange(ctx, key, start, stop) 擷取某個索引範圍裡的元素
    vals, err := rdb.LRange(ctx, "test_list", 1, 4).Result()
    if err != nil {
        panic(err)
    }
    fmt.Println("擷取索引1到4的值:", vals)

    // LTrim(ctx, key, start, stop) 對一個清單進行修剪,
    // 隻讓清單保留指定區間内的元素,不在指定區間之内的元素都将被删除
    val, err = rdb.LTrim(ctx, "test_list", 1, 4).Result()  // 此時隻剩下1到4範圍内的值
    if err != nil {
        panic(err)
    }
    fmt.Println("val值:", val)
}

// 列印結果如下:
/*
test_list have existed 
test_list delete success!
6
test_list的長度: 6
index是2的值: 4
插入成功
設定成功
[6 9 4 3 8 2 1] <nil>
從清單左側彈出元素: 6
擷取索引1到4的值: [4 3 8 2]
val值: OK
*/      

3.操作redis Hash類型

Redis hash 是一個鍵值(key=>value)對集合。Redis hash 是一個 string 類型的 field 和 value 的映射表,hash 特别适合用于存儲對象。

下面是go-redis操作redis Hash類型的一些API:

  • HSet:給key設定field和value
  • HGet:擷取key某個field的value
  • HMset:給key批量設定field和value
  • HLen:擷取鍵值對個數
  • HGetAll:擷取全部鍵值對元素
  • HKeys:擷取所有的key
  • HIncrBy:增加,成功傳回增加後的值
  • HDel:删除鍵值對元素
  • HExists:檢查key某個field是否存在
package main

import (
    "context"
    "fmt"

    "github.com/go-redis/redis/v8"
)

func main() {
    ctx := context.Background()

    rdb := redis.NewClient(&redis.Options{
        Addr:     "localhost:6379",
        Password: "",
        DB:       0,
    })
    _, err := rdb.Ping(ctx).Result()  // PING, <nil>
    if err != nil {
        fmt.Println("connect redis failed:", err)
        return
    }

    // HSet 給key設定field和value
    result, err := rdb.HSet(ctx, "user1", "name", "zhangsan").Result()
    if err != nil {
        panic(err)
    }
    fmt.Println(result)  // 1

    // HMSet 批量設定
    rdb.HMSet(ctx, "user1", map[string]interface{}{"age": 18, "sex": "male"})

    // HGet 擷取某個field的value
    name, err := rdb.HGet(ctx, "user1", "name").Result()
    if err != nil {
        panic(err)
    }
    fmt.Println(name)  // zhangsan

    // HMGet 批量擷取field的value
    fields, err := rdb.HMGet(ctx, "user1", "name", "age").Result()
    if err != nil {
        panic(err)
    }
    fmt.Println(fields)  // [zhangsan 18]

    // HLen 擷取鍵值對個數
    len, err := rdb.HLen(ctx, "user1").Result()
    if err != nil {
        panic(err)
    }
    fmt.Println(len)  // 3

    // HGetAll 擷取全部元素
    all, err := rdb.HGetAll(ctx, "user1").Result()
    if err != nil {
        panic(err)
    }
    fmt.Println(all)  // map[age:18 name:zhangsan sex:male]

    // HKeys 擷取所有的key
    keys, err := rdb.HKeys(ctx, "user1").Result()
    if err != nil {
        panic(err)
    }
    fmt.Println(keys)  // [name age sex]

    // HIncrBy 增加,成功傳回增加後的值
    age, err := rdb.HIncrBy(ctx, "user1", "age", 2).Result()
    if err != nil {
        panic(err)
    }
    fmt.Println(age)  // 20

    // HDel 删除鍵值對元素
    result, err = rdb.HDel(ctx, "user1", "name").Result()
    if err != nil {
        panic(err)
    }
    fmt.Println(result)  // 1

    // HExists 檢查某個元素是否存在
    fmt.Println(rdb.HExists(ctx, "user1","name"))  // hexists user1 name: false
}

// 列印結果如下:
/*
1
zhangsan
[zhangsan 18]
3
map[age:18 name:zhangsan sex:male]
[name age sex]
20
1
hexists user1 name: false
*/      

4.操作redis Set類型

Redis 的 Set 是 string 類型的無序集合。

集合是通過哈希表實作的,是以添加,删除,查找的複雜度都是 O(1)。

下面是go-redis操作redis Set集合類型的一些API:

  • SAdd:向指定集合添加集合元素
  • SSMembers:擷取集合中的所有成員
  • SCard:擷取集合中成員的數量
  • SIsMember:判斷某成員是否在集合中
  • SRem:删除集合裡指定成員
  • SPop:随機從集合中彈出一個元素
package main

import (
  "context"
  "fmt"

  "github.com/go-redis/redis/v8"
)

func main() {
  ctx := context.Background()
  
  rdb := redis.NewClient(&redis.Options{
    Addr:     "localhost:6379",
    Password: "",
    DB:       0,
  })
  _, err := rdb.Ping(ctx).Result()  // PING, <nil>
  if err != nil {
    fmt.Println("connect redis failed:", err)
    return
  }
  
  // SAdd 向指定集合添加集合元素
  result, err := rdb.SAdd(ctx, "dev_users", "zhangsan", "lisi", "wangwu", "zhangsan").Result()
  if err != nil {
    panic(err)
  }
  fmt.Println(result)  // 3

  // SMembers 擷取集合中的所有成員
  members, err := rdb.SMembers(ctx, "dev_users").Result()
  if err != nil {
    panic(err)
  }
  fmt.Println(members)  // [zhangsan wangwu lisi]

  // SCard 擷取集合中成員的數量
  count, err := rdb.SCard(ctx, "dev_users").Result()
  if err != nil {
    panic(err)
  }
  fmt.Println(count)  // 3

  // SIsMember 判斷某成員是否在集合中
  is, err := rdb.SIsMember(ctx, "dev_users", "zhaoliu").Result()
  if err != nil {
    panic(err)
  }
  fmt.Println(is)  // false

  // SRem 删除集合裡指定成員
  n, err := rdb.SRem(ctx, "dev_users", "zhangsan", "lisi").Result()
  if err != nil {
    panic(err)
  }
  fmt.Println(n)  // 2

  // SPop 随機從集合中彈出一個元素
  user, err := rdb.SPop(ctx, "dev_users").Result()  // 此時集合中隻剩wangwu,彈出wangwu了
  if err != nil {
    panic(err)
  }
  fmt.Println(user)  // wangwu
}

// 列印結果如下:
/*
3
[zhangsan wangwu lisi]
3
false
2
wangwu
*/      

下面是go-redis集合運算的一些API:

  • SInter:求集合間的交集
  • SDiff:求集合間的差集
  • SUnion:求集合間的并集
package main

import (
  "context"
  "fmt"

  "github.com/go-redis/redis/v8"
)

func main() {
  ctx := context.Background()
  
  rdb := redis.NewClient(&redis.Options{
    Addr:     "localhost:6379",
    Password: "",
    DB:       0,
  })
  _, err := rdb.Ping(ctx).Result()  // PING, <nil>
  if err != nil {
    fmt.Println("connect redis failed:", err)
    return
  }

  // 準備一些資料
  // 先往dev_group1集合添加一些成員
  result1, err := rdb.SAdd(ctx, "dev_group1", "zhangsan", "lisi", "wangwu", "zhangsan").Result()
  if err != nil {
    panic(err)
  }
  fmt.Println(result1)  // 3
  // 再往dev_group2集合添加一些成員
  result2, err := rdb.SAdd(ctx, "dev_group2", "zhaoliu", "tiaiqi", "zhangsan", "lisi").Result()
  if err != nil {
    panic(err)
  }
  fmt.Println(result2)  // 4

  // SInter 求集合間的交集
  inter, err := rdb.SInter(ctx, "dev_group1", "dev_group2").Result()
  if err != nil {
    panic(err)
  }
  fmt.Println("交集:", inter)  // 交集: [zhangsan lisi]

  // SDiff 求集合間的差集 
  diff, err := rdb.SDiff(ctx, "dev_group1", "dev_group2").Result() // dev_group1集合與dev_group2集合的差集
  if err != nil {
    panic(err)
  }
  fmt.Println("差集:", diff)  // 差集: [wangwu]

  diff2, err := rdb.SDiff(ctx, "dev_group2", "dev_group1").Result() // dev_group2集合與dev_group1集合的差集
  if err != nil {
    panic(err)
  }
  fmt.Println("差集:", diff2)  // 差集: [zhaoliu tiaiqi]

  // SUnion 求集合間的并集
  union, err := rdb.SUnion(ctx, "dev_group1", "dev_group2").Result()
  if err != nil {
    panic(err)
  }
  fmt.Println("并集:", union)  // 并集: [lisi wangwu zhaoliu tiaiqi zhangsan]

}

// 列印結果如下:
/*
3
4
交集: [zhangsan lisi]
差集: [wangwu]
差集: [zhaoliu tiaiqi]
并集: [lisi wangwu zhaoliu tiaiqi zhangsan]
*/      

5.操作redis Zset類型

Redis zset 和 set 一樣也是string類型元素的集合,且不允許重複的成員。不同的是每個元素都會關聯一個double類型的分數。redis正是通過分數來為集合中的成員進行從小到大的排序。zset的成員是唯一的,但分數(score)卻可以重複。

下面是go-redis操作redis Zset有序集合類型的一些API:

  • ZAdd:向一個有序集合中添加元素
  • ZCard:擷取有序集合的元素個數
  • ZCount:擷取有序集合指定區間内元素個數
  • ZScore:擷取有序集合的元素的score
  • ZRank:傳回有序集中指定成員的排名。其中有序內建員按分數值遞增(從小到大)順序排列。
  • ZRevRank:傳回有序集合中指定成員的排名,有序內建員按分數值遞減(從大到小)排序
  • ZRange:傳回有序集中,指定區間内的成員,其中成員的位置按分數值遞增(從小到大)來排序。
  • ZRevRange:傳回有序集中,指定區間内的成員,其中成員的位置按分數值遞減(從大到小)來排列。
  • ZIncrBy:對有序集合中指定成員的分數加上一個增量
  • ZRangeByScore:通過分數傳回有序集合指定區間内的成員,分數從低到高排序
  • ZRevRangeByScore:傳回有序集中指定分數區間内的成員,分數從高到低排序
  • ZRemRangeByRank:移除有序集合中給定的排名區間的所有成員
  • ZRemRangeByScore:移除有序集合中給定的分數區間的所有成員
  • ZRem:移除有序集合中的一個或多個成員
package main

import (
  "context"
  "fmt"

  "github.com/go-redis/redis/v8"
)

func main() {
  ctx := context.Background()
  
  rdb := redis.NewClient(&redis.Options{
    Addr:     "localhost:6379",
    Password: "",
    DB:       0,
  })
  _, err := rdb.Ping(ctx).Result()  // PING, <nil>
  if err != nil {
    fmt.Println("connect redis failed:", err)
    return
  }

  // ZAdd 向一個有序集合中添加元素
  rdb.ZAdd(ctx, "test_zset", &redis.Z{
    Score: 1,
    Member: "python",
  })
  rdb.ZAdd(ctx, "test_zset", &redis.Z{
    Score: 2,
    Member: "c",
  })
  rdb.ZAdd(ctx, "test_zset", &redis.Z{
    Score: 3,
    Member: "java",
  })
  rdb.ZAdd(ctx, "test_zset", &redis.Z{
    Score: 4,
    Member: "c++",
  })
  rdb.ZAdd(ctx, "test_zset", &redis.Z{
    Score: 5,
    Member: "c#",
  })
  rdb.ZAdd(ctx, "test_zset", &redis.Z{
    Score: 6,
    Member: "visual bacis",
  })

  // ZCard 擷取有序集合的元素個數
  count, err := rdb.ZCard(ctx, "test_zset").Result()
  if err != nil {
    panic(err)
  }
  fmt.Println(count)  // 6

  // ZCount 擷取有序集合指定區間内元素個數
  // fmt.Println(rdb.ZCount(ctx, "test_zset", "2", "4"))
  n, err := rdb.ZCount(ctx, "test_zset", "2", "4").Result()
  if err != nil {
    panic(err)
  }
  fmt.Println(n)  // 3

  // ZScore 擷取有序集合的元素的score
  score, err := rdb.ZScore(ctx, "test_zset", "c++").Result()
  if err != nil {
    panic(err)
  }
  fmt.Println(score)  // 4

  // ZRank 傳回有序集中指定成員的排名。其中有序內建員按分數值遞增(從小到大)順序排列。
  result, err := rdb.ZRank(ctx, "test_zset", "java").Result()
  if err != nil {
    panic(err)
  }
  fmt.Println(result)  // 2

  // ZRevRank 傳回有序集合中指定成員的排名,有序內建員按分數值遞減(從大到小)排序
  result, err = rdb.ZRevRank(ctx, "test_zset", "java").Result()
  if err != nil {
    panic(err)
  }
  fmt.Println(result)  // 3

  // ZRange 傳回有序集中,指定區間内的成員,其中成員的位置按分數值遞增(從小到大)來排序。
  elems, err := rdb.ZRange(ctx, "test_zset", 0, 2).Result()
  if err != nil {
    panic(err)
  }
  fmt.Println(elems)  // [python c java]
  
  // ZRevRange 傳回有序集中,指定區間内的成員,其中成員的位置按分數值遞減(從大到小)來排列。
  elems, err = rdb.ZRevRange(ctx, "test_zset", 0, 2).Result()
  if err != nil {
    panic(err)
  }
  fmt.Println(elems)  // [visual bacis c# c++]

  // ZIncrBy 對有序集合中指定成員的分數加上一個增量
  r, err := rdb.ZIncrBy(ctx, "test_zset", 2, "c++").Result()
  if err != nil {
    panic(err)
  }
  fmt.Println(r)  // 6

  // ZRangeByScore 通過分數傳回有序集合指定區間内的成員,分數從低到高排序
  res, err := rdb.ZRangeByScore(ctx, "test_zset", &redis.ZRangeBy{
    Min:    "2",
    Max:    "5",
  }).Result()
  if err != nil {
    panic(err)
  }
  fmt.Println(res)  // [c java c#]

  // ZRevRangeByScore 傳回有序集中指定分數區間内的成員,分數從高到低排序
  res, err = rdb.ZRevRangeByScore(ctx, "test_zset", &redis.ZRangeBy{
    Min:    "2",
    Max:    "5",
  }).Result()
  if err != nil {
    panic(err)
  }
  fmt.Println(res)  // [c# java c]

  // ZRem 移除有序集合中的一個或多個成員
  rem, err := rdb.ZRem(ctx, "test_zset", "visual bacis").Result()
  if err != nil {
    panic(err)
  }
  // 删除的元素個數
  fmt.Println(rem)  // 1

  // ZRemRangeByRank 移除有序集合中給定的排名區間的所有成員
  // 按照升序删除第一個和第二個元素
  rem, err = rdb.ZRemRangeByRank(ctx, "test_zset",  0, 1).Result()
  if err != nil {
    panic(err)
  }
  fmt.Println(rem)  // 2

  // ZRemRangeByScore 移除有序集合中給定的分數區間的所有成員
  // 删除score在2-4之間的元素
  rem, err = rdb.ZRemRangeByScore(ctx, "test_zset", "2", "4").Result()
  if err != nil {
    panic(err)
  }
  fmt.Println(rem)  // 1
}

// 列印結果如下:
/*
6
3
4
2
3
[python c java]
[visual bacis c# c++]
6
[c java c#]
[c# java c]
1
2
1
*/      

6.管道操作

Redis管道可以在服務端未響應時,用戶端繼續向服務端發送請求,并最終一次性讀取所有服務端的響應。管道技術最顯著的優勢是提高了 redis 服務的性能。

下面是管道的操作示例:

package main

import (
  "context"
  "fmt"
  "time"

  "github.com/go-redis/redis/v8"
)

func main() {
  ctx := context.Background()
  
  rdb := redis.NewClient(&redis.Options{
    Addr:     "localhost:6379",
    Password: "",
    DB:       0,
  })
  _, err := rdb.Ping(ctx).Result()  // PING, <nil>
  if err != nil {
    fmt.Println("connect redis failed:", err)
    return
  }

  var incr *redis.IntCmd
  _, err = rdb.Pipelined(ctx, func(piper redis.Pipeliner) error {
    incr = piper.Incr(ctx, "pipelined_counter")
    piper.Expire(ctx, "pipelined_counter", time.Hour)
    return nil
  })
  if err != nil {
    panic(err)
  }
  fmt.Println(incr.Val())  // 1

}

// 列印結果如下:
/*
1
*/      

7.事務操作

事務可以了解為一個打包的批量執行腳本,但批量指令并非原子化的操作,中間某條指令的失敗不會導緻前面已做指令的復原,也不會造成後續的指令不做。

一個事務從開始到執行會經曆三個階段:開始事務、指令入隊及執行事務。

這裡是事務操作的示範:

待填。

8.釋出/訂閱

Redis釋出訂閱是一種消息通信模式:發送者 (pub) 發送消息,訂閱者 (sub) 接收消息。Redis的用戶端可訂閱任意數量的頻道。

Redis釋出的示範代碼:

// pub.go
package main

import (
  "context"
  "fmt"

  "github.com/go-redis/redis/v8"
)

func main() {
  ctx := context.Background()

  rdb := redis.NewClient(&redis.Options{
    Addr:     "localhost:6379",
    Password: "",
    DB:       0,
  })
  _, err := rdb.Ping(ctx).Result()  // PING, <nil>
  if err != nil {
    fmt.Println("connect redis failed:", err)
    return
  }
  
  // 釋出
  err := rdb.Publish(ctx, "mychannel1", "payload").Err()
  if err != nil {
    panic(err)
  }
  fmt.Println("publish done!")
}      

Redis訂閱的示範代碼:

// sub.go
package main

import (
  "context"
  "fmt"

  "github.com/go-redis/redis/v8"
)

func main() {
  ctx := context.Background()

  rdb := redis.NewClient(&redis.Options{
    Addr:     "localhost:6379",
    Password: "",
    DB:       0,
  })
  _, err := rdb.Ping(ctx).Result()  // PING, <nil>
  if err != nil {
    fmt.Println("connect redis failed:", err)
    return
  }
  
  // 訂閱頻道
  pubsub := rdb.Subscribe(ctx, "mychannel1")

  // 完成後關閉訂閱。
  defer pubsub.Close()

  // 接收消息
  for {
    msg, err := pubsub.ReceiveMessage(ctx)
    if err != nil {
      panic(err)
    }
    fmt.Println(msg.Channel, msg.Payload)
  }
}      

先啟動訂閱代碼sub.go,再啟動釋出代碼pub.go,即可看到效果。

參考文章

繼續閱讀