1.快速入门
1.安装依赖包
1
| go get -u github.com/go-redis/redis
|
2.golang连接redis
1 2 3 4 5 6
| client := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", DB: 0, })
|
3.简单的例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| err := client.Set("key", "value", 0).Err()
if err != nil { panic(err) }
val, err := client.Get("key").Result()
if err != nil { panic(err) } fmt.Println("key", val)
|
2.连接设置
1.golang连接redis
1 2 3 4 5 6
| client := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", DB: 0, })
|
通过例子,我们知道主要通过Options配置redis的连接参数,下面对Options参数进行详细说明。
提示:go-redis包自带了连接池,会自动维护redis连接,因此创建一次client即可,不要查询一次redis就关闭client。
2.Options参数详解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| type Options struct { Network string Addr string
OnConnect func(*Conn) error
Password string DB int
MaxRetries int MinRetryBackoff time.Duration MaxRetryBackoff time.Duration
DialTimeout time.Duration ReadTimeout time.Duration WriteTimeout time.Duration
PoolSize int MinIdleConns int MaxConnAge time.Duration PoolTimeout time.Duration IdleTimeout time.Duration IdleCheckFrequency time.Duration
readOnly bool }
|
3.基本键值操作
redis基本的key/value操作,指的是针对value值的类型为字符串或者数字类型的读写操作。
golang redis常用函数列表:
- Set - 设置一个key的值
- Get - 查询key的值
- GetSet - 设置一个key的值,并返回这个key的旧值
- SetNX - 如果key不存在,则设置这个key的值
- MGet - 批量查询key的值
- MSet - 批量设置key的值
- Incr,IncrBy,IncrByFloat - 针对一个key的数值进行递增操作
- Decr,DecrBy - 针对一个key的数值进行递减操作
- Del - 删除key操作,可以批量删除
- Expire - 设置key的过期时间
1.Set
1 2 3 4 5
| err := client.Set("key","value",0).Err() if err != nil{ panic(err) }
|
2.Get
查询key的值
1 2 3 4 5 6 7
| val, err := client.Get("key").Result()
if err != nil { panic(err) } fmt.Println("key", val)
|
3.GetSet
1 2 3 4 5 6 7 8
| oldVal, err := client.GetSet("key", "new value").Result()
if err != nil { panic(err) }
fmt.Println("key", oldVal)
|
4.SetNX
如果key不存在,则设置这个key的值
1 2 3 4 5
| err := client.SetNX("key", "value", 0).Err() if err != nil { panic(err) }
|
5.MGet
批量查询key的值
1 2 3 4 5 6 7
|
vals, err := client.MGet("key1", "key2", "key3").Result() if err != nil { panic(err) } fmt.Println(vals)
|
6.MSet
批量设置key的值
1 2 3 4
| err := client.MSet("key1", "value1", "key2", "value2", "key3", "value3").Err() if err != nil { panic(err) }
|
7.Incr
、IncrBy
、IncrByFloat
针对一个key的值进行递增操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| val, err := client.Incr("key").Result() if err != nil { panic(err) } fmt.Println("最新值", val)
val, err := client.IncrBy("key", 2).Result() if err != nil { panic(err) } fmt.Println("最新值", val)
val, err := client.IncrByFloat("key", 2).Result() if err != nil { panic(err) } fmt.Println("最新值", val)
|
8.Decr
、DecrBy
针对一个key的值进行递减操作
1 2 3 4 5 6 7 8 9 10 11 12 13
| val, err := client.Decr("key").Result() if err != nil { panic(err) } fmt.Println("最新值", val)
val, err := client.DecrBy("key", 2).Result() if err != nil { panic(err) } fmt.Println("最新值", val)
|
9.Del
删除key操作,支持批量删除
1 2 3 4 5 6 7 8
| / 删除key client.Del("key")
err := client.Del("key1", "key2", "key3").Err() if err != nil { panic(err) }
|
10.Expire
设置key的过期时间,单位为秒
4.hash用法
golang redis hash类型数据操作。
如果你希望key/value的值也能作为hash结构进行操作,可以选择redis hash类型。
使用场景举例:
如果我们希望缓存一条用户信息(包括用户id、用户名、email字段),希望能够做到局部读写用户信息(例如:读写用户名),也能够读取整条用户信息,那么hash类型就支持这些操作。
redis hash操作主要有2-3个元素组成:
- key - redis key 唯一标识
- field - hash数据的字段名
- value - 值,有些操作不需要值
go redis hash数据常用函数:
- HSet - 根据key和field字段设置,field字段的值
- HGet - 根据key和field字段,查询field字段的值
- HGetAll - 根据key查询所有字段和值
- HIncrBy - 根据key和field字段,累加数值。
- HKeys - 根据key返回所有字段名
- HLen - 根据key,查询hash的字段数量
- HMGet - 根据key和多个字段名,批量查询多个hash字段值
- HMSet - 根据key和多个字段名和字段值,批量设置hash字段值
- HSetNX - 如果field字段不存在,则设置hash字段值
- HDel - 根据key和字段名,删除hash字段,支持批量删除hash字段
- HExists - 检测hash字段名是否存在。
提示:不管我们选择redis什么类型的数据,操作的时候都必须要有一个==唯一的Key, 用来唯一标识一个数据。==
1.HSet
根据key和field字段设置,field字段的值
1 2 3 4 5
| err := client.HSet("user_1", "username", "tizi365").Err() if err != nil { panic(err) }
|
2.HGet
根据key
和field
字段,查询field
字段的值
1 2 3 4 5 6
| username, err := client.HGet("user_1", "username").Result() if err != nil { panic(err) } fmt.Println(username)
|
3.HGetAll
根据key
查询所有字段和值
1 2 3 4 5 6 7 8 9 10
| data, err := client.HGetAll("user_1").Result() if err != nil { panic(err) }
for field, val := range data { fmt.Println(field,val) }
|
4.HIncrBy
根据key和field字段,累加字段的数值
1 2 3 4 5 6 7
| count, err := client.HIncrBy("user_1", "count", 2).Result() if err != nil { panic(err) }
fmt.Println(count)
|
5.HKeys
根据Key
返回所有字段名
1 2 3 4 5 6 7
| keys, err := client.HKeys("user_1").Result() if err != nil { panic(err) }
fmt.Println(keys)
|
6.HLen
根据key,查询hash的字段数量
1 2 3 4 5 6
| size, err := client.HLen("key").Result() if err != nil { panic(err) }
fmt.Println(size)
|
7.HMGet
根据key和多个字段名,批量查询多个hash字段值
1 2 3 4 5 6
| size, err := client.HLen("key").Result() if err != nil { panic(err) }
fmt.Println(size)
|
8.HMSet
根据key和多个字段名和字段值,批量设置hash字段值
1 2 3 4 5 6 7 8 9 10
| data := make(map[string]interface{}) data["id"] = 1 data["username"] = "tizi"
err := client.HMSet("key", data).Err() if err != nil { panic(err) }
|
9.HSetNX
如果hash不存在,则设置hash字段值
1 2 3 4
| err := client.HSetNX("key", "id", 100).Err() if err != nil { panic(err) }
|
10.HDel
根据key和字段名,删除hash字段,支持批量删除hash字段
1 2 3 4 5
| client.HDel("key", "id")
client.HDel("key", "id", "username")
|
11.HExists
检查hash字段名是否存在
1 2 3 4 5
| err := client.HExists("key", "id").Err() if err != nil { panic(err) }
|
5.List用法
Redis列表是简单的字符串列表,列表是有序的,列表中的元素可以重复。
可以添加一个元素到列表的头部(左边)或者尾部(右边)
golang redis list数据操作常用函数:
- LPush - 从列表左边插入数据
- LPushX - 跟LPush的区别是,仅当列表存在的时候才插入数据
- RPop - 从列表的右边删除第一个数据,并返回删除的数据
- RPush - 从列表右边插入数据
- RPushX - 跟RPush的区别是,仅当列表存在的时候才插入数据
- LPop - 从列表左边删除第一个数据,并返回删除的数据
- LLen - 返回列表的大小
- LRange - 返回列表的一个范围内的数据,也可以返回全部数据
- LRem - 删除列表中的数据
- LIndex - 根据索引坐标,查询列表中的数据
- LInsert - 在指定位置插入数据
1.LPush
从列表左边插入数据
1 2 3 4 5 6 7 8
| client.LPush("key", "data1")
err := client.LPush("key", 1,2,3,4,5).Err() if err != nil { panic(err) }
|
2.LPushX
跟LPush的区别是,仅当列表存在的时候才插入数据,用法完全一样。
3.RPop
从列表的右边删除第一个数据,并返回删除的数据
1 2 3 4 5 6
| val, err := client.RPop("key").Result() if err != nil { panic(err) }
fmt.Println(val)
|
4.RPush
从列表右边插入数据
1 2 3 4 5 6 7 8
| client.RPush("key", "data1")
err := client.RPush("key", 1,2,3,4,5).Err() if err != nil { panic(err) }
|
5.RPushX
跟RPush的区别是,仅当列表存在的时候才插入数据, 他们用法一样
6.LPop
从列表左边删除第一个数据,并返回删除的数据
1 2 3 4 5 6
| val, err := client.LPop("key").Result() if err != nil { panic(err) }
fmt.Println(val)
|
7.LLen
返回列表的大小
1 2 3 4 5 6
| val, err := client.LLen("key").Result() if err != nil { panic(err) }
fmt.Println(val)
|
8.LRange
返回列表的一个范围内的数据,也可以返回全部数据
1 2 3 4 5 6
| vals, err := client.LRange("key",0,-1).Result() if err != nil { panic(err) } fmt.Println(vals)
|
9.LRem
删除列表中的数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| dels, err := client.LRem("key",1,100).Result() if err != nil { panic(err) }
client.LRem("key",2,100)
client.LRem("key",-2,100)
client.LRem("key",0,100)
|
10.LIndex
根据索引坐标,查询列表中的数据
1 2 3 4 5 6 7
| val, err := client.LIndex("key",5).Result() if err != nil { panic(err) }
fmt.Println(val)
|
11.LInsert
在指定位置插入数据
1 2 3 4 5 6 7 8 9 10 11 12
|
err := client.LInsert("key","before", 5, 4).Err() if err != nil { panic(err) }
client.LInsert("key","before", "tizi365", "欢迎你")
client.LInsert("key","after", "tizi365", "2019")
|
6.集合
redis的set类型(集合)是string类型数值的无序集合,并且集合元素唯一。
下面介绍go redis的集合用法。
go redis 集合(set)常用函数列表:
- SAdd - 添加集合元素
- SCard - 获取集合元素个数
- SIsMember - 判断元素是否在集合中
- SMembers - 获取集合中所有的元素
- SRem - 删除集合元素
- SPop,SPopN - 随机返回集合中的元素,并且删除返回的元素
1.SAdd
添加集合元素
1 2 3 4 5 6 7 8
| err := client.SAdd("key",100).Err() if err != nil { panic(err) }
client.SAdd("key",100, 200, 300)
|
2.SCard
获取集合元素个数
1 2 3 4 5
| size, err := client.SCard("key").Result() if err != nil { panic(err) } fmt.Println(size)
|
3.SIsMember
判断元素是否在集合中
1 2 3 4 5
| ok, _ := client.SIsMember("key", 100).Result() if ok { fmt.Println("集合包含指定元素") }
|
4.SMembers
获取集合中所有的元素
1 2 3
| es, _ := client.SMembers("key").Result()
fmt.Println(es)
|
5.SRem
删除集合元素
1 2 3 4 5
| client.SRem("key", 100)
client.SRem("key", "tizi", "2019")
|
6.SPop,SPopN
随机返回集合中的元素,并且删除返回的元素
1 2 3 4 5 6 7
| val, _ := client.SPop("key").Result() fmt.Println(val)
vals, _ := client.SPopN("key", 5).Result() fmt.Println(vals)
|
7.有序集合
Redis 有序集合(sorted set)和集合一样也是string类型元素的集合,且不允许重复的成员,不同的是每个元素都会关联一个double类型的分数,这个分数主要用于集合元素排序。
下面介绍golang redis 有序集合的用法
go redis有序集合常用函数:
- ZAdd - 添加一个或者多个元素到集合,如果元素已经存在则更新分数
- ZCard - 返回集合元素个数
- ZCount - 统计某个分数范围内的元素个数
- ZIncrBy - 增加元素的分数
- ZRange,ZRevRange - 返回集合中某个索引范围的元素,根据分数从小到大排序
- ZRangeByScore,ZRevRangeByScore - 根据分数范围返回集合元素,元素根据分数从小到大排序,支持分页。
- ZRem - 删除集合元素
- ZRemRangeByRank - 根据索引范围删除元素
- ZRemRangeByScore - 根据分数范围删除元素
- ZScore - 查询元素对应的分数
- ZRank, ZRevRank - 查询元素的排名
1.ZAdd
添加一个或者多个元素到集合,如果元素已经存在则更新分数
1 2 3 4 5
| err := client.ZAdd("key", redis.Z{2.5,"tizi"}).Err() if err != nil { panic(err) }
|
下面是redis.Z结构体说明:
1 2 3 4
| type Z struct { Score float64 Member interface{} }
|
2.ZCard
返回集合元素个数
1 2 3 4 5
| size, err := client.ZCard("key").Result() if err != nil { panic(err) } fmt.Println(size)
|
3.ZCount
统计某个分数范围内的元素个数
1 2 3 4 5 6 7 8 9 10 11
| size, err := client.ZCount("key", "1","5").Result() if err != nil { panic(err) } fmt.Println(size)
size, err := client.ZCount("key", "(1","5").Result()
|
4.ZIncrBy
增加元素的分数
1 2
| client.ZIncrBy("key", 2,"5")
|
5.ZRange,ZRevRange
返回集合中某个索引范围的元素,根据分数从小到大排序
1 2 3 4 5 6 7 8 9 10
|
vals, err := client.ZRange("key", 0,-1).Result() if err != nil { panic(err) }
for _, val := range vals { fmt.Println(val) }
|
ZRevRange用法跟ZRange一样,区别是ZRevRange的结果是按分数从大到小排序。
6.ZRangeByScore
根据分数范围返回集合元素,元素根据分数从小到大排序,支持分页。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| op := redis.ZRangeBy{ Min:"2", Max:"10", Offset:0, Count:5, } vals, err := client.ZRangeByScore("key", op).Result() if err != nil { panic(err) }
for _, val := range vals { fmt.Println(val) }
|
7.ZRevRangeByScore
用法类似ZRangeByScore,区别是元素根据分数从大到小排序。
8.ZRangeByScoreWithScores
用法跟ZRangeByScore一样,区别是除了返回集合元素,同时也返回元素对应的分数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| op := redis.ZRangeBy{ Min:"2", Max:"10", Offset:0, Count:5, }
vals, err := client.ZRangeByScoreWithScores("key", op).Result() if err != nil { panic(err) }
for _, val := range vals { fmt.Println(val.Member) fmt.Println(val.Score) }
|
8.ZRem
删除集合元素
1 2 3 4 5 6
| client.ZRem("key", "tizi")
client.ZRem("key", "tizi", "xiaoli")
|
9.ZRemRangeByRank
根据索引范围删除元素
1 2 3 4 5 6 7
|
client.ZRemRangeByRank("key", 0, 5)
client.ZRemRangeByRank("key", -1, -2)
|
10.ZRemRangeByScore
根据分数范围删除元素
1 2 3 4 5
| client.ZRemRangeByScore("key", "2", "5")
client.ZRemRangeByScore("key", "2", "(5")
|
11.ZScore
查询元素对应的分数
1 2 3
| score, _ := client.ZScore("key", "tizi").Result() fmt.Println(score)
|
12.ZRank
根据元素名,查询集合元素在集合中的排名,从0开始算,集合元素按分数从小到大排序
1 2
| rk, _ := client.ZRank("key", "tizi").Result() fmt.Println(rk)
|
ZRevRank的作用跟ZRank一样,区别是ZRevRank是按分数从大到小排序。
7.发布订阅
Redis提供了发布订阅功能,可以用于消息的传输,Redis的发布订阅机制包括三个部分,发布者,订阅者和Channel。
发布订阅架构图:
发布者和订阅者都是Redis客户端,Channel则为Redis服务器端,发布者将消息发送到某个的频道,订阅了这个频道的订阅者就能接收到这条消息。Redis的这种发布订阅机制与基于主题的发布订阅类似,Channel相当于主题。
下面介绍golang如何使用redis的发布订阅功能。
go redis发布订阅常用函数:
- Subscribe - 订阅channel
- PSubscribe - 订阅channel支持通配符匹配
- Publish - 将信息发送到指定的channel。
- PubSubChannels - 查询活跃的channel
- PubSubNumSub - 查询指定的channel有多少个订阅者
1.Subscribe
订阅channel
例子1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| sub := client.Subscribe("channel1")
iface, err := sub.Receive() if err != nil { }
switch iface.(type) { case *redis.Subscription: case *redis.Message: m := iface.(redis.Message) fmt.Println(m.Payload) case *redis.Pong: default: }
|
例子2:
使用golang channel的方式处理消息
1 2 3 4 5 6 7 8 9
| sub := client.Subscribe("channel1")
for msg := range sub.Channel() { fmt.Println(msg.Channel) fmt.Println(msg.Payload) }
|
例子3:
取消订阅
1 2 3 4 5 6 7
| sub := client.Subscribe("channel1")
sub.Unsubscribe("channel1")
|
2.PSubscribe
用法跟Subscribe一样,区别是PSubscribe订阅通道(channel)支持模式匹配。
例子:
1 2 3
| sub := client.PSubscribe("ch_user_*")
|
3.Publish
将消息发送到指定的channel
1 2
| client.Publish("channel1","message")
|
4.PubSubChannels
查询活跃的channel
1 2 3 4 5 6 7 8
| chs, _ := client.PubSubChannels("").Result() for _, ch := range chs { fmt.Println(ch) }
chs, _ := client.PubSubChannels("user_*").Result()
|
5.PubSubNumSub
查询指定的channel有多少个订阅者
1 2 3 4 5 6
| chs, _ := client.PubSubNumSub("channel1", "channel2").Result() for ch, count := range chs { fmt.Println(ch) fmt.Println(count) }
|
redis事务可以一次执行多个命令, 并且带有以下两个重要的保证:
- 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
- 事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。
8.事务
下面介绍golang redis事务用法。
go redis事务常用函数:
- TxPipeline - 以Pipeline的方式操作事务
- Watch - redis乐观锁支持
1.TxPipeline
以Pipeline的方式操作事务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| pipe := client.TxPipeline()
incr := pipe.Incr("tx_pipeline_counter") pipe.Expire("tx_pipeline_counter", time.Hour)
_, err := pipe.Exec()
fmt.Println(incr.Val(), err)
|
2.watch
redis乐观锁支持,可以通过watch监听一些Key, 如果这些key的值没有被其他人改变的话,才可以提交事务。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| fn := func(tx *redis.Tx) error { v, err := tx.Get("key").Result() if err != nil && err != redis.Nil { return err }
fmt.Println(v)
_, err = tx.Pipelined(func(pipe redis.Pipeliner) error { pipe.Set("key", "new value", 0) return nil }) return err }
client.Watch(fn, "key")
|