go 语言之Redis

Redis的基本使用

1 添加key-val [set]

2查看当前Redis的所有key 

3获取key 对应的值

4切换Redis数据库select index

查看当前数据库的key-val数量[dbsize]

清空当前数据库的key-val 和清空所有数据库的key-val[flushdb flushall]

127.0.0.1:6379> set c1 "qwe"
OK
127.0.0.1:6379> set c2 "qwe2"
OK
127.0.0.1:6379> keys *
 1) "c1"
 2) "add"
 3) "K1"
 4) "key2"
 5) "sure1"
 6) "key1"
 7) "c2"
 8) "herolist"
 9) "key3"
10) "user1"
11) "address"
127.0.0.1:6379> get c1
"qwe"
127.0.0.1:6379> SELECT 1
OK
127.0.0.1:6379[1]> keys *
(empty array)
127.0.0.1:6379[1]> SELECT 0
OK
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> keys *
(empty array)

     del 删除key

127.0.0.1:6379> set c2  nihao22
OK
127.0.0.1:6379> del c2
(integer) 1

  setex 键设置超时时间

127.0.0.1:6379> setex c1 4 nihao
OK
127.0.0.1:6379> get c1
"nihao"
127.0.0.1:6379> get c1
(nil)

  mset[同时设置多个值] mget同时取多个值

127.0.0.1:6379> mset c1 hgf c2 yui c3 789
OK
127.0.0.1:6379> mget c1 c2 c3
1) "hgf"
2) "yui"
3) "789"

  hash (哈希)

redis hash 是一个键值对集合,var user1 map[string]string 

redis 哈希 是一个string类型的field 和value 的映射表,哈希特别适用存储对象

127.0.0.1:6379> HSET user1 name chenxi age 45 job golang
(integer) 3
127.0.0.1:6379> HGET user1 name
"chenxi"
127.0.0.1:6379> HGET user1 age
"45"
127.0.0.1:6379> HGET user1 job
"golang"

  hgetall一次性获取所有 hdel 删除

127.0.0.1:6379> HGETall user1
1) "name"
2) "chenxi"
3) "age"
4) "45"
5) "job"
6) "golang"
127.0.0.1:6379> HDEL user1 name
(integer) 1
127.0.0.1:6379> HDEL user1 age
(integer) 1
127.0.0.1:6379> HGETall user1
1) "job"
2) "golang"

  hlen 统计多少个元素

127.0.0.1:6379> HLEN user1
(integer) 1

  hmset hmget 一次性设置多个或获取多个元素

127.0.0.1:6379> hmset user2 name chenxi age 30 job java
OK
127.0.0.1:6379> hmget user2  name age job
1) "chenxi"
2) "30"
3) "java"
127.0.0.1:6379>

  hexists判断某个值是否存在

127.0.0.1:6379> HEXISTS user1 age
(integer) 0
127.0.0.1:6379> HEXISTS user1 job
(integer) 1

  list 介绍

列表是简单的字符串列表,按照插入顺序排序,可以添加到一个元素的头部(左边)或者尾部(右边)

list 本质是一个链表,list 的元素是有序的,元素的值可以重复

list操作

127.0.0.1:6379> LPush a1 beijing shanghai tianjing guangzhou
(integer) 4
127.0.0.1:6379> LRANGE a1 0 -1
1) "guangzhou"
2) "tianjing"
3) "shanghai"
4) "beijing"

  list 列表操作

lpush/rpush/lrange/lpop/rpop/del

lrange key start stop:返回列表key 中指定区间内的元素,区间以偏移量start 和stop 指定。下标index参数start和stop都以0为底,也就是说。以0表示列表的第一个元素。以1表示列表的第二个元素;以-1表示列表的最后一个元素,-2表示列表的倒数第二个元素

  

127.0.0.1:6379> lpush a2  aaa bbb ccc
(integer) 3
127.0.0.1:6379> lrange a2 0 -1
1) "ccc"
2) "bbb"
3) "aaa"
127.0.0.1:6379> rpush a2 ddd eee
(integer) 5
127.0.0.1:6379> lrange a2 0 -1
1) "ccc"
2) "bbb"
3) "aaa"
4) "ddd"
5) "eee"
127.0.0.1:6379> LPOP a2
"ccc"
127.0.0.1:6379> LPOP a2
"bbb"
127.0.0.1:6379> lrange a2 0 -1
1) "aaa"
2) "ddd"
3) "eee"
127.0.0.1:6379> rPOP a2
"eee"
127.0.0.1:6379> lrange a2 0 -1
1) "aaa"
2) "ddd"
127.0.0.1:6379> del a2
(integer) 1
127.0.0.1:6379> lrange a2 0 -1
(empty array)

  list 使用细节

