可以看到通过客户端方法Do/Receive获取可供方便转换的gvar.Var通用变量结果。通过gvar.Var的强大转换功能可以转换为任意的数据类型,如基本数据类型Int,String,Strings,或者结构体Struct等等。

Do示例

package main

import (
	"fmt"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gctx"
)

func main() {
	var (
		ctx = gctx.New()
	)

	conn, _ := g.Redis().Conn(ctx)
	defer conn.Close(ctx)
	conn.Do(ctx, "SET", "k", "v")
	v, _ := conn.Do(ctx, "GET", "k")
	fmt.Println(v.String())
}
执行后,输出结果为:
v

Receive示例

package main

import (
	"fmt"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gctx"
)

func main() {
	var (
		ctx = gctx.New()
	)

	conn, _ := g.Redis().Conn(ctx)
	defer conn.Close(ctx)
	_, err := conn.Do(ctx, "SUBSCRIBE", "channel")
	if err != nil {
		panic(err)
	}
	for {
		reply, err := conn.Receive(ctx)
		if err != nil {
			panic(err)
		}
		fmt.Println(reply.Strings())
	}
}

执行后,程序将阻塞等待获取数据。

另外打开一个终端通过redis-cli命令进入Redis Server,发布一条消息:

$ redis-cli
127.0.0.1:6379> publish channel test
(integer) 1
127.0.0.1:6379>

随后程序终端立即打印出从Redis Server获取的数据:

[message channel test]

HashSet示例

HashSet是我们比较常用的Redis数据结构,我们可以非常方便地将Redis中的HashSet获取并转换为Golang Map

package main

import (
	"fmt"
	"github.com/gogf/gf/v2/container/gvar"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gctx"
)

func main() {
	var (
		ctx = gctx.New()
		err    error
		result *gvar.Var
		key    = "user"
	)

	_, err = g.Redis().Do(ctx,"HSET", key, "id", 10000)
	if err != nil {
		panic(err)
	}
	_, err = g.Redis().Do(ctx,"HSET", key, "name", "john")
	if err != nil {
		panic(err)
	}
	result, err = g.Redis().Do(ctx,"HGETALL", key)
	if err != nil {
		panic(err)
	}
	fmt.Println(result.Map())
}
Content Menu

  • No labels

18 Comments

  1. `HashSet是我们比较常用的Redis数据结构` ??

  2. 为什么经过DoVar出来的结果会被base64编码

     var (
    	config = gredis.Config{
    		Host: "127.0.0.1",
    		Port: 6379,
    		Db:   0,
    	}
    ) 
    func main() {  
    	group := "test"
    	gredis.SetConfig(&config, group)
    
    	redis := gredis.Instance(group)
    	defer redis.Close()
    
    	_, err := redis.Do("ZADD", "mykey", 1, "golang", 2, "c++", 3, "java")
    	if err != nil {
    		panic(err)
    	}
    	r, err := redis.Do("ZSCAN", "mykey", 0)
    	if err != nil {
    		panic(err)
    	}
    
    	if list, ok := r.([]interface{}); ok {
    		fmt.Println(len(list), list)
    		if len(list) >= 2 {
    			fmt.Println(gconv.String(list[0]))
    			fmt.Println(gconv.Strings(list[1]))
    		}
    	}
    	fmt.Println("----------------------------")
    	r1, err := redis.DoVar("ZSCAN", "mykey", 1)
    	if err != nil {
    		panic(err)
    	}
    	fmt.Println(r1)
    }
    2 [[48] [[103 111 108 97 110 103] [49] [99 43 43] [50] [106 97 118 97] [51]]]
    0
    [golang 1 c++ 2 java 3]
    ----------------------------
    ["0","[\"Z29sYW5n\",\"MQ==\",\"Yysr\",\"Mg==\",\"amF2YQ==\",\"Mw==\"]"]
    
    
    1. 因为底层数据是[]byte类型,打印出来的时候fmt包会按照base64打印。

      1. 并不是,是转换底层调用了json.Marshal

        C:\hailaz\go\pkg\mod\github.com\gogf\gf@v1.15.7\util\gconv\gconv.go:420

        C:\Program Files\Go\src\encoding\json\encode.go

        // Array and slice values encode as JSON arrays, except that
        // []byte encodes as a base64-encoded string, and a nil slice
        // encodes as the null JSON value.

        1. 为什么经过DoVar出来的结果会被base64编码?

          回答:因为底层数据是[]byte类型,打印出来的时候fmt包会按照base64打印。

          1. 这跟fmt真的没关系

            	bs := []byte{48, 49}
            	fmt.Println(bs, string(bs))
            	b, _ := json.Marshal(bs)
            	fmt.Println(b, string(b))
            
            // output
            [48 49] 01
            [34 77 68 69 61 34] "MDE="
        2. 你那个截图我猜得没错是处理的slice类型,而不是slice中的[]byte元素项。

          1. 是当成slice处理了,我认为这个结果不符合预期。

  3. 当我查询一个正常的 redis set

    数据库中仅存有一个 4

    但是当我取值时我获得了 json.Marsal 后的值,这不是一个正常的表现

    我的代码
    items, err := g.Redis().Ctx(ctx).DoVar("SSCAN", myFollowKey, 0, "match", "*", "count", 1000)
    // value={interface | []string} => 0:"0",1:"["NA=="]" 
    // safe=false

    我没办法上传图片,事实上这是一个很明显的bug

    郭强 


    1. 你把完整的可复现该问题的最小可运行示例代码提个issue呢。

  4. redis 支持pipline吗?

  5. g.Redis().Ctx(ctx).DoVar("ZRANGEBYSCORE", key, 0, float64(time.Now().Unix())) 无法设置分页参数
  6. 请问如何设置redis键的过期时间???

    1. g.Redis().Do("EXPIRE", key, timeOutSeconds)


  7. 支持lua脚本嘛,如果支持怎么使用

    1. 原则上是支持的, lua脚本两种执行方式, EVAL ,或者先SCRIPT LOAD lua脚本然后保存返回sha值,后面通过EVALSHA执行。 

          ctx := context.Background()
      	_,_ = g.Redis().Do(ctx, "SET", "asdf", "xoo][:::::>")
      	v, err := g.Redis().Do(ctx, "EVAL", "return redis.call('get', KEYS[1])", 1, "asdf")
      	if err != nil {
      		panic(err)
      	}
      	fmt.Println(v.String())
      
      	shaV, err := g.Redis().Do(ctx, "SCRIPT", "LOAD", "return redis.call('get', KEYS[1])")
      	if err != nil {
      		panic(err)
      	}
      	sha := shaV.String()
      	fmt.Println(sha)
      	v, err = g.Redis().Do(ctx, "EVALSHA", sha, 1, "asdf")
      	if err != nil {
      		panic(err)
      	}
      	fmt.Println(v.String())