Golang redis快速入门
mhr18 2024-11-25 10:39 20 浏览 0 评论
golang redis快速入门
redis是目前流行的高性能key/value缓存,基本上在各种项目都经常出现,后续教程针对golang如何操作redis进行展开。
本教程是使用的是go-redis/redis包操作redis。 github: https://github.com/go-redis/redis
1.安装依赖包
go get -u github.com/go-redis/redis
2.golang连接redis
// 根据redis配置初始化一个客户端
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 0, // 默认数据库,默认是0
})
3.简单的例子
// 设置一个key,过期时间为0,意思就是永远不过期err := client.Set("key", "value", 0).Err()// 检测设置是否成功if err != nil { panic(err)}// 根据key查询缓存,通过Result函数返回两个值// 第一个代表key的值,第二个代表查询错误信息val, err := client.Get("key").Result()// 检测,查询是否出错if err != nil { panic(err)}fmt.Println("key", val)
golang 如何连接redis
下面介绍golang如何连接redis服务端。
1.golang连接redis
// 初始化一个新的redis client
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379", // redis地址
Password: "", // redis没密码,没有设置,则留空
DB: 0, // 使用默认数据库
})
通过例子,我们知道主要通过Options配置redis的连接参数,下面对Options参数进行详细说明。
提示:go-redis包自带了连接池,会自动维护redis连接,因此创建一次client即可,不要查询一次redis就关闭client。
2.Options参数详解
type Options struct { // 网络类型 tcp 或者 unix. // 默认是 tcp. Network string // redis地址,格式 host:port Addr string // 新建一个redis连接的时候,会回调这个函数 OnConnect func(*Conn) error // redis密码,redis server没有设置可以为空。 Password string // redis数据库,序号从0开始,默认是0,可以不用设置 DB int // redis操作失败最大重试次数,默认不重试。 MaxRetries int // 最小重试时间间隔. // 默认是 8ms ; -1 表示关闭. MinRetryBackoff time.Duration // 最大重试时间间隔 // 默认是 512ms; -1 表示关闭. MaxRetryBackoff time.Duration // redis连接超时时间. // 默认是 5 秒. DialTimeout time.Duration // socket读取超时时间 // 默认 3 秒. ReadTimeout time.Duration // socket写超时时间 WriteTimeout time.Duration // redis连接池的最大连接数. // 默认连接池大小等于 cpu个数 * 10 PoolSize int // redis连接池最小空闲连接数. MinIdleConns int // redis连接最大的存活时间,默认不会关闭过时的连接. MaxConnAge time.Duration // 当你从redis连接池获取一个连接之后,连接池最多等待这个拿出去的连接多长时间。 // 默认是等待 ReadTimeout + 1 秒. PoolTimeout time.Duration // redis连接池多久会关闭一个空闲连接. // 默认是 5 分钟. -1 则表示关闭这个配置项 IdleTimeout time.Duration // 多长时间检测一下,空闲连接 // 默认是 1 分钟. -1 表示关闭空闲连接检测 IdleCheckFrequency time.Duration // 只读设置,如果设置为true, redis只能查询缓存不能更新。 readOnly bool}
golang redis基本键值操作
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
设置一个key的值
// 第三个参数代表key的过期时间,0代表不会过期。
err := client.Set("key", "value", 0).Err()
if err != nil {
panic(err)
}
2.Get
查询key的值
// Result函数返回两个值,第一个是key的值,第二个是错误信息
val, err := client.Get("key").Result()
// 判断查询是否出错
if err != nil {
panic(err)
}
fmt.Println("key", val)
3.GetSet
设置一个key的值,并返回这个key的旧值
// Result函数返回两个值,第一个是key的值,第二个是错误信息oldVal, err := client.GetSet("key", "new value").Result()if err != nil { panic(err)}// 打印key的旧值fmt.Println("key", oldVal)
4.SetNX
如果key不存在,则设置这个key的值
// 第三个参数代表key的过期时间,0代表不会过期。
err := client.SetNX("key", "value", 0).Err()
if err != nil {
panic(err)
}
5.MGet
批量查询key的值
// MGet函数可以传入任意个key,一次性返回多个值。
// 这里Result返回两个值,第一个值是一个数组,第二个值是错误信息
vals, err := client.MGet("key1", "key2", "key3").Result()
if err != nil {
panic(err)
}
fmt.Println(vals)
6.MSet
批量设置key的值
err := client.MSet("key1", "value1", "key2", "value2", "key3", "value3").Err()
if err != nil {
panic(err)
}
7.Incr,IncrBy
针对一个key的数值进行递增操作
// Incr函数每次加一val, err := client.Incr("key").Result()if err != nil { panic(err)}fmt.Println("最新值", val)// IncrBy函数,可以指定每次递增多少val, err := client.IncrBy("key", 2).Result()if err != nil { panic(err)}fmt.Println("最新值", val)// IncrByFloat函数,可以指定每次递增多少,跟IncrBy的区别是累加的是浮点数val, err := client.IncrByFloat("key", 2).Result()if err != nil { panic(err)}fmt.Println("最新值", val)
8.Decr,DecrBy
针对一个key的数值进行递减操作
// Decr函数每次减一val, err := client.Decr("key").Result()if err != nil { panic(err)}fmt.Println("最新值", val)// DecrBy函数,可以指定每次递减多少val, err := client.DecrBy("key", 2).Result()if err != nil { panic(err)}fmt.Println("最新值", val)
9.Del
删除key操作,支持批量删除
// 删除keyclient.Del("key")// 删除多个key, Del函数支持删除多个keyerr := client.Del("key1", "key2", "key3").Err()if err != nil { panic(err)}
10.Expire
设置key的过期时间,单位秒
client.Expire("key", 3)
golang redis 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字段的值
// user_1 是hash key,username 是字段名, tizi365是字段值
err := client.HSet("user_1", "username", "tizi365").Err()
if err != nil {
panic(err)
}
2.HGet
根据key和field字段,查询field字段的值
// user_1 是hash key,username是字段名
username, err := client.HGet("user_1", "username").Result()
if err != nil {
panic(err)
}
fmt.Println(username)
3.HGetAll
根据key查询所有字段和值
// 一次性返回key=user_1的所有hash字段和值data, err := client.HGetAll("user_1").Result()if err != nil { panic(err)}// data是一个map类型,这里使用使用循环迭代输出for field, val := range data { fmt.Println(field,val)}
4.HIncrBy
根据key和field字段,累加字段的数值
// 累加count字段的值,一次性累加2, user_1为hash keycount, err := client.HIncrBy("user_1", "count", 2).Result()if err != nil { panic(err)}fmt.Println(count)
5.HKeys
根据key返回所有字段名
// keys是一个string数组keys, err := client.HKeys("user_1").Result()if err != nil { panic(err)}fmt.Println(keys)
6.HLen
根据key,查询hash的字段数量
size, err := client.HLen("key").Result()if err != nil { panic(err)}fmt.Println(size)
7.HMGet
根据key和多个字段名,批量查询多个hash字段值
// HMGet支持多个field字段名,意思是一次返回多个字段值vals, err := client.HMGet("key","field1", "field2").Result()if err != nil { panic(err)}// vals是一个数组fmt.Println(vals)
8.HMSet
根据key和多个字段名和字段值,批量设置hash字段值
// 初始化hash数据的多个字段值data := make(map[string]interface{})data["id"] = 1data["username"] = "tizi"// 一次性保存多个hash字段值err := client.HMSet("key", data).Err()if err != nil { panic(err)}
9.HSetNX
如果field字段不存在,则设置hash字段值
err := client.HSetNX("key", "id", 100).Err()
if err != nil {
panic(err)
}
10.HDel
根据key和字段名,删除hash字段,支持批量删除hash字段
// 删除一个字段idclient.HDel("key", "id")// 删除多个字段client.HDel("key", "id", "username")
11.HExists
检测hash字段名是否存在。
// 检测id字段是否存在
err := client.HExists("key", "id").Err()
if err != nil {
panic(err)
}
golang redis 列表(list)用法
Redis列表是简单的字符串列表,列表是有序的,列表中的元素可以重复。
可以添加一个元素到列表的头部(左边)或者尾部(右边)
golang redis list数据操作常用函数:
- LPush - 从列表左边插入数据
- LPushX - 跟LPush的区别是,仅当列表存在的时候才插入数据
- RPop - 从列表的右边删除第一个数据,并返回删除的数据
- RPush - 从列表右边插入数据
- RPushX - 跟RPush的区别是,仅当列表存在的时候才插入数据
- LPop - 从列表左边删除第一个数据,并返回删除的数据
- LLen - 返回列表的大小
- LRange - 返回列表的一个范围内的数据,也可以返回全部数据
- LRem - 删除列表中的数据
- LIndex - 根据索引坐标,查询列表中的数据
- LInsert - 在指定位置插入数据
1.LPush
从列表左边插入数据
// 插入一个数据client.LPush("key", "data1")// LPush支持一次插入任意个数据err := client.LPush("key", 1,2,3,4,5).Err()if err != nil { panic(err)}
2.LPushX
跟LPush的区别是,仅当列表存在的时候才插入数据,用法完全一样。
3.RPop
从列表的右边删除第一个数据,并返回删除的数据
val, err := client.RPop("key").Result()if err != nil { panic(err)}fmt.Println(val)
4.RPush
从列表右边插入数据
// 插入一个数据client.RPush("key", "data1")// 支持一次插入任意个数据err := client.RPush("key", 1,2,3,4,5).Err()if err != nil { panic(err)}
5.RPushX
跟RPush的区别是,仅当列表存在的时候才插入数据, 他们用法一样
6.LPop
从列表左边删除第一个数据,并返回删除的数据
val, err := client.LPop("key").Result()if err != nil { panic(err)}fmt.Println(val)
7.LLen
返回列表的大小
val, err := client.LLen("key").Result()if err != nil { panic(err)}fmt.Println(val)
8.LRange
返回列表的一个范围内的数据,也可以返回全部数据
// 返回从0开始到-1位置之间的数据,意思就是返回全部数据
vals, err := client.LRange("key",0,-1).Result()
if err != nil {
panic(err)
}
fmt.Println(vals)
9.LRem
删除列表中的数据
// 从列表左边开始,删除100, 如果出现重复元素,仅删除1次,也就是删除第一个dels, err := client.LRem("key",1,100).Result()if err != nil { panic(err)}// 如果存在多个100,则从列表左边开始删除2个100client.LRem("key",2,100)// 如果存在多个100,则从列表右边开始删除2个100// 第二个参数负数表示从右边开始删除几个等于100的元素client.LRem("key",-2,100)// 如果存在多个100,第二个参数为0,表示删除所有元素等于100的数据client.LRem("key",0,100)
10.LIndex
根据索引坐标,查询列表中的数据
// 列表索引从0开始计算,这里返回第6个元素val, err := client.LIndex("key",5).Result()if err != nil { panic(err)}fmt.Println(val)
11.LInsert
在指定位置插入数据
// 在列表中5的前面插入4// before是之前的意思err := client.LInsert("key","before", 5, 4).Err()if err != nil { panic(err)}// 在列表中 tizi365 元素的前面插入 欢迎你client.LInsert("key","before", "tizi365", "欢迎你")// 在列表中 tizi365 元素的后面插入 2019client.LInsert("key","after", "tizi365", "2019")
golang redis 集合(set)
redis的set类型(集合)是string类型数值的无序集合,并且集合元素唯一。
下面介绍go redis的集合用法。
go redis 集合(set)常用函数列表:
- SAdd - 添加集合元素
- SCard - 获取集合元素个数
- SIsMember - 判断元素是否在集合中
- SMembers - 获取集合中所有的元素
- SRem - 删除集合元素
- SPop,SPopN - 随机返回集合中的元素,并且删除返回的元素
1.SAdd
添加集合元素
// 添加100到集合中err := client.SAdd("key",100).Err()if err != nil { panic(err)}// 将100,200,300添加到集合中client.SAdd("key",100, 200, 300)
2.SCard
获取集合元素个数
size, err := client.SCard("key").Result()
if err != nil {
panic(err)
}
fmt.Println(size)
3.SIsMember
判断元素是否在集合中
// 检测100是否包含在集合中
ok, _ := client.SIsMember("key", 100).Result()
if ok {
fmt.Println("集合包含指定元素")
}
4.SMembers
获取集合中所有的元素
es, _ := client.SMembers("key").Result()
// 返回的es是string数组
fmt.Println(es)
5.SRem
删除集合元素
// 删除集合中的元素100client.SRem("key", 100)// 删除集合中的元素tizi和2019client.SRem("key", "tizi", "2019")
6.SPop,SPopN
随机返回集合中的元素,并且删除返回的元素
// 随机返回集合中的一个元素,并且删除这个元素val, _ := client.SPop("key").Result()fmt.Println(val)// 随机返回集合中的5个元素,并且删除这些元素vals, _ := client.SPopN("key", 5).Result()fmt.Println(vals)
golang redis 有序集合(sorted set)
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
添加一个或者多个元素到集合,如果元素已经存在则更新分数
// 添加一个集合元素到集合中, 这个元素的分数是2.5,元素名是tizi
err := client.ZAdd("key", redis.Z{2.5,"tizi"}).Err()
if err != nil {
panic(err)
}
下面是redis.Z结构体说明:
type Z struct {
Score float64 // 分数
Member interface{} // 元素名
}
2.ZCard
返回集合元素个数
size, err := client.ZCard("key").Result()
if err != nil {
panic(err)
}
fmt.Println(size)
3.ZCount
统计某个分数范围内的元素个数
// 返回: 1<=分数<=5 的元素个数, 注意:"1", "5"两个参数是字符串size, err := client.ZCount("key", "1","5").Result()if err != nil { panic(err)}fmt.Println(size)// 返回: 1<分数<=5 的元素个数// 说明:默认第二,第三个参数是大于等于和小于等于的关系。// 如果加上( 则表示大于或者小于,相当于去掉了等于关系。size, err := client.ZCount("key", "(1","5").Result()
4.ZIncrBy
增加元素的分数
// 给元素5,加上2分
client.ZIncrBy("key", 2,"5")
5.ZRange,ZRevRange
返回集合中某个索引范围的元素,根据分数从小到大排序
// 返回从0到-1位置的集合元素, 元素按分数从小到大排序// 0到-1代表则返回全部数据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
根据分数范围返回集合元素,元素根据分数从小到大排序,支持分页。
// 初始化查询条件, Offset和Count用于分页op := redis.ZRangeBy{ Min:"2", // 最小分数 Max:"10", // 最大分数 Offset:0, // 类似sql的limit, 表示开始偏移量 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一样,区别是除了返回集合元素,同时也返回元素对应的分数
// 初始化查询条件, Offset和Count用于分页op := redis.ZRangeBy{ Min:"2", // 最小分数 Max:"10", // 最大分数 Offset:0, // 类似sql的limit, 表示开始偏移量 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
删除集合元素
// 删除集合中的元素tiziclient.ZRem("key", "tizi")// 删除集合中的元素tizi和xiaoli// 支持一次删除多个元素client.ZRem("key", "tizi", "xiaoli")
9.ZRemRangeByRank
根据索引范围删除元素
// 集合元素按分数排序,从最低分到高分,删除第0个元素到第5个元素。// 这里相当于删除最低分的几个元素client.ZRemRangeByRank("key", 0, 5)// 位置参数写成负数,代表从高分开始删除。// 这个例子,删除最高分数的两个元素,-1代表最高分数的位置,-2第二高分,以此类推。client.ZRemRangeByRank("key", -1, -2)
10.ZRemRangeByScore
根据分数范围删除元素
// 删除范围: 2<=分数<=5 的元素client.ZRemRangeByScore("key", "2", "5")// 删除范围: 2<=分数<5 的元素client.ZRemRangeByScore("key", "2", "(5")
11.ZScore
查询元素对应的分数
// 查询集合元素tizi的分数
score, _ := client.ZScore("key", "tizi").Result()
fmt.Println(score)
12.ZRank
根据元素名,查询集合元素在集合中的排名,从0开始算,集合元素按分数从小到大排序
rk, _ := client.ZRank("key", "tizi").Result()
fmt.Println(rk)
ZRevRank的作用跟ZRank一样,区别是ZRevRank是按分数从大到小排序。
golang redis发布订阅
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:
// 订阅channel1这个channelsub := client.Subscribe("channel1")// 读取channel消息iface, err := sub.Receive()if err != nil { // handle error}// 检测收到的消息类型switch iface.(type) {case *redis.Subscription: // 订阅成功case *redis.Message: // 处理收到的消息 // 这里需要做一下类型转换 m := iface.(redis.Message) // 打印收到的小 fmt.Println(m.Payload)case *redis.Pong: // 收到Pong消息default: // handle error}
例子2: 使用golang channel的方式处理消息
// 订阅channel1这个channelsub := client.Subscribe("channel1")// sub.Channel() 返回go channel,可以循环读取redis服务器发过来的消息for msg := range sub.Channel() { // 打印收到的消息 fmt.Println(msg.Channel) fmt.Println(msg.Payload)}
例子3: 取消订阅
// 订阅channel1这个channelsub := client.Subscribe("channel1")// 忽略其他处理逻辑 // 取消订阅sub.Unsubscribe("channel1")
2.PSubscribe
用法跟Subscribe一样,区别是PSubscribe订阅通道(channel)支持模式匹配。
例子:
// 订阅channel1这个channel
sub := client.PSubscribe("ch_user_*")
// 可以匹配ch_user_开头的任意channel
3.Publish
将消息发送到指定的channel
// 将"message"消息发送到channel1这个通道上
client.Publish("channel1","message")
4.PubSubChannels
查询活跃的channel
// 没有指定查询channel的匹配模式,则返回所有的channelchs, _ := client.PubSubChannels("").Result()for _, ch := range chs { fmt.Println(ch)}// 匹配user_开头的channelchs, _ := client.PubSubChannels("user_*").Result()
5.PubSubNumSub
查询指定的channel有多少个订阅者
// 查询channel1,channel2两个通道的订阅者数量
chs, _ := client.PubSubNumSub("channel1", "channel2").Result()
for ch, count := range chs {
fmt.Println(ch) // channel名字
fmt.Println(count) // channel的订阅者数量
}
golang redis事务
redis事务可以一次执行多个命令, 并且带有以下两个重要的保证:
- 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
- 事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。
下面介绍golang redis事务用法。
go redis事务常用函数:
- TxPipeline - 以Pipeline的方式操作事务
- Watch - redis乐观锁支持
1.TxPipeline
以Pipeline的方式操作事务
// 开启一个TxPipeline事务pipe := client.TxPipeline()// 执行事务操作,可以通过pipe读写redisincr := pipe.Incr("tx_pipeline_counter")pipe.Expire("tx_pipeline_counter", time.Hour)// 上面代码等同于执行下面redis命令//// MULTI// INCR pipeline_counter// EXPIRE pipeline_counts 3600// EXEC// 通过Exec函数提交redis事务_, err := pipe.Exec()// 提交事务后,我们可以查询事务操作的结果// 前面执行Incr函数,在没有执行exec函数之前,实际上还没开始运行。fmt.Println(incr.Val(), err)
2.watch
redis乐观锁支持,可以通过watch监听一些Key, 如果这些key的值没有被其他人改变的话,才可以提交事务。
// 定义一个回调函数,用于处理事务逻辑
fn := func(tx *redis.Tx) error {
// 先查询下当前watch监听的key的值
v, err := tx.Get("key").Result()
if err != nil && err != redis.Nil {
return err
}
// 这里可以处理业务
fmt.Println(v)
// 如果key的值没有改变的话,Pipelined函数才会调用成功
_, err = tx.Pipelined(func(pipe redis.Pipeliner) error {
// 在这里给key设置最新值
pipe.Set("key", "new value", 0)
return nil
})
return err
}
// 使用Watch监听一些Key, 同时绑定一个回调函数fn, 监听Key后的逻辑写在fn这个回调函数里面
// 如果想监听多个key,可以这么写:client.Watch(fn, "key1", "key2", "key3")
client.Watch(fn, "key")
- 上一篇:必须知道的 17 个Go开发库
- 下一篇:go-websocket 分布式IM
相关推荐
- 【推荐】一个开源免费、AI 驱动的智能数据管理系统,支持多数据库
-
如果您对源码&技术感兴趣,请点赞+收藏+转发+关注,大家的支持是我分享最大的动力!!!.前言在当今数据驱动的时代,高效、智能地管理数据已成为企业和个人不可或缺的能力。为了满足这一需求,我们推出了这款开...
- Pure Storage推出统一数据管理云平台及新闪存阵列
-
PureStorage公司今日推出企业数据云(EnterpriseDataCloud),称其为组织在混合环境中存储、管理和使用数据方式的全面架构升级。该公司表示,EDC使组织能够在本地、云端和混...
- 对Java学习的10条建议(对java课程的建议)
-
不少Java的初学者一开始都是信心满满准备迎接挑战,但是经过一段时间的学习之后,多少都会碰到各种挫败,以下北风网就总结一些对于初学者非常有用的建议,希望能够给他们解决现实中的问题。Java编程的准备:...
- SQLShift 重大更新:Oracle→PostgreSQL 存储过程转换功能上线!
-
官网:https://sqlshift.cn/6月,SQLShift迎来重大版本更新!作为国内首个支持Oracle->OceanBase存储过程智能转换的工具,SQLShift在过去一...
- JDK21有没有什么稳定、简单又强势的特性?
-
佳未阿里云开发者2025年03月05日08:30浙江阿里妹导读这篇文章主要介绍了Java虚拟线程的发展及其在AJDK中的实现和优化。阅前声明:本文介绍的内容基于AJDK21.0.5[1]以及以上...
- 「松勤软件测试」网站总出现404 bug?总结8个原因,不信解决不了
-
在进行网站测试的时候,有没有碰到过网站崩溃,打不开,出现404错误等各种现象,如果你碰到了,那么恭喜你,你的网站出问题了,是什么原因导致网站出问题呢,根据松勤软件测试的总结如下:01数据库中的表空间不...
- Java面试题及答案最全总结(2025版)
-
大家好,我是Java面试陪考员最近很多小伙伴在忙着找工作,给大家整理了一份非常全面的Java面试题及答案。涉及的内容非常全面,包含:Spring、MySQL、JVM、Redis、Linux、Sprin...
- 数据库日常运维工作内容(数据库日常运维 工作内容)
-
#数据库日常运维工作包括哪些内容?#数据库日常运维工作是一个涵盖多个层面的综合性任务,以下是详细的分类和内容说明:一、数据库运维核心工作监控与告警性能监控:实时监控CPU、内存、I/O、连接数、锁等待...
- 分布式之系统底层原理(上)(底层分布式技术)
-
作者:allanpan,腾讯IEG高级后台工程师导言分布式事务是分布式系统必不可少的组成部分,基本上只要实现一个分布式系统就逃不开对分布式事务的支持。本文从分布式事务这个概念切入,尝试对分布式事务...
- oracle 死锁了怎么办?kill 进程 直接上干货
-
1、查看死锁是否存在selectusername,lockwait,status,machine,programfromv$sessionwheresidin(selectsession...
- SpringBoot 各种分页查询方式详解(全网最全)
-
一、分页查询基础概念与原理1.1什么是分页查询分页查询是指将大量数据分割成多个小块(页)进行展示的技术,它是现代Web应用中必不可少的功能。想象一下你去图书馆找书,如果所有书都堆在一张桌子上,你很难...
- 《战场兄弟》全事件攻略 一般事件合同事件红装及隐藏职业攻略
-
《战场兄弟》全事件攻略,一般事件合同事件红装及隐藏职业攻略。《战场兄弟》事件奖励,事件条件。《战场兄弟》是OverhypeStudios制作发行的一款由xcom和桌游为灵感来源,以中世纪、低魔奇幻为...
- LoadRunner(loadrunner录制不到脚本)
-
一、核心组件与工作流程LoadRunner性能测试工具-并发测试-正版软件下载-使用教程-价格-官方代理商的架构围绕三大核心组件构建,形成完整测试闭环:VirtualUserGenerator(...
- Redis数据类型介绍(redis 数据类型)
-
介绍Redis支持五种数据类型:String(字符串),Hash(哈希),List(列表),Set(集合)及Zset(sortedset:有序集合)。1、字符串类型概述1.1、数据类型Redis支持...
- RMAN备份监控及优化总结(rman备份原理)
-
今天主要介绍一下如何对RMAN备份监控及优化,这里就不讲rman备份的一些原理了,仅供参考。一、监控RMAN备份1、确定备份源与备份设备的最大速度从磁盘读的速度和磁带写的带度、备份的速度不可能超出这两...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- oracle位图索引 (63)
- oracle批量插入数据 (62)
- oracle事务隔离级别 (53)
- oracle 空为0 (50)
- oracle主从同步 (55)
- oracle 乐观锁 (51)
- redis 命令 (78)
- php redis (88)
- redis 存储 (66)
- redis 锁 (69)
- 启动 redis (66)
- redis 时间 (56)
- redis 删除 (67)
- redis内存 (57)
- redis并发 (52)
- redis 主从 (69)
- redis 订阅 (51)
- redis 登录 (54)
- redis 面试 (58)
- 阿里 redis (59)
- redis 搭建 (53)
- redis的缓存 (55)
- lua redis (58)
- redis 连接池 (61)
- redis 限流 (51)