8.2 Go与各种Redis数据类型

8.2.1 读写列表类对象

工程结构如下:

(base) yanglei@yuanhong redisDataType % tree ./
./
├── conn
│   ├── pool.go
│   └── redis.go
├── dataType
│   └── list
│       └── list.go
├── go.mod
├── go.sum
└── main.go

3 directories, 6 files

其中conn/目录下的文件和上一小节的完全相同.

dataType/list/list.go:

package list

import (
	"github.com/gomodule/redigo/redis"
)

func LPush(conn redis.Conn, key string, values ...string) (int, error) {
	length := 0

	for _, value := range values {
		err := conn.Send("LPUSH", key, value)
		if err != nil {
			return 0, err
		}
	}
	err := conn.Flush()
	if err != nil {
		return 0, err
	}

	for i := 0; i < len(values); i++ {
		reply, _ := redis.Int(conn.Receive())
		length = reply
	}

	return length, nil
}

func RPush(conn redis.Conn, key string, values ...string) (int, error) {
	length := 0

	for _, value := range values {
		err := conn.Send("RPUSH", key, value)
		if err != nil {
			return 0, err
		}
	}
	err := conn.Flush()
	if err != nil {
		return 0, err
	}

	for i := 0; i < len(values); i++ {
		reply, _ := redis.Int(conn.Receive())
		length = reply
	}

	return length, nil
}

func LPop(conn redis.Conn, key string) (string, error) {
	return redis.String(conn.Do("LPOP", key))
}

func RPop(conn redis.Conn, key string) (string, error) {
	return redis.String(conn.Do("RPOP", key))
}

func LLen(conn redis.Conn, key string) (int, error) {
	return redis.Int(conn.Do("LLEN", key))
}

func LRange(conn redis.Conn, key string, start int, end int) ([]string, error) {
	return redis.Strings(conn.Do("LRANGE", key, start, end))
}

func LTrim(conn redis.Conn, key string, start int, end int) (string, error) {
	return redis.String(conn.Do("LTRIM", key, start, end))
}

func LSet(conn redis.Conn, key string, index int, value string) (string, error) {
	return redis.String(conn.Do("LSET", key, index, value))
}

func LIndex(conn redis.Conn, key string, index int) (string, error) {
	return redis.String(conn.Do("LINDEX", key, index))
}

main.go:

package main

import (
	"fmt"
	"log"
	"redisDataType/conn"
	"redisDataType/dataType/list"
	"time"
)

func main() {
	conf := conn.Conf{
		NetWork:  "tcp",
		Address:  "localhost:6379",
		User:     "redis_user",
		Password: "redis_password",
	}

	poolConf := conn.PoolConf{
		MaxIdle:     10,
		MaxActive:   100,
		IdleTimeout: time.Hour,
		Conf:        conf,
	}

	// 初始化连接池
	conn.NewPool(poolConf)

	// 从连接池中获取一个连接
	redisConn, err := conn.GetConnFromPool(poolConf)
	if err != nil {
		log.Fatalf("get conn from pool error: %v\n", err)
	}

	// 将该连接返回到连接池中
	defer conn.CloseConnToPool(redisConn)

	// 用LPUSH命令将元素插入到列表头部
	values := []string{"3", "2", "1"}
	length, err := list.LPush(redisConn, "myList", values...)
	if err != nil {
		log.Fatalf("LPUSH error: %v\n", err)
	}
	fmt.Printf("after LPUSH, length of list =  %d\n", length)

	// 查看列表中的元素
	elements, err := list.LRange(redisConn, "myList", 0, -1)
	if err != nil {
		log.Fatalf("LRANGE error: %v\n", err)
	}
	fmt.Printf("after LPUSH, LRANGE: %v\n", elements)

	// 用RPUSH命令将元素插入到列表尾部
	values = []string{"4", "5", "6"}
	length, err = list.RPush(redisConn, "myList", values...)
	if err != nil {
		log.Fatalf("RPUSH error: %v\n", err)
	}
	fmt.Printf("after RPUSH, length of list =  %d\n", length)

	// 查看列表中的元素
	elements, err = list.LRange(redisConn, "myList", 0, -1)
	if err != nil {
		log.Fatalf("LRANGE error: %v\n", err)
	}
	fmt.Printf("after RPUSH, LRANGE: %v\n", elements)

	// 用LPOP命令从列表头部弹出一个元素
	element, err := list.LPop(redisConn, "myList")
	if err != nil {
		log.Fatalf("LPOP error: %v\n", err)
	}
	fmt.Printf("the element which operated by LPOP =  %s\n", element)

	// 查看列表中的元素
	elements, err = list.LRange(redisConn, "myList", 0, -1)
	if err != nil {
		log.Fatalf("LRANGE error: %v\n", err)
	}
	fmt.Printf("after LPOP, LRANGE: %v\n", elements)
}