(1)index 按照索引下标,按照所有下标获取元素(从左到右,编号从0开始)

(2)LLEN key 返回列表key不存在,则key被解释为一个空列表,返回0

(3)list 其他说明

list 数据,可以从左或者右,插入添加

如果值全移走,对应的键也就消失了

set 的介绍和使用

redis 的set 是string类型的无序集合。

底层是hashTable 数据结构,set 也是存放很多字符串元素,字符串元素是无序的,而且元素的值不能重复

127.0.0.1:6379> sadd email tom@solu.com chenxi@soulu.com tianya@.com
(integer) 3
127.0.0.1:6379> SMEMBERS email
1) "tom@solu.com"
2) "chenxi@soulu.com"
3) "tianya@.com"

  go连接redis需要安装三方开源库

✅ 1. 新建项目目录
mkdir D:\code\go-projects\demo
cd D:\code\go-projects\demo
✅ 2. 初始化模块(核心)
go mod init demo

你会看到:

go.mod
mkdir xxx
cd xxx
go mod init xxx
② 引入依赖(比如你之前用的 redis)
go get github.com/redis/go-redis/v9
③ 自动整理依赖
go mod tidy

       import "context" 包介绍

package context

import "context"

package context 定义了 Context 类型,它负责在 API 边界和进程之间传递截止时间、取消信号和其他请求范围的值。

传入服务器的请求应创建一个 Context,传出服务器的调用应接受一个 Context。它们之间的函数调用链必须传播该 Context,并可选择将其替换为使用 WithCancel、WithDeadline、WithTimeout 或 WithValue 创建的派生 Context。当一个 Context 被取消时,所有从它派生的 Context 也会被取消。

WithCancel、WithDeadline 和 WithTimeout 函数接受一个 Context(父 Context),并返回一个派生 Context(子 Context)和一个 CancelFunc。调用 CancelFunc 会取消子 Context 及其子 Context,移除父 Context 对子 Context 的引用,并停止所有关联的计时器。如果未调用 CancelFunc,则子 Context 及其子 Context 会一直处于泄漏状态,直到父 Context 被取消或计时器触发为止。 go vet 工具会检查所有控制流路径上是否使用了 CancelFunc。

使用 Context 的程序应遵循以下规则,以保持跨包接口的一致性,并使静态分析工具能够检查上下文传播:

不要将 Context 存储在结构体类型中;而是将 Context 显式传递给每个需要它的函数。Context 应该是第一个参数,通常命名为 ctx:

func DoSomething(ctx context.Context, arg Arg) error {

// ... 使用 ctx ...

}

不要传递 nil Context,即使函数允许这样做。如果您不确定要使用哪个 Context,请传递 context.TODO。

仅将上下文值用于在进程和 API 之间传递的请求作用域数据,不要用于向函数传递可选参数。

同一个 Context 可以传递给在不同 goroutine 中运行的函数;Context 可以安全地被多个 goroutine 同时使用。

func Background 方法介绍

func Background() Context

Background 返回一个非空的空 Context 对象。它永远不会被取消,没有值,也没有截止时间。它通常被主函数、初始化和测试使用,也作为传入请求的顶级 Context。

  

代码

package main
import (
	"github.com/redis/go-redis/v9"
	"fmt"
	"context"

)
func main(){
	ctx := context.Background()
	//通过go 向redis 写数据 
	conn:=redis.NewClient(&redis.Options{
		Addr: "127.0.0.1:6379", //redis 地址
	    Password: "", //密码
	    DB: 0, }) //连的库
	//测试连接
	_, err := conn.Ping(ctx).Result()
	if err != nil {
		panic(err)
		//return
	}
	fmt.Println("连接 Redis 成功 ✅")
	//写数据
	err = conn.Set(ctx,"name","chenxi",0).Err()
	if err !=nil{
		panic(err)
	}
	// 4. 读数据
	val, err := conn.Get(ctx, "name").Result()
	if err != nil {
		panic(err)
	}
	fmt.Println(val)
	
 }
//执行结果
// PS D:\golang\goproject\src\src01\go_code\src> go run chapter19\tcpredisdemo01\main.go
// 连接 Redis 成功 ✅
// chenxi

  用redis 客户端查看数据

127.0.0.1:6379> get name
"chenxi"

  哈希数据

package main
import (
	"github.com/redis/go-redis/v9"
	"fmt"
	"context"

)
func main(){
	ctx := context.Background()
	//通过go 向redis 写数据 
	conn:=redis.NewClient(&redis.Options{
		Addr: "127.0.0.1:6379", //redis 地址
	    Password: "", //密码
	    DB: 0, }) //连的库
	//测试连接
	_, err := conn.Ping(ctx).Result()
	if err != nil {
		panic(err)
		//return
	}
	fmt.Println("连接 Redis 成功 ✅")
	//写数据
	err = conn.Set(ctx,"name","chenxi",0).Err()
	if err !=nil{
		panic(err)
	}
	err= conn.HSet(ctx,"users",map[string]interface{}{
		"name1": "小鹿",
		"age": 18,
		"job": "golang",
	}).Err()
	// 4. 读数据
	val, err := conn.Get(ctx, "name").Result()
	if err != nil {
		panic(err)
	}
	fmt.Println(val)
	//读数据
	val1,err := conn.HMGet(ctx, "users","name1","age","job").Result()
	fmt.Println(val1)
	
 }
//执行结果
// PS D:\golang\goproject\src\src01\go_code\src> go run chapter19\tcpredisdemo01\main.go
// 连接 Redis 成功 ✅
// chenxi
// [小鹿 18 golang]

  批量操作数据

package main
import (
	"github.com/redis/go-redis/v9"
	"fmt"
	"context"

)
func main(){
	ctx := context.Background()
	//通过go 向redis 写数据 
	conn:=redis.NewClient(&redis.Options{
		Addr: "127.0.0.1:6379", //redis 地址
	    Password: "", //密码
	    DB: 0, }) //连的库
	//测试连接
	_, err := conn.Ping(ctx).Result()
	if err != nil {
		panic(err)
		//return
	}
	fmt.Println("连接 Redis 成功 ✅")
	//写数据
	err = conn.Set(ctx,"name","chenxi",0).Err()
	if err !=nil{
		panic(err)
	}
	err= conn.HSet(ctx,"users",map[string]interface{}{
		"name1": "小鹿",
		"age": 18,
		"job": "golang",
	}).Err()
	// 4. 读数据
	val, err := conn.Get(ctx, "name").Result()
	if err != nil {
		panic(err)
	}
	fmt.Println(val)
	//读数据
	val1,err := conn.HMGet(ctx, "users","name1","age","job").Result()
	fmt.Println(val1)
	//批量操作数据
	err = conn.MSet(ctx,"name2","chenxi","age",19,"Address","河北").Err()
	if err != nil {
		panic(err)
	}
	//批量获取多个数据
	val2,err:=conn.MGet(ctx,"name2","age","Address").Result()
	fmt.Println(val2)
 }
//执行结果
// PS D:\golang\goproject\src\src01\go_code\src> go run chapter19\tcpredisdemo01\main.go
// 连接 Redis 成功 ✅
// chenxi
// [小鹿 18 golang]
// [chenxi 19 河北]

      Go 里的 Pipeline 工作流程

你这个问题已经进入 Redis 高性能核心机制 了 👍
我帮你把 Pipeline(管道)讲到“能用在项目里”的程度,而不是只停在概念。


一、先用一句话讲清 Pipeline

👉 Pipeline = 把多个 Redis 命令打包,一次性发给服务器执行


二、为什么需要 Pipeline?

先看“普通方式”👇

客户端 → Redis:SET name chenxi
Redis → 客户端:OK

客户端 → Redis:SET age 28
Redis → 客户端:OK

👉 每条命令都要:

  • 发送一次请求

  • 等一次响应


❗问题:网络往返(RTT)太多

假设:

  • 一次网络延迟 = 1ms

  • 1000 次操作 = 1000ms ❌


三、Pipeline 怎么优化?

👉 把命令打包:

客户端 → Redis:
SET name chenxi
SET age 28
GET name
GET age

Redis → 客户端:
OK
OK
chenxi
28

👉 只需要:

  • 1 次发送

  • 1 次返回


✅ 性能对比

方式网络往返次数
普通 N 次
Pipeline 1 次

👉 性能差距可以是 10倍 ~ 100倍


四、Go 里的 Pipeline 工作流程(非常重要)

标准流程:

1️⃣ 创建 pipeline
2️⃣ 写入命令(不会执行)
3️⃣ Exec 执行
4️⃣ 获取结果

✅ 示例代码

pipe := rdb.Pipeline()

set1 := pipe.Set(ctx, "name", "chenxi", 0)
set2 := pipe.Set(ctx, "age", 28, 0)
get1 := pipe.Get(ctx, "name")
get2 := pipe.Get(ctx, "age")

_, err := pipe.Exec(ctx)
if err != nil {
    panic(err)
}

fmt.Println(set1.Val())
fmt.Println(set2.Val())
fmt.Println(get1.Val())
fmt.Println(get2.Val())

五、Pipeline 的本质(你要真正理解这个)

👉 它不是并发执行
👉 它是 减少网络开销


❗关键点:

  • Redis 仍然是 单线程执行命令

  • 只是客户端一次发过去很多命令


六、Pipeline vs 普通操作(本质区别)

项目普通Pipeline
执行方式 一条一条发 批量发
网络开销 极低
延迟
适合场景 少量操作 批量操作

七、Pipeline vs 事务(很多人会混淆)

👉 这是重点!!!

特性Pipeline事务(MULTI/EXEC)
原子性 ❌ 没有 ✅ 有
失败回滚 ❌ 不支持 ❌(Redis事务也不回滚)
目的 性能优化 保证顺序执行
是否一起执行 ❌ 只是批量发送 ✅ 一起执行

👉 一句话区分:

  • Pipeline 👉

  • 事务 👉 顺序执行


八、什么时候必须用 Pipeline(实战场景)

你未来做:

👉 亚马逊选品系统 / 爬虫系统


🔥 场景1:批量写入商品

for _, p := range products {
    pipe.HSet(ctx, "product:"+p.ID, p.Data)
}
pipe.Exec(ctx)

🔥 场景2:批量读取缓存

for _, key := range keys {
    pipe.Get(ctx, key)
}
pipe.Exec(ctx)

🔥 场景3:任务队列

for _, url := range urls {
    pipe.LPush(ctx, "task_queue", url)
}

九、使用 Pipeline 的注意事项(很关键)

❗1. 必须调用 Exec()

不然:

👉 什么都不会执行


❗2. 不要在 Exec 前调用 .Result()

cmd := pipe.Get(ctx, "key")

👉 Exec 后:

cmd.Val()

❗3. 批量不要太大

👉 一次几千条 OK
👉 几十万条 ❌(会占内存)


❗4. 适合“无依赖操作”

SET A
SET B
GET C

👉 OK

但:

SET A
GET A(依赖结果)

👉 不适合 pipeline


十、现在的阶段,一句很关键的话

现在学的 Pipeline,不是一个“小技巧”,而是:

高并发系统的基础能力


最后帮总结一句话(记住这个就够了)

👉 Pipeline = 用一次网络请求,完成一批 Redis 操作

遍历示例

package main
import (
	"github.com/redis/go-redis/v9"
	"fmt"
	"context"
	"time"

)
func main(){
	ctx := context.Background()
	//通过go 向redis 写数据 
	conn:=redis.NewClient(&redis.Options{
		Addr: "127.0.0.1:6379", //redis 地址
	    Password: "", //密码
	    DB: 0, }) //连的库
	//测试连接
	_, err := conn.Ping(ctx).Result()
	if err != nil {
		panic(err)
		//return
	}
	fmt.Println("连接 Redis 成功 ✅")
	//写数据
	err = conn.Set(ctx,"name","chenxi",0).Err()
	if err !=nil{
		panic(err)
	}
	err= conn.HSet(ctx,"users",map[string]interface{}{
		"name1": "小鹿",
		"age": 18,
		"job": "golang",
	}).Err()
	// 4. 读数据
	val, err := conn.Get(ctx, "name").Result()
	if err != nil {
		panic(err)
	}
	fmt.Println(val)
	//读数据
	val1,err := conn.HMGet(ctx, "users","name1","age","job").Result()
	fmt.Println(val1)
	//批量操作数据
	err = conn.MSet(ctx,"name2","chenxi","age",19,"Address","河北").Err()
	if err != nil {
		panic(err)
	}
	//批量获取多个数据
	val2,err:=conn.MGet(ctx,"name2","age","Address").Result()
	fmt.Println(val2)
	/*
	pipe.MGet(...) 没有执行,所以拿不到数据
	二、Pipeline 的本质(你必须理解)

👉 Pipeline 就像一个“命令缓冲区”:

你写的命令 → 先放进去(不会立刻执行)
只有 Exec() → 才真正发给 Redis
👉 这个 .Result() 的前提是:

命令已经执行过(Exec)

但你没有 Exec,所以:

没有返回值 ❌
可能是 nil / 空 ❌
1️⃣ pipe.xxx()   (收集命令)
2️⃣ pipe.xxx()   (继续收集)
3️⃣ Exec()       (统一执行)
4️⃣ cmd.Val()    (取结果)
七、你刚刚这个错误,本质说明什么?

👉 你已经开始进入:

“异步/批量执行模型”

这是 Go + Redis 的高级用法,不是初学者内容了。
八、再给一个进阶建议(非常重要)

以后写 pipeline,养成这个习惯:

cmd := pipe.Get(ctx, "key")

👉 不要直接 .Result()
👉 一定要:

cmd.Val()

在 Exec 之后取值
最后一句话(点醒你)

👉 Pipeline 不是“立即执行”,而是:

先收集 → 再统一执行 → 再取结果
	*/
	pipe := conn.Pipeline()
	pipe.Set(ctx, "name", "chenxi", time.Minute)
	pipe.Set(ctx, "age", 28, time.Minute)
	_, err = pipe.Exec(ctx)
	if err != nil {
    	panic(err)
	}	
	// var3,err:=pipe.MGet(ctx, "name","age").Result()
	var3:= pipe.MGet(ctx, "name", "age")
	_, err = pipe.Exec(ctx)
	if err != nil {
    	panic(err)
	}
	fmt.Println(var3.Val())

	for i ,v:= range var3.Val(){
		fmt.Printf("var3[%d]=%s\n",i,v)
	}
 }
//执行结果
// PS D:\golang\goproject\src\src01\go_code\src> go run chapter19\tcpredisdemo01\main.go
// 连接 Redis 成功 ✅
// chenxi
// [小鹿 18 golang]
// [chenxi 19 河北]
// [chenxi 28]
// var3[0]=chenxi
// var3[1]=28

  练习题

package main
import (
	"github.com/redis/go-redis/v9"
	"fmt"
	"context"
	//"time"

)
func main(){
	var  name string
	var  age int
	var skill string
	fmt.Println("输入名字")
	fmt.Scanln(&name)
	fmt.Println("输入年龄")
	fmt.Scanln(&age)
	fmt.Println("职业")
	fmt.Scanln(&skill)
	ctx := context.Background()
	//通过go 向redis 写数据 
	conn:=redis.NewClient(&redis.Options{
		Addr: "127.0.0.1:6379", //redis 地址
	    Password: "", //密码
	    DB: 0, }) //连的库
	//测试连接
	_, err := conn.Ping(ctx).Result()
	if err != nil {
		panic(err)
		//return
	}
	fmt.Println("连接 Redis 成功 ✅")
	

	//写数据
	// err = conn.Set(ctx,"name","chenxi",0).Err()
	// if err !=nil{
	// 	panic(err)
	// }
	// err= conn.HSet(ctx,"users",map[string]interface{}{
	// 	"name1": name,
	// 	"age": age,
	// 	"job": skill,
	// }).Err()

	pipe := conn.Pipeline()
	var3:=pipe.HSet(ctx,"user",map[string]interface{}{
		"name":name,
		"age":age,
		"skill":skill,
	})
	ge:=pipe.HGetAll(ctx,"user")
	_, err = pipe.Exec(ctx)
	if err !=nil{
		fmt.Println("你好")
	}
	fmt.Println("这次新写入的字段数量",var3.Val())
	for i,k := range ge.Val(){
		fmt.Printf("var3[%v]=%v\n",i,k)
	}
 }
//执行结果
// PS D:\golang\goproject\src\src01\go_code\src> go run chapter19\tcpredisdemo02\main.go
// 输入名字
// chenxi
// 输入年龄
// 15
// 职业
// java
// 连接 Redis 成功 ✅
// 这次新写入的字段数量 3
// var3[name]=chenxi
// var3[age]=15
// var3[skill]=java

  redis 连接池

说明: 通过golang对redis 操作,还可以通过Redis连接池流程如下

1)事先初始化一定数量的连接,放入连接池里

2)当go 需要操作Redis时,直接从Redis 连接池取出连接

3)这样可以省下来获取Redis链接的时间,从而提高效率

示例

rdb := redis.NewClient(&redis.Options{
    Addr:         "localhost:6379",
    PoolSize:     10,  // 最大连接数
    MinIdleConns: 2,   // 最小空闲连接
})

  示例

rdb := redis.NewClient(&redis.Options{
    Addr:         "localhost:6379",
    Password:     "",
    DB:           0,

    PoolSize:     20, // 最大连接数(核心参数)
    MinIdleConns: 5,  // 最小空闲连接

    DialTimeout:  5 * time.Second,
    ReadTimeout:  3 * time.Second,
    WriteTimeout: 3 * time.Second,
})

  参数

| 参数           | 作用            |
| ------------ | ------------- |
| PoolSize     | 最大并发连接数       |
| MinIdleConns | 保持几个“随时可用”的连接 |
| Timeout      | 防止卡死          |

DialTimeout   → 建立连接最多等多久
ReadTimeout   → 读数据最多等多久
WriteTimeout  → 写数据最多等多久

  示例

package main

import (
	"context"
	"fmt"
	"sync"
	//"time"

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

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

	rdb := redis.NewClient(&redis.Options{
		Addr:         "localhost:6379",
		PoolSize:     10, // 控制并发连接
		MinIdleConns: 3,
	})

	// 先写入数据
	rdb.Set(ctx, "name", "chenxi", 0)

	var wg sync.WaitGroup

	// 模拟100个并发请求
	for i := 0; i < 10; i++ {
		wg.Add(1)

		go func(i int) {
			defer wg.Done()

			val, err := rdb.Get(ctx, "name").Result()
			if err != nil {
				fmt.Println("错误:", err)
				return
			}

			fmt.Printf("goroutine %d -> %s\n", i, val)
		}(i)
	}

	wg.Wait()
}
//执行结果
// PS D:\golang\goproject\src\src01\go_code\src> go run chapter19\tcpredisdemo05\main.go
// goroutine 9 -> chenxi
// goroutine 8 -> chenxi
// goroutine 3 -> chenxi
// goroutine 2 -> chenxi
// goroutine 4 -> chenxi
// goroutine 1 -> chenxi
// goroutine 6 -> chenxi
// goroutine 0 -> chenxi
// goroutine 7 -> chenxi
// goroutine 5 -> chenxi

  重点在这里

1️⃣ 所有 goroutine 共用一个 rdb
rdb := redis.NewClient(...)

👉 ❗不是每个 goroutine 新建连接

2️⃣ 连接池自动分配连接
100个请求 → 连接池最多给10个连接(PoolSize=10)

👉 多出来的请求会:

等待连接
或复用空闲连接
3️⃣ 没有手动 close

👉 因为:

✅ 连接是复用的,不是一次性的

  结合 Pipeline(高性能写入)

package main

import (
	"context"
	"fmt"
	"github.com/redis/go-redis/v9"
)
var (
	rdb *redis.Client
	ctx context.Context
)
func init(){
	ctx = context.Background()
	rdb = redis.NewClient(&redis.Options{
		Addr:         "localhost:6379",
		PoolSize:     10, // 控制并发连接
		MinIdleConns: 3,
	})
}

func main() {

	// 先写入数据
	//rdb.Set(ctx, "name", "chenxi", 0)
	pipe := rdb.Pipeline()

	for i := 0; i < 1000; i++ {
		key := fmt.Sprintf("product:%d", i)

		pipe.HSet(ctx, key, map[string]interface{}{
			"name":  fmt.Sprintf("商品%d", i),
			"price": i * 10,
		})
	}

	_, err := pipe.Exec(ctx)
	if err != nil {
		panic(err)
	}
	var cursor uint64
	for  {
	keys,nextCursor,err:=rdb.Scan(ctx ,cursor,"product:*",100).Result()
	if err !=nil{
		fmt.Println("错误")
		return
	}
	for _,key:=range keys{
		fmt.Println("key:", key)
		// 获取数据
		data, _ := rdb.HGetAll(ctx, key).Result()
		fmt.Println(data)
	}
	cursor = nextCursor

	if cursor == 0 {
		break
	}
	}
	
}
//执行结果
// PS D:\golang\goproject\src\src01\go_code\src> go run chapter19\tcpredisdemo06\main.go
// key: product:13
// map[name:商品13 price:130]
// ...
// key: product:122
// map[name:商品122 price:1220]

  

 

posted @ 2026-04-02 09:24  烟雨楼台,行云流水  阅读(3)  评论(0)    收藏  举报