使用go-redis/redis依赖操作redis

目录

一、go-redis/redis(v6.15.9)

1.redis依赖安装

go get -u github.com/go-redis/redis
// 声明一个全局的rdb变量
var rdb *redis.Client

// 初始化连接
func initClient() (err error) {
	rdb = redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // no password set
		DB:       0,  // use default DB
	})

	_, err = rdb.Ping().Result()
	if err != nil {
		return err
	}
	return nil
}

2.redid.Z结构体

type Z struct {
	Score  float64
	Member interface{}
}

3.cmdable接口

3.1接口
//这个接口有很多方法
type Cmdable interface {
	Pipeline() Pipeliner
	Pipelined(fn func(Pipeliner) error) ([]Cmder, error)

	TxPipelined(fn func(Pipeliner) error) ([]Cmder, error)
	TxPipeline() Pipeliner

	Command() *CommandsInfoCmd
	ClientGetName() *StringCmd
	Echo(message interface{}) *StringCmd
	Ping() *StatusCmd
	.............
	}
3.2ZAdd方法
func (c *cmdable) ZAdd(key string, members ...Z) *IntCmd {}
3.3ZIncrBy方法
func (c *cmdable) ZIncrBy(key string, increment float64, member string) *FloatCmd {}
3.4ZRevRangeWithScores方法
func (c *cmdable) ZRevRangeWithScores(key string, start, stop int64) *ZSliceCmd {}
3.5ZRangeByScoreWithScores方法
func (c *cmdable) ZRangeByScoreWithScores(key string, opt ZRangeBy) *ZSliceCmd {
3.6Incr方法
func (c *cmdable) Incr(key string) *IntCmd {}

4.redsi.Pipeliner接口

type Pipeliner interface {
   StatefulCmdable
   Do(args ...interface{}) *Cmd
   Process(cmd Cmder) error
   Close() error
   Discard() error
   Exec() ([]Cmder, error)
}

5.redis.Client结构体

5.1结构体
type Client struct {
	baseClient
	cmdable
	ctx context.Context
}
5.2TxPipeline方法
func (c *Client) TxPipeline() Pipeliner {}

6.redis.baseClient结构体

6.1结构体
type baseClient struct {
	opt      *Options
	connPool pool.Pooler
	limiter  Limiter

	process           func(Cmder) error
	processPipeline   func([]Cmder) error
	processTxPipeline func([]Cmder) error

	onClose func() error // hook called when client is closed
}
6.2Do方法
func (c *baseClient) Do(args ...interface{}) *Cmd {

7.redis.IntCmd结构体

7.1结构体
type IntCmd struct {
	baseCmd
	val int64
}
7.2Result方法
func (cmd *IntCmd) Result() (int64, error) {
	return cmd.val, cmd.err
}

8.redis.FloatCmd结构体

8.1结构体
type FloatCmd struct {
	baseCmd

	val float64
}
8.2Result方法
func (cmd *FloatCmd) Result() (float64, error) {
	return cmd.Val(), cmd.Err()
}

9.redis.ZSliceCmd结构体

9.1结构体
type ZSliceCmd struct {
	baseCmd
	val []Z
}
9.2Result方法
func (cmd *ZSliceCmd) Result() ([]Z, error) {
	return cmd.val, cmd.err
}

10.baseCmd结构体

type baseCmd struct {
	_args []interface{}
	err   error
	_readTimeout *time.Duration
}

11.redis.ZRangeBy结构体

type ZRangeBy struct {
	Min, Max      string
	Offset, Count int64
}

12.sortedset有序集合zadd操作

package main

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

// 声明一个全局的rdb变量
var rdb *redis.Client

// 初始化连接
func initClient() (err error) {
	rdb = redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // no password set
		DB:       0,  // use default DB
	})
	//Ping返回的是:*StatusCmd ; Result方法是StatusCmd结构体的方法(StatusCmd的val, baseCmd的err)
	_, err = rdb.Ping().Result()
	if err != nil {
		return err
	}
	return nil
}
func redisExample2() {
	if err := initClient(); err != nil {
		return
	}
	zsetKey := "language_rank"
	languages := []redis.Z{
		redis.Z{Score: 90.0, Member: "Golang"},
		redis.Z{Score: 98.0, Member: "Java"},
		redis.Z{Score: 95.0, Member: "Python"},
		redis.Z{Score: 97.0, Member: "JavaScript"},
		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)//输出:zadd 5 succ.

	// 把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)//输出:Golang's score is 100.000000 now.

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

	// 取95~100分的
	op := 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)
		/*输出:
		Python 95
		JavaScript 97
		Java 98
		C/C++ 99
		Golang 100*/
	}
}
func main() {
	redisExample2()
	/*输出:
	zadd 5 succ.
	Golang's score is 100.000000 now.
	Golang 100
	C/C++ 99
	Java 98
	Python 95
	JavaScript 97
	Java 98
	C/C++ 99
	Golang 100

	*/
}

13.事务示例1

Redis是单线程的,因此单个命令始终是原子的,但是来自不同客户端的两个给定命令可以依次执行,例如在它们之间交替执行。但是,Multi/exec能够确保在multi/exec两个语句之间的命令之间没有其他客户端正在执行命令。
在这种场景我们需要使用TxPipeline。TxPipeline总体上类似于上面的Pipeline,但是它内部会使用MULTI/EXEC包裹排队的命令

package main

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

// 声明一个全局的rdb变量
var rdb *redis.Client

// 初始化连接
func initClient() (err error) {
	rdb = redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // no password set
		DB:       0,  // use default DB
	})

	_, err = rdb.Ping().Result()
	if err != nil {
		return err
	}
	return nil
}
func V8Example() {
	initClient()
    //Do是baseClient结构体的方法
	rdb.Do("set", "key8", "value8")
    //Client结构体里面有cmdable结构体
    //Keys是cmable结构体的方法,返回*StringSliceCmd
    // Result是StringSliceCmd结构体的方法
	vals, _ := rdb.Keys("k*").Result()
	fmt.Println(vals) //输出:[key8]
     //返回的是Pipeliner接口
	pipe := rdb.TxPipeline() //相当于MULTI开启事务
    //Pipeliner接口里定义有Do这个方法
	pipe.Do("set", "key8", "value8")
	pipe.Do("set", "key9", "value9")
    
	vals1, _ := rdb.Keys("k*").Result()
	fmt.Println(vals1) //输出:[key8]
	vals2, _ := pipe.Keys("k*").Result()
	fmt.Println(vals2) //输出:[]
    //Pipeliner接口里定义有Exec这个方法
	pipe.Exec() ///相当于EXEC事务

	vals3, _ := rdb.Keys("k*").Result()
	fmt.Println(vals3) //输出[key8 key9]

}
func main() {
	V8Example()
}

14.事务示例2

package main

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

// 声明一个全局的rdb变量
var rdb *redis.Client

// 初始化连接
func initClient() (err error) {
	rdb = redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // no password set
		DB:       0,  // use default DB
	})

	_, err = rdb.Ping().Result()
	if err != nil {
		return err
	}
	return nil
}
func V8Example() {
	initClient()
	rdb.Do("set", "tx_pipeline_counter", "1")
	val, _ := rdb.Get("tx_pipeline_counter").Result()
	fmt.Println(val) //输出:1

	pipe := rdb.TxPipeline()
	incr := pipe.Incr("tx_pipeline_counter")
	pipe.Expire("tx_pipeline_counter", time.Hour)

	pipe.Exec()
	fmt.Println(incr.Val())//输出:2
	val1, _ := rdb.Get("tx_pipeline_counter").Result()
	fmt.Println(val1) //输出:2

}
func main() {
	V8Example()
}

image-20220302170636548

二、go-redis/redis(v8)

1.redis依赖安装

最新版本的go-redis库的相关命令都需要传递context.Context参数.

2.redis.NewClient函数

func NewClient(opt *Options) *Client {}
//Options是一个结构体,里面有很多参数

3.redis.Client结构体

3.1结构体
type Client struct {
	*baseClient
	cmdable
	hooks
	ctx context.Context
}
3.2Do方法
func (c *Client) Do(ctx context.Context, args ...interface{}) *Cmd {}
3.3TxPipeline方法
func (c *Client) TxPipeline() Pipeliner {}

4.redis.Pipeliner接口

type Pipeliner interface {
	StatefulCmdable
	Do(ctx context.Context, args ...interface{}) *Cmd
	Process(ctx context.Context, cmd Cmder) error
	Close() error
	Discard() error
	Exec(ctx context.Context) ([]Cmder, error)
}

5.redis.Cmd结构体

type Cmd struct {
	baseCmd

	val interface{}
}

6.baseCmd结构体

6.1结构体
//注意:引用不到,因为是小写
type baseCmd struct {
	ctx    context.Context
	args   []interface{}
	err    error
	keyPos int8

	_readTimeout *time.Duration
}
6.2Err()方法
func (cmd *baseCmd) Err() error {
	return cmd.err
}

7.redis.StringCmd结构体

7.1结构体
type StringCmd struct {
	baseCmd
	val string
}
7.2Val方法
func (cmd *StringCmd) Val() string {
	return cmd.val
}
7.3Result方法
func (cmd *StringCmd) Result() (string, error) {
	return cmd.Val(), cmd.err
}

8.redis.StatusCmd结构体

8.1结构体
type StatusCmd struct {
	baseCmd

	val string
}
8.2Result方法
func (cmd *StatusCmd) Result() (string, error) {
	return cmd.val, cmd.err
}

9.redis.StringSliceCmd结构体

9.1结构体
type StringSliceCmd struct {
	baseCmd

	val []string
}
9.2Result()方法
func (cmd *StringSliceCmd) Result() ([]string, error) {
	return cmd.Val(), cmd.Err()
}

10.redis.ScanCmd结构体

11.1结构体
type ScanCmd struct {
	baseCmd

	page   []string
	cursor uint64

	process cmdable
}
11.2Iterator方法
func (cmd *ScanCmd) Iterator() *ScanIterator {
	return &ScanIterator{
		cmd: cmd,
	}
}

12.redis.ScanIterator结构体

12.1结构体
type ScanIterator struct {
	mu  sync.Mutex // protects Scanner and pos
	cmd *ScanCmd
	pos int
}
12.2Next方法
func (it *ScanIterator) Next(ctx context.Context) bool {}

13.redis.IntCmd结构体

13.1结构体
type IntCmd struct {
	baseCmd

	val int64
}

14.cmdable类型

14.1类型
type cmdable func(ctx context.Context, cmd Cmder) error
14.2Set方法
func (c cmdable) Set(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd {}
14.3Get方法
func (c cmdable) Get(ctx context.Context, key string) *StringCmd {}
14.4Ping方法
func (c cmdable) Ping(ctx context.Context) *StatusCmd {}
14.5Keys方法
func (c cmdable) Keys(ctx context.Context, pattern string) *StringSliceCmd {}
14.6Scan方法
func (c cmdable) Scan(ctx context.Context, cursor uint64, match string, count int64) *ScanCmd {}
14.7Del方法
func (c cmdable) Del(ctx context.Context, keys ...string) *IntCmd {} 

15.NewClusterClient函数

func NewClusterClient(opt *ClusterOptions) *ClusterClient {}

16.NewFailoverClient函数

func NewFailoverClient(failoverOpt *FailoverOptions) *Client {}

17.String类型Set、Get单操作

package main

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

var (
	rdb *redis.Client
)

// 初始化连接
func initClient() (err error) {
	rdb = redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "",  // no password set
		DB:       0,   // use default DB
		PoolSize: 100, // 连接池大小
	})
	/*func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
	  return WithDeadline(parent, time.Now().Add(timeout))}*/
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
    //Ping返回的是:*StatusCmd ; Result方法是StatusCmd结构体的方法(StatusCmd的val, baseCmd的err)
	_, err = rdb.Ping(ctx).Result()
	return err
}

func V8Example() {
	/*func Background() Context {
		return background
	}
	*/
	ctx := context.Background()
	if err := initClient(); err != nil {
		//Set是cmdable的方法Set返回的是*StatusCmd;StatusCmd结构体里面有basecmd
        //Err()是baseCmd结构体的方法 (baseCmd.err)
        //rdb是client结构体,这个结构体里面有cmdable类型,
		err := rdb.Set(ctx, "key", "value", 0).Err()
		if err != nil {
			panic(err)
		}
		//Set返回的是*StringCmd; Result是StringCmd结构体的方法 (StringCmd.Val() [StringCmd.val]  )
		val, err := rdb.Get(ctx, "key").Result()
		if err != nil {
			panic(err)
		}
		fmt.Println("key", val)

		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)
		}
		// Output: key value
		// key2 does not exist
	}
}
func main() {
	V8Example()
	/*输出:
	key value
	key2 does not exist
	*/
}

18.根据前缀获取Key

package main

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

var (
	rdb *redis.Client
)

// 初始化连接
func initClient() (err error) {
	rdb = redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "",  // no password set
		DB:       0,   // use default DB
		PoolSize: 100, // 连接池大小
	})
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	_, err = rdb.Ping(ctx).Result()
	return err
}

func V8Example() {
	ctx := context.Background()
	err := initClient()
	rdb.Set(ctx, "key", "value", 0).Err()
	rdb.Set(ctx, "keppp", "value", 0).Err()
	vals, _ := rdb.Keys(ctx, "k*").Result()
	if err != nil {
		panic(err)
	}
	fmt.Println(vals) //输出: [key keppp]

}
func main() {
	V8Example()
}

19.执行自定义命令

package main

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

var (
	rdb *redis.Client
)

// 初始化连接
func initClient() (err error) {
	rdb = redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "",  // no password set
		DB:       0,   // use default DB
		PoolSize: 100, // 连接池大小
	})
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	_, err = rdb.Ping(ctx).Result()
	return err
}

func V8Example() {
	ctx := context.Background()
	initClient()
    //Do是Client结构体的方法
	rdb.Do(ctx, "set", "key1", "value1").Result()
	val1, _ := rdb.Get(ctx, "key1").Result()
	val2, _ := rdb.Do(ctx, "get", "key1").Result()
	fmt.Println(val1) //输出:val1
	fmt.Println(val2) //输出:val1
}
func main() {
	V8Example()
}

20.按通配符删除key

当通配符匹配的key的数量不多时,可以使用Keys()得到所有的key在使用Del命令删除。 如果key的数量非常多的时候,我们可以搭配使用Scan命令和Del命令完成删除。

package main

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

var (
	rdb *redis.Client
)

// 初始化连接
func initClient() (err error) {
	rdb = redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "",  // no password set
		DB:       0,   // use default DB
		PoolSize: 100, // 连接池大小
	})
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	_, err = rdb.Ping(ctx).Result()
	return err
}

func V8Example() {
	initClient()
	ctx := context.Background()
	rdb.Do(ctx, "set", "key1", "value1").Result()
	rdb.Do(ctx, "set", "key2", "value2").Result()
	vals1, _ := rdb.Keys(ctx, "k*").Result()
	fmt.Println(vals1) //输出:[key2 key1]
	iter := rdb.Scan(ctx, 0, "k*", 0).Iterator()
	for iter.Next(ctx) {
		err := rdb.Del(ctx, iter.Val()).Err()
		if err != nil {
			panic(err)
		}
	}
	vals2, _ := rdb.Keys(ctx, "k*").Result()
	fmt.Println(vals2)//输出:[]
}
func main() {
	V8Example()
}

21.连接redis集群

func initClient() (err error) {

	rdb := redis.NewClusterClient(&redis.ClusterOptions{
		Addrs: []string{":7000", ":7001", ":7002", ":7003", ":7004", ":7005"},
	})
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	//Ping返回的是:*StatusCmd ; Result方法是StatusCmd结构体的方法(StatusCmd的val, baseCmd的err)
	_, err = rdb.Ping(ctx).Result()
	return err
}

22.连接Redis哨兵模式

func initClient() (err error) {

	rdb := redis.NewFailoverClient(&redis.FailoverOptions{
		MasterName:    "master",
		SentinelAddrs: []string{"x.x.x.x:26379", "xx.xx.xx.xx:26379", "xxx.xxx.xxx.xxx:26379"},
	})
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	_, err = rdb.Ping(ctx).Result()
	return err
}
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