运行结果如下:

(base) yanglei@yuanhong redisDataType % go run main.go
after LPUSH, length of list =  3
after LPUSH, LRANGE: [1 2 3]
after RPUSH, length of list =  6
after RPUSH, LRANGE: [1 2 3 4 5 6]
the element which operated by LPOP =  1
after LPOP, LRANGE: [2 3 4 5 6]

8.2.2 读写哈希表类对象

工程结构如下:

(base) yanglei@yuanhong redisDataType % tree ./       
./
├── conn
│   ├── pool.go
│   └── redis.go
├── dataType
│   ├── hash
│   │   └── hash.go
│   └── list
│       └── list.go
├── go.mod
├── go.sum
└── main.go

4 directories, 7 files

dataType/hash/hash.go:

package hash

import (
	"github.com/gomodule/redigo/redis"
)

func HSet(conn redis.Conn, key string, hashes map[string]string) (int, error) {
	_, err := conn.Do("HMSET", redis.Args{}.Add(key).AddFlat(hashes)...)
	if err != nil {
		return 0, err
	}

	length, err := HLen(conn, key)
	if err != nil {
		// TODO: 此处获取长度失败不应该返回0
		return 0, err
	}

	return length, nil
}

func HLen(conn redis.Conn, key string) (int, error) {
	return redis.Int(conn.Do("HLEN", key))
}

func HGet(conn redis.Conn, key string, field string) (string, error) {
	return redis.String(conn.Do("HGET", key, field))
}

func HGetAll(conn redis.Conn, key string) (map[string]string, error) {
	return redis.StringMap(conn.Do("HGETALL", key))
}

func HExists(conn redis.Conn, key string, field string) (bool, error) {
	return redis.Bool(conn.Do("HEXISTS", key, field))
}

func HDel(conn redis.Conn, key string, fields ...string) (int, error) {
	args := redis.Args{}.Add(key).AddFlat(fields)
	return redis.Int(conn.Do("HDEL", args...))
}

main.go:

package main

import (
	"fmt"
	"log"
	"redisDataType/conn"
	"redisDataType/dataType/hash"
	"time"
)

