排行榜功能是一个很普遍的需求,对于这类需求如果数据总量过大用mysql实现的话会很浪费性能。
select * from rank_name order by score desc limit 0,10
这时候可以考虑使用redis中的有序集合来实现(以下是会用到的一些命令)
- zrange 查看排行榜 (升序)
- zrevrange 查看排行榜 (降序)
- zadd 添加一个数据
- zrem 删除一个数据
- zrank 获取排名(升序)
- zrevrank 获取排名 (降序)
以下是golang代码实现
c1,err := redis.Dial("tcp","127.0.0.1:6379")
if err != nil {
panic(err)
}
defer c1.Close()
_, err = c1.Do("zrange","rank_name","0","-1","withscores")
if err != nil {
return
}
for i := 0; i <100; i++ {
c1.Do("zadd","rank_name",rand.Intn(1000),"张"+strconv.Itoa(i))
}
do, err := redis.ByteSlices(c1.Do("zrange", "rank_name", 0, -1,"withscores"))
if err != nil {
return
}
for _, v := range do {
fmt.Println(string(v))
}
其他例子,普通方式:使用参数
这种方式(method(conn, …))需要将其写在参数中,比较繁琐,也不便于找到其相关的方法,于是我们对其进行了结构体封装,请略过以下代码!
package main
import (
"fmt"
"github.com/garyburd/redigo/redis"
)
func main() {
conn := redisConnect()
defer conn.Close()
setString(conn, "country", "China")
getString(conn, "country")
}
// connect redis
func redisConnect() redis.Conn {
conn, err := redis.Dial("tcp", "127.0.0.1:6379")
if err != nil {
fmt.Println("connect redis error:", err)
return nil
}
fmt.Println("connect redis success!")
return conn
}
// setString SET filed value
func setString(conn redis.Conn, field string, value interface{}) {
_, _ = conn.Do("SET", field, value)
}
// getString GET field
func getString(conn redis.Conn, field string) {
res, _ := redis.String(conn.Do("GET", field))
fmt.Printf("Get %s: %s \n", field, res)
}
使用结构体封装进行方法调用
使用这种方式(db.method(…))进行封装,不仅便于书写,而且也更容易找到相关的方法来调用
package main
import (
"fmt"
"github.com/garyburd/redigo/redis"
"log"
"reflect"
)
func main() {
conn := RedisConnect()
defer conn.Close()
// 认证信息
// if _, err := conn.Do("username", "password"); err != nil {
// conn.Close()
// }
db := Conn{conn}
// 删:key键
// db.DelKey("score")
// 删:单条数据
// db.DelSortSetByField("score", "Tom")
// 增
db.SetSortSet("score", 96, "Coulson")
db.SetSortSet("score", 92, "Tom")
db.SetSortSet("score", 97, "Jack")
// 查:长度
fmt.Println(db.GetSortSetLength("score"))
// 查:排名(asc: 升序, desc: 降序, int: 降序前n条数据)
nameRank, scoreRank := db.RankSortSet("score", "asc")
fmt.Println(nameRank, scoreRank)
// 查:单条数据
fmt.Println(db.GetSortSetByField("score", "Tom"))
}
// RedisConnect connect redis
func RedisConnect() redis.Conn {
conn, err := redis.Dial("tcp", "127.0.0.1:6379")
if err != nil {
fmt.Println("connect redis error:", err)
return nil
}
fmt.Println("connect redis success!")
return conn
}
type Conn struct {
redis.Conn
}
func (conn *Conn) DelKey(key string) {
_, err := conn.Do("DEL", key)
if err != nil {
log.Printf("Failed to del the key: %s \n", key)
}
fmt.Printf("success to del the key: %s! \n", key)
}
// SetSortSet ZADD key ...
func (conn *Conn) SetSortSet(key string, value int, field string) {
_, err := conn.Do("ZADD", key, value, field)
if err != nil {
// error: WRONGTYPE Operation against a key holding the wrong kind of value
log.Printf("Already exist duplicate keys: `%s` \n", key)
panic(err)
}
log.Printf("success to set key: %s %d %s", key, value, field)
}
// GetSortSetLength ZCARD key
func (conn *Conn) GetSortSetLength(key string) interface{} {
res, err := conn.Do("ZCARD", key)
if err != nil {
panic(err)
}
return res
}
// RankSortSet sort
func (conn *Conn) RankSortSet(key string, limit interface{}) (nameArr []string, valueArr []string) {
// ZRANGE score 0 -1 WITHSCORES # 递增排列
// ZRANGE salary 0 <n> WITHSCORES # [0, n)
// fmt.Println(reflect.TypeOf(limit).Name())
cmd, index := "ZREVRANGE", -1
switch {
case limit == "asc":
cmd = "ZRANGE"
index = -1
case limit == "desc":
cmd = "ZREVRANGE"
index = -1
case reflect.TypeOf(limit).Name() == "int" && int(reflect.ValueOf(limit).Int()) > 0:
index = int(reflect.ValueOf(limit).Int()) - 1
default:
cmd = "ZREVRANGE"
index = -1
}
// scoreMap, err := redis.StringMap(conn.Do("ZRANGE", "score", 0, -1, "withscores"))
scoreMap, err := redis.StringMap(conn.Do(cmd, "score", 0, index, "withscores"))
if err != nil {
log.Printf("Failed to rank by key %s \n", key)
}
// sort
for name := range scoreMap {
nameArr = append(nameArr, name)
valueArr = append(valueArr, scoreMap[name])
}
return nameArr, valueArr
}
// GetSortSetByField 获取单个数据
func (conn *Conn) GetSortSetByField(field string, value interface{}) interface{} {
res, err := redis.Int(conn.Do("ZSCORE", field, value))
if err != nil {
log.Printf("can't find %v of %v \n", field, value)
}
return res
}
// DelSortSetByField 删除单条数据
func (conn *Conn) DelSortSetByField(field string, value interface{}) interface{} {
res, err := conn.Do("ZREM", field, value)
if err != nil {
log.Printf("failed to del %v by %v \n", field, value)
}
return res
}