func main() {
	conf := conn.Conf{
		NetWork:  "tcp",
		Address:  "localhost:6379",
		User:     "redis_user",
		Password: "redis_password",
	}

	poolConf := conn.PoolConf{
		MaxIdle:     10,
		MaxActive:   100,
		IdleTimeout: time.Hour,
		Conf:        conf,
	}

	// 初始化连接池
	conn.NewPool(poolConf)

	// 从连接池中获取一个连接
	redisConn, err := conn.GetConnFromPool(poolConf)
	if err != nil {
		log.Fatalf("get conn from pool error: %v\n", err)
	}

	// 将该连接返回到连接池中
	defer conn.CloseConnToPool(redisConn)

	// 向哈希表添加字段
	hashMap := map[string]string{
		"field1": "value1",
		"field2": "value2",
	}
	length, err := hash.HSet(redisConn, "hash", hashMap)
	if err != nil {
		log.Fatalf("HSET error: %v\n", err)
	}
	fmt.Printf("after HSET, the length of hash is %d\n", length)

	// 从哈希表中获取字段
	value, err := hash.HGet(redisConn, "hash", "field1")
	if err != nil {
		log.Fatalf("HGET error: %v\n", err)
	}
	fmt.Printf("key = %s, field = %s, value = %s \n", "hash", "field1", value)

	// 获取哈希表的长度
	length, err = hash.HLen(redisConn, "hash")
	if err != nil {
		log.Fatalf("HLEN error: %v\n", err)
	}
	fmt.Printf("the length of hash is %d\n", length)

	// 获取哈希表的所有字段和值
	hashMapResult, err := hash.HGetAll(redisConn, "hash")
	if err != nil {
		log.Fatalf("HGETALL error: %v\n", err)
	}
	fmt.Printf("the result of HGETALL is %v\n", hashMapResult)

	// 判断哈希表中是否存在某个字段
	exists, err := hash.HExists(redisConn, "hash", "field1")
	if err != nil {
		log.Fatalf("HEXISTS error: %v\n", err)
	}
	fmt.Printf("the field1 of hash exists: %v\n", exists)

	exists, err = hash.HExists(redisConn, "hash", "field3")
	if err != nil {
		log.Fatalf("HEXISTS error: %v\n", err)
	}
	fmt.Printf("the field3 of hash exists: %v\n", exists)

	// 删除哈希表中的字段
	deletedNum, err := hash.HDel(redisConn, "hash", "field1", "field2", "field3")
	if err != nil {
		log.Fatalf("HDEL error: %v\n", err)
	}
	fmt.Printf("the number of deleted fields is %d\n", deletedNum)
}
(base) yanglei@yuanhong redisDataType % go run main.go
after HSET, the length of hashes is 2
key = hashes, field = field1, value = value1 
the length of hashes is 2
the result of HGETALL is map[field1:value1 field2:value2]
the field1 of hashes exists: true
the field3 of hashes exists: false
the number of deleted fields is 2

8.2.3 读写集合类对象

工程结构如下:

(base) yanglei@yuanhong redisDataType % tree ./
./
├── conn
│   ├── pool.go
│   └── redis.go
├── dataType
│   ├── hash
│   │   └── hash.go
│   ├── list
│   │   └── list.go
│   └── set
│       └── set.go
├── go.mod
├── go.sum
└── main.go

5 directories, 8 files

dataType/set/set.go:

package set

import "github.com/gomodule/redigo/redis"

func SAdd(conn redis.Conn, key string, members ...interface{}) (int, error) {
	args := redis.Args{}.Add(key).AddFlat(members)
	return redis.Int(conn.Do("SADD", args...))
}

func SIsMember(conn redis.Conn, key string, member interface{}) (bool, error) {
	return redis.Bool(conn.Do("SISMEMBER", key, member))
}

func SMembers(conn redis.Conn, key string) ([]string, error) {
	return redis.Strings(conn.Do("SMEMBERS", key))
}

// SRem 删除集合中的元素(根据给定的元素值删除) 返回删除的元素个数
func SRem(conn redis.Conn, key string, members ...interface{}) (int, error) {
	args := redis.Args{}.Add(key).AddFlat(members)
	return redis.Int(conn.Do("SREM", args...))
}

// SPop 随机删除并返回集合中的一个元素
func SPop(conn redis.Conn, key string) (string, error) {
	return redis.String(conn.Do("SPOP", key))
}

main.go:

package main

import (
	"fmt"
	"log"
	"redisDataType/conn"
	"redisDataType/dataType/set"
	"time"
)

func main() {
	conf := conn.Conf{
		NetWork:  "tcp",
		Address:  "localhost:6379",
		User:     "redis_user",
		Password: "redis_password",
	}

	poolConf := conn.PoolConf{
		MaxIdle:     10,
		MaxActive:   100,
		IdleTimeout: time.Hour,
		Conf:        conf,
	}

	// 初始化连接池
	conn.NewPool(poolConf)

	// 从连接池中获取一个连接
	redisConn, err := conn.GetConnFromPool(poolConf)
	if err != nil {
		log.Fatalf("get conn from pool error: %v\n", err)
	}

	// 将该连接返回到连接池中
	defer conn.CloseConnToPool(redisConn)

	// 向集合中添加元素
	newMemberNum, err := set.SAdd(redisConn, "setKey", "setValue1", "setValue2", "setValue4", "setValue6")
	if err != nil {
		log.Fatalf("SADD error: %v\n", err)
	}
	fmt.Printf("new memeber num: %d\n", newMemberNum)

	newMemberNum, err = set.SAdd(redisConn, "setKey", "setValue2", "setValue3")
	if err != nil {
		log.Fatalf("SADD error: %v\n", err)
	}
	fmt.Printf("new memeber num: %d\n", newMemberNum)

	// 判断给定元素是否存在于集合中
	isMember, err := set.SIsMember(redisConn, "setKey", "setValue1")
	if err != nil {
		log.Fatalf("SISMEMBER error: %v\n", err)
	}
	fmt.Printf("setValue1 is member: %v\n", isMember)

	isMember, err = set.SIsMember(redisConn, "setKey", "setValue5")
	if err != nil {
		log.Fatalf("SISMEMBER error: %v\n", err)
	}
	fmt.Printf("setValue5 is member: %v\n", isMember)

	// 获取集合的所有元素
	members, err := set.SMembers(redisConn, "setKey")
	if err != nil {
		log.Fatalf("SMEMBERS error: %v\n", err)
	}
	fmt.Printf("members: %v\n", members)

	// 根据给定的元素值删除元素
	delSets := []interface{}{"setValue1", "setValue2", "setValue5"}
	delNum, err := set.SRem(redisConn, "setKey", delSets...)
	if err != nil {
		log.Fatalf("SREM error: %v\n", err)
	}
	fmt.Printf("delete num by SREM: %d\n", delNum)

	// 随机删除并返回集合中的一个元素
	popMember, err := set.SPop(redisConn, "setKey")
	if err != nil {
		log.Fatalf("SPOP error: %v\n", err)
	}
	fmt.Printf("pop member: %s\n", popMember)
}

运行结果如下:

(base) yanglei@yuanhong redisDataType % go run main.go
new memeber num: 4
new memeber num: 1
setValue1 is member: true
setValue5 is member: false
members: [setValue2 setValue4 setValue1 setValue6 setValue3]
delete num by SREM: 2
pop member: setValue4

8.2.4 读写有序集合类对象

工程结构如下:

(base) yanglei@yuanhong redisDataType % tree ./
./
├── conn
│   ├── pool.go
│   └── redis.go
├── dataType
│   ├── hash
│   │   └── hash.go
│   ├── list
│   │   └── list.go
│   ├── set
│   │   └── set.go
│   └── sortedSet
│       └── sortedSet.go
├── go.mod
├── go.sum
└── main.go

6 directories, 9 files

dataType/sortedSet/sortedSet.go:

package sortedSet

import (
	"github.com/gomodule/redigo/redis"
)

func ZAdd(conn redis.Conn, key string, scoreMap map[int]interface{}) (int, error) {
	args := redis.Args{}.Add(key).AddFlat(scoreMap)
	return redis.Int(conn.Do("ZADD", args...))
}

func ZCard(conn redis.Conn, key string) (int, error) {
	return redis.Int(conn.Do("ZCARD", key))
}

// ZRange 根据索引获取有序集合中的元素(按照分数从小到大排序)
func ZRange(conn redis.Conn, key string, start int, stop int) ([]string, error) {
	return redis.Strings(conn.Do("ZRANGE", key, start, stop))
}

// ZRevRange 根据索引获取有序集合中的元素(按照分数从大到小排序)
func ZRevRange(conn redis.Conn, key string, start int, stop int) ([]string, error) {
	return redis.Strings(conn.Do("ZREVRANGE", key, start, stop))
}

func ZScore(conn redis.Conn, key string, member string) (float64, error) {
	return redis.Float64(conn.Do("ZSCORE", key, member))
}

func ZRem(conn redis.Conn, key string, members ...string) (int, error) {
	args := redis.Args{}.Add(key).AddFlat(members)
	return redis.Int(conn.Do("ZREM", args...))
}

main.go:

package main

import (
	"fmt"
	"log"
	"redisDataType/conn"
	"redisDataType/dataType/sortedSet"
	"time"
)

func main() {
	conf := conn.Conf{
		NetWork:  "tcp",
		Address:  "localhost:6379",
		User:     "redis_user",
		Password: "redis_password",
	}

	poolConf := conn.PoolConf{
		MaxIdle:     10,
		MaxActive:   100,
		IdleTimeout: time.Hour,
		Conf:        conf,
	}

	// 初始化连接池
	conn.NewPool(poolConf)

	// 从连接池中获取一个连接
	redisConn, err := conn.GetConnFromPool(poolConf)
	if err != nil {
		log.Fatalf("get conn from pool error: %v\n", err)
	}

	// 将该连接返回到连接池中
	defer conn.CloseConnToPool(redisConn)

	// 添加元素到有序集合中
	scoreMap := map[int]interface{}{
		1: "one",
		3: "three",
	}
	addNum, err := sortedSet.ZAdd(redisConn, "myZSet", scoreMap)
	if err != nil {
		log.Fatalf("ZADD error: %v\n", err)
	}
	fmt.Printf("addNum: %d\n", addNum)

	scoreMap = map[int]interface{}{
		3: "three",
		5: "five",
	}
	addNum, err = sortedSet.ZAdd(redisConn, "myZSet", scoreMap)
	if err != nil {
		log.Fatalf("ZADD error: %v\n", err)
	}
	fmt.Printf("addNum: %d\n", addNum)

	// 获取有序集合中的元素数量
	cardNum, err := sortedSet.ZCard(redisConn, "myZSet")
	if err != nil {
		log.Fatalf("ZCARD error: %v\n", err)
	}
	fmt.Printf("cardNum: %d\n", cardNum)

	// 根据分数的索引获取元素
	// 按分数从小到大排序
	members, err := sortedSet.ZRange(redisConn, "myZSet", 0, 1)
	if err != nil {
		log.Fatalf("ZRANGE error: %v\n", err)
	}
	fmt.Printf("ZRANGE members: %v\n", members)
	// 按分数从大到小排序
	members, err = sortedSet.ZRevRange(redisConn, "myZSet", 0, 1)
	if err != nil {
		log.Fatalf("ZREVRANGE error: %v\n", err)
	}
	fmt.Printf("ZREVRANGE members: %v\n", members)

	// 获取指定成员的分数
	score, err := sortedSet.ZScore(redisConn, "myZSet", "three")
	if err != nil {
		log.Fatalf("ZSCORE error: %v\n", err)
	}
	fmt.Printf("ZSCORE score: %.1f\n", score)

	// 删除指定成员
	deletedMembers := []string{"three", "five", "seven"}
	delNum, err := sortedSet.ZRem(redisConn, "myZSet", deletedMembers...)
	if err != nil {
		log.Fatalf("ZREM error: %v\n", err)
	}
	fmt.Printf("ZREM delNum: %d\n", delNum)
}

运行结果:

(base) yanglei@yuanhong redisDataType % go run main.go 
addNum: 2
addNum: 1
cardNum: 3
ZRANGE members: [one three]
ZREVRANGE members: [five three]
ZSCORE score: 3.0
ZREM delNum: 2

8.2.5 操作地理位置数据

Last updated