Redis排行榜思想

目錄

  1. 排行榜的背景
  2. 排行榜數據庫設計
  3. 排行榜代碼簡易實現

排行榜的背景

排行榜功能是一個很普遍的需求。使用 Redis 中有序集合(zset)的特性來實現排行榜是又好又快的選擇。一般排行榜都是有實效性的,比如“用戶積分榜”,遊戲中活躍度排行榜,遊戲裝備排行榜等。

排行榜數據庫設計

面臨的問題:

數據庫設計複雜,併發數較高,數據要求實時性高

簡單談一下設計數據庫的注意點:

1、表設計過程中應該注意的點即數據類型
1)字節更小的通常更好
控制字節長度

2)使用合適的數據類型
如tinyint只佔8個位,char(1024)與varchar(1024)的對比,char用於類似定長數據存儲比varchar節省空間,如:uuid(32),可以用char(32).

3)儘量避免NULL建議使用NOT NULL DEFAULT ‘’
NULL的列會讓索引統計和值比較都更復雜。可爲NULL的列會佔據更多的磁盤空間,在Mysql中也需要更多複雜的處理程序

2、索引設計過程中應該注意的點

1)選擇唯一性索引
唯一性索引的值是唯一的,可以更快速的通過該索引來確定某條記錄,保證物理上面唯一

2)爲經常需要排序、分組和聯合操作的字段建立索引
經常需要ORDER BY、GROUP BY、DISTINCT和UNION等操作的字段,排序操作會浪費很多時間

3)常作爲查詢條件的字段建立索引
如果某個字段經常用來做查詢條件,那麼該字段的查詢速度會影響整個表的查詢速度

4)數據少的地方不必建立索引**

本文設計簡易三張表:

數據庫表
score_flow(積分流水錶)
user_score(用戶積分表總表)
sys_user(用戶信息表)設計,用於實現兩個功能:

1)查top100
2)查用戶的排名

排行榜代碼簡易實現

本文環境搭建參考與Springboot與Redis Cache深度整合
工程結構:
在這裏插入圖片描述

1.sql腳本

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for `score_flow`
-- ----------------------------
#積分流水錶
DROP TABLE IF EXISTS `score_flow`;
CREATE TABLE `score_flow` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `score` bigint(11) DEFAULT NULL,
  `user_id` int(11) DEFAULT NULL,
  `user_name` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;


-- ----------------------------
-- Table structure for `sys_user`
-- ----------------------------
#用戶表
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_name` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES ('1', '高晨曦');
INSERT INTO `sys_user` VALUES ('2', '瑞燊兒');
INSERT INTO `sys_user` VALUES ('3', '張飛');
INSERT INTO `sys_user` VALUES ('4', '馬超');
INSERT INTO `sys_user` VALUES ('5', '關羽');

-- ----------------------------
-- Table structure for `user_score`
-- ----------------------------
#用戶得分表
DROP TABLE IF EXISTS `user_score`;
CREATE TABLE `user_score` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `user_score` bigint(11) DEFAULT NULL,
  `name` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

2.mapper採用的mybatis.generator.plugin反向生成的,這裏不列舉如何生成的,mapper包下存放以下代碼類

ScoreFlowMapper相關代碼

package com.gcxzflgl.redis.mapper;


public interface ScoreFlowMapper {
    @SelectProvider(type=ScoreFlowSqlProvider.class, method="countByExample")
    int countByExample(ScoreFlowExample example);

    @DeleteProvider(type=ScoreFlowSqlProvider.class, method="deleteByExample")
    int deleteByExample(ScoreFlowExample example);

    @Delete({
        "delete from score_flow",
        "where id = #{id,jdbcType=INTEGER}"
    })
    int deleteByPrimaryKey(Integer id);

    @Insert({
        "insert into score_flow (score, user_id, ",
        "user_name)",
        "values (#{score,jdbcType=BIGINT}, #{userId,jdbcType=INTEGER}, ",
        "#{userName,jdbcType=VARCHAR})"
    })
    @Options(useGeneratedKeys=true,keyProperty="id")
    int insert(ScoreFlow record);

    @InsertProvider(type=ScoreFlowSqlProvider.class, method="insertSelective")
    @Options(useGeneratedKeys=true,keyProperty="id")
    int insertSelective(ScoreFlow record);

    @SelectProvider(type=ScoreFlowSqlProvider.class, method="selectByExample")
    @Results({
        @Result(column="id", property="id", jdbcType=JdbcType.INTEGER, id=true),
        @Result(column="score", property="score", jdbcType=JdbcType.BIGINT),
        @Result(column="user_id", property="userId", jdbcType=JdbcType.INTEGER),
        @Result(column="user_name", property="userName", jdbcType=JdbcType.VARCHAR)
    })
    List<ScoreFlow> selectByExample(ScoreFlowExample example);

    @Select({
        "select",
        "id, score, user_id, user_name",
        "from score_flow",
        "where id = #{id,jdbcType=INTEGER}"
    })
    @Results({
        @Result(column="id", property="id", jdbcType=JdbcType.INTEGER, id=true),
        @Result(column="score", property="score", jdbcType=JdbcType.BIGINT),
        @Result(column="user_id", property="userId", jdbcType=JdbcType.INTEGER),
        @Result(column="user_name", property="userName", jdbcType=JdbcType.VARCHAR)
    })
    ScoreFlow selectByPrimaryKey(Integer id);

    @UpdateProvider(type=ScoreFlowSqlProvider.class, method="updateByExampleSelective")
    int updateByExampleSelective(@Param("record") ScoreFlow record, @Param("example") ScoreFlowExample example);

    @UpdateProvider(type=ScoreFlowSqlProvider.class, method="updateByExample")
    int updateByExample(@Param("record") ScoreFlow record, @Param("example") ScoreFlowExample example);

    @UpdateProvider(type=ScoreFlowSqlProvider.class, method="updateByPrimaryKeySelective")
    int updateByPrimaryKeySelective(ScoreFlow record);

    @Update({
        "update score_flow",
        "set score = #{score,jdbcType=BIGINT},",
          "user_id = #{userId,jdbcType=INTEGER},",
          "user_name = #{userName,jdbcType=VARCHAR}",
        "where id = #{id,jdbcType=INTEGER}"
    })
    int updateByPrimaryKey(ScoreFlow record);
}

ScoreFlowSqlProvider 相關代碼

package com.gcxzflgl.redis.mapper;


public class ScoreFlowSqlProvider {

    public String countByExample(ScoreFlowExample example) {
        BEGIN();
        SELECT("count(*)");
        FROM("score_flow");
        applyWhere(example, false);
        return SQL();
    }

    public String deleteByExample(ScoreFlowExample example) {
        BEGIN();
        DELETE_FROM("score_flow");
        applyWhere(example, false);
        return SQL();
    }

    public String insertSelective(ScoreFlow record) {
        BEGIN();
        INSERT_INTO("score_flow");
        
        if (record.getScore() != null) {
            VALUES("score", "#{score,jdbcType=BIGINT}");
        }
        
        if (record.getUserId() != null) {
            VALUES("user_id", "#{userId,jdbcType=INTEGER}");
        }
        
        if (record.getUserName() != null) {
            VALUES("user_name", "#{userName,jdbcType=VARCHAR}");
        }
        
        return SQL();
    }

    public String selectByExample(ScoreFlowExample example) {
        BEGIN();
        if (example != null && example.isDistinct()) {
            SELECT_DISTINCT("id");
        } else {
            SELECT("id");
        }
        SELECT("score");
        SELECT("user_id");
        SELECT("user_name");
        FROM("score_flow");
        applyWhere(example, false);
        
        if (example != null && example.getOrderByClause() != null) {
            ORDER_BY(example.getOrderByClause());
        }
        
        return SQL();
    }

    public String updateByExampleSelective(Map<String, Object> parameter) {
        ScoreFlow record = (ScoreFlow) parameter.get("record");
        ScoreFlowExample example = (ScoreFlowExample) parameter.get("example");
        
        BEGIN();
        UPDATE("score_flow");
        
        if (record.getId() != null) {
            SET("id = #{record.id,jdbcType=INTEGER}");
        }
        
        if (record.getScore() != null) {
            SET("score = #{record.score,jdbcType=BIGINT}");
        }
        
        if (record.getUserId() != null) {
            SET("user_id = #{record.userId,jdbcType=INTEGER}");
        }
        
        if (record.getUserName() != null) {
            SET("user_name = #{record.userName,jdbcType=VARCHAR}");
        }
        
        applyWhere(example, true);
        return SQL();
    }

    public String updateByExample(Map<String, Object> parameter) {
        BEGIN();
        UPDATE("score_flow");
        
        SET("id = #{record.id,jdbcType=INTEGER}");
        SET("score = #{record.score,jdbcType=BIGINT}");
        SET("user_id = #{record.userId,jdbcType=INTEGER}");
        SET("user_name = #{record.userName,jdbcType=VARCHAR}");
        
        ScoreFlowExample example = (ScoreFlowExample) parameter.get("example");
        applyWhere(example, true);
        return SQL();
    }

    public String updateByPrimaryKeySelective(ScoreFlow record) {
        BEGIN();
        UPDATE("score_flow");
        
        if (record.getScore() != null) {
            SET("score = #{score,jdbcType=BIGINT}");
        }
        
        if (record.getUserId() != null) {
            SET("user_id = #{userId,jdbcType=INTEGER}");
        }
        
        if (record.getUserName() != null) {
            SET("user_name = #{userName,jdbcType=VARCHAR}");
        }
        
        WHERE("id = #{id,jdbcType=INTEGER}");
        
        return SQL();
    }

    protected void applyWhere(ScoreFlowExample example, boolean includeExamplePhrase) {
        if (example == null) {
            return;
        }
        
        String parmPhrase1;
        String parmPhrase1_th;
        String parmPhrase2;
        String parmPhrase2_th;
        String parmPhrase3;
        String parmPhrase3_th;
        if (includeExamplePhrase) {
            parmPhrase1 = "%s #{example.oredCriteria[%d].allCriteria[%d].value}";
            parmPhrase1_th = "%s #{example.oredCriteria[%d].allCriteria[%d].value,typeHandler=%s}";
            parmPhrase2 = "%s #{example.oredCriteria[%d].allCriteria[%d].value} and #{example.oredCriteria[%d].criteria[%d].secondValue}";
            parmPhrase2_th = "%s #{example.oredCriteria[%d].allCriteria[%d].value,typeHandler=%s} and #{example.oredCriteria[%d].criteria[%d].secondValue,typeHandler=%s}";
            parmPhrase3 = "#{example.oredCriteria[%d].allCriteria[%d].value[%d]}";
            parmPhrase3_th = "#{example.oredCriteria[%d].allCriteria[%d].value[%d],typeHandler=%s}";
        } else {
            parmPhrase1 = "%s #{oredCriteria[%d].allCriteria[%d].value}";
            parmPhrase1_th = "%s #{oredCriteria[%d].allCriteria[%d].value,typeHandler=%s}";
            parmPhrase2 = "%s #{oredCriteria[%d].allCriteria[%d].value} and #{oredCriteria[%d].criteria[%d].secondValue}";
            parmPhrase2_th = "%s #{oredCriteria[%d].allCriteria[%d].value,typeHandler=%s} and #{oredCriteria[%d].criteria[%d].secondValue,typeHandler=%s}";
            parmPhrase3 = "#{oredCriteria[%d].allCriteria[%d].value[%d]}";
            parmPhrase3_th = "#{oredCriteria[%d].allCriteria[%d].value[%d],typeHandler=%s}";
        }
        
        StringBuilder sb = new StringBuilder();
        List<Criteria> oredCriteria = example.getOredCriteria();
        boolean firstCriteria = true;
        for (int i = 0; i < oredCriteria.size(); i++) {
            Criteria criteria = oredCriteria.get(i);
            if (criteria.isValid()) {
                if (firstCriteria) {
                    firstCriteria = false;
                } else {
                    sb.append(" or ");
                }
                
                sb.append('(');
                List<Criterion> criterions = criteria.getAllCriteria();
                boolean firstCriterion = true;
                for (int j = 0; j < criterions.size(); j++) {
                    Criterion criterion = criterions.get(j);
                    if (firstCriterion) {
                        firstCriterion = false;
                    } else {
                        sb.append(" and ");
                    }
                    
                    if (criterion.isNoValue()) {
                        sb.append(criterion.getCondition());
                    } else if (criterion.isSingleValue()) {
                        if (criterion.getTypeHandler() == null) {
                            sb.append(String.format(parmPhrase1, criterion.getCondition(), i, j));
                        } else {
                            sb.append(String.format(parmPhrase1_th, criterion.getCondition(), i, j,criterion.getTypeHandler()));
                        }
                    } else if (criterion.isBetweenValue()) {
                        if (criterion.getTypeHandler() == null) {
                            sb.append(String.format(parmPhrase2, criterion.getCondition(), i, j, i, j));
                        } else {
                            sb.append(String.format(parmPhrase2_th, criterion.getCondition(), i, j, criterion.getTypeHandler(), i, j, criterion.getTypeHandler()));
                        }
                    } else if (criterion.isListValue()) {
                        sb.append(criterion.getCondition());
                        sb.append(" (");
                        List<?> listItems = (List<?>) criterion.getValue();
                        boolean comma = false;
                        for (int k = 0; k < listItems.size(); k++) {
                            if (comma) {
                                sb.append(", ");
                            } else {
                                comma = true;
                            }
                            if (criterion.getTypeHandler() == null) {
                                sb.append(String.format(parmPhrase3, i, j, k));
                            } else {
                                sb.append(String.format(parmPhrase3_th, i, j, k, criterion.getTypeHandler()));
                            }
                        }
                        sb.append(')');
                    }
                }
                sb.append(')');
            }
        }
        
        if (sb.length() > 0) {
            WHERE(sb.toString());
        }
    }
}

UserMapper相關代碼

package com.gcxzflgl.redis.mapper;


@Mapper
@Component
public interface UserMapper {

	@Insert("insert sys_user(id,user_name) values(#{id},#{userName})")
	void insert(User u);
	
	@Update("update sys_user set user_name = #{userName} where id=#{id} ")
	void update(User u);
	
	@Delete("delete from sys_user where id=#{id} ")
	void delete(@Param("id") String id);

	@Select("select id,user_name from sys_user where id=#{id} ")
	User find(@Param("id") String id);

	//注:方法名和要UserMapper.xml中的id一致
	List<User> query(@Param("userName") String userName);

	@Delete("delete from sys_user")
	void deleteAll();
}

UserScoreMapper 相關代碼

package com.gcxzflgl.redis.mapper;


public interface UserScoreMapper {
    @SelectProvider(type=UserScoreSqlProvider.class, method="countByExample")
    int countByExample(UserScoreExample example);

    @DeleteProvider(type=UserScoreSqlProvider.class, method="deleteByExample")
    int deleteByExample(UserScoreExample example);

    @Delete({
        "delete from user_score",
        "where id = #{id,jdbcType=INTEGER}"
    })
    int deleteByPrimaryKey(Integer id);

    @Insert({
        "insert into user_score (user_id, user_score, ",
        "name)",
        "values (#{userId,jdbcType=INTEGER}, #{userScore,jdbcType=BIGINT}, ",
        "#{name,jdbcType=VARCHAR})"
    })
    @Options(useGeneratedKeys=true,keyProperty="id")
    int insert(UserScore record);

    @InsertProvider(type=UserScoreSqlProvider.class, method="insertSelective")
    @Options(useGeneratedKeys=true,keyProperty="id")
    int insertSelective(UserScore record);

    @SelectProvider(type=UserScoreSqlProvider.class, method="selectByExample")
    @Results({
        @Result(column="id", property="id", jdbcType=JdbcType.INTEGER, id=true),
        @Result(column="user_id", property="userId", jdbcType=JdbcType.INTEGER),
        @Result(column="user_score", property="userScore", jdbcType=JdbcType.BIGINT),
        @Result(column="name", property="name", jdbcType=JdbcType.VARCHAR)
    })
    List<UserScore> selectByExample(UserScoreExample example);

    @Select({
        "select",
        "id, user_id, user_score, name",
        "from user_score",
        "where id = #{id,jdbcType=INTEGER}"
    })
    @Results({
        @Result(column="id", property="id", jdbcType=JdbcType.INTEGER, id=true),
        @Result(column="user_id", property="userId", jdbcType=JdbcType.INTEGER),
        @Result(column="user_score", property="userScore", jdbcType=JdbcType.BIGINT),
        @Result(column="name", property="name", jdbcType=JdbcType.VARCHAR)
    })
    UserScore selectByPrimaryKey(Integer id);

    @UpdateProvider(type=UserScoreSqlProvider.class, method="updateByExampleSelective")
    int updateByExampleSelective(@Param("record") UserScore record, @Param("example") UserScoreExample example);

    @UpdateProvider(type=UserScoreSqlProvider.class, method="updateByExample")
    int updateByExample(@Param("record") UserScore record, @Param("example") UserScoreExample example);

    @UpdateProvider(type=UserScoreSqlProvider.class, method="updateByPrimaryKeySelective")
    int updateByPrimaryKeySelective(UserScore record);

    @Update({
        "update user_score",
        "set user_id = #{userId,jdbcType=INTEGER},",
          "user_score = #{userScore,jdbcType=BIGINT},",
          "name = #{name,jdbcType=VARCHAR}",
        "where id = #{id,jdbcType=INTEGER}"
    })
    int updateByPrimaryKey(UserScore record);
}

UserScoreSqlProvider 相關代碼

package com.gcxzflgl.redis.mapper;


public class UserScoreSqlProvider {

    public String countByExample(UserScoreExample example) {
        BEGIN();
        SELECT("count(*)");
        FROM("user_score");
        applyWhere(example, false);
        return SQL();
    }

    public String deleteByExample(UserScoreExample example) {
        BEGIN();
        DELETE_FROM("user_score");
        applyWhere(example, false);
        return SQL();
    }

    public String insertSelective(UserScore record) {
        BEGIN();
        INSERT_INTO("user_score");
        
        if (record.getUserId() != null) {
            VALUES("user_id", "#{userId,jdbcType=INTEGER}");
        }
        
        if (record.getUserScore() != null) {
            VALUES("user_score", "#{userScore,jdbcType=BIGINT}");
        }
        
        if (record.getName() != null) {
            VALUES("name", "#{name,jdbcType=VARCHAR}");
        }
        
        return SQL();
    }

    public String selectByExample(UserScoreExample example) {
        BEGIN();
        if (example != null && example.isDistinct()) {
            SELECT_DISTINCT("id");
        } else {
            SELECT("id");
        }
        SELECT("user_id");
        SELECT("user_score");
        SELECT("name");
        FROM("user_score");
        applyWhere(example, false);
        
        if (example != null && example.getOrderByClause() != null) {
            ORDER_BY(example.getOrderByClause());
        }
        
        return SQL();
    }

    public String updateByExampleSelective(Map<String, Object> parameter) {
        UserScore record = (UserScore) parameter.get("record");
        UserScoreExample example = (UserScoreExample) parameter.get("example");
        
        BEGIN();
        UPDATE("user_score");
        
        if (record.getId() != null) {
            SET("id = #{record.id,jdbcType=INTEGER}");
        }
        
        if (record.getUserId() != null) {
            SET("user_id = #{record.userId,jdbcType=INTEGER}");
        }
        
        if (record.getUserScore() != null) {
            SET("user_score = #{record.userScore,jdbcType=BIGINT}");
        }
        
        if (record.getName() != null) {
            SET("name = #{record.name,jdbcType=VARCHAR}");
        }
        
        applyWhere(example, true);
        return SQL();
    }

    public String updateByExample(Map<String, Object> parameter) {
        BEGIN();
        UPDATE("user_score");
        
        SET("id = #{record.id,jdbcType=INTEGER}");
        SET("user_id = #{record.userId,jdbcType=INTEGER}");
        SET("user_score = #{record.userScore,jdbcType=BIGINT}");
        SET("name = #{record.name,jdbcType=VARCHAR}");
        
        UserScoreExample example = (UserScoreExample) parameter.get("example");
        applyWhere(example, true);
        return SQL();
    }

    public String updateByPrimaryKeySelective(UserScore record) {
        BEGIN();
        UPDATE("user_score");
        
        if (record.getUserId() != null) {
            SET("user_id = #{userId,jdbcType=INTEGER}");
        }
        
        if (record.getUserScore() != null) {
            SET("user_score = #{userScore,jdbcType=BIGINT}");
        }
        
        if (record.getName() != null) {
            SET("name = #{name,jdbcType=VARCHAR}");
        }
        
        WHERE("id = #{id,jdbcType=INTEGER}");
        
        return SQL();
    }

    protected void applyWhere(UserScoreExample example, boolean includeExamplePhrase) {
        if (example == null) {
            return;
        }
        
        String parmPhrase1;
        String parmPhrase1_th;
        String parmPhrase2;
        String parmPhrase2_th;
        String parmPhrase3;
        String parmPhrase3_th;
        if (includeExamplePhrase) {
            parmPhrase1 = "%s #{example.oredCriteria[%d].allCriteria[%d].value}";
            parmPhrase1_th = "%s #{example.oredCriteria[%d].allCriteria[%d].value,typeHandler=%s}";
            parmPhrase2 = "%s #{example.oredCriteria[%d].allCriteria[%d].value} and #{example.oredCriteria[%d].criteria[%d].secondValue}";
            parmPhrase2_th = "%s #{example.oredCriteria[%d].allCriteria[%d].value,typeHandler=%s} and #{example.oredCriteria[%d].criteria[%d].secondValue,typeHandler=%s}";
            parmPhrase3 = "#{example.oredCriteria[%d].allCriteria[%d].value[%d]}";
            parmPhrase3_th = "#{example.oredCriteria[%d].allCriteria[%d].value[%d],typeHandler=%s}";
        } else {
            parmPhrase1 = "%s #{oredCriteria[%d].allCriteria[%d].value}";
            parmPhrase1_th = "%s #{oredCriteria[%d].allCriteria[%d].value,typeHandler=%s}";
            parmPhrase2 = "%s #{oredCriteria[%d].allCriteria[%d].value} and #{oredCriteria[%d].criteria[%d].secondValue}";
            parmPhrase2_th = "%s #{oredCriteria[%d].allCriteria[%d].value,typeHandler=%s} and #{oredCriteria[%d].criteria[%d].secondValue,typeHandler=%s}";
            parmPhrase3 = "#{oredCriteria[%d].allCriteria[%d].value[%d]}";
            parmPhrase3_th = "#{oredCriteria[%d].allCriteria[%d].value[%d],typeHandler=%s}";
        }
        
        StringBuilder sb = new StringBuilder();
        List<Criteria> oredCriteria = example.getOredCriteria();
        boolean firstCriteria = true;
        for (int i = 0; i < oredCriteria.size(); i++) {
            Criteria criteria = oredCriteria.get(i);
            if (criteria.isValid()) {
                if (firstCriteria) {
                    firstCriteria = false;
                } else {
                    sb.append(" or ");
                }
                
                sb.append('(');
                List<Criterion> criterions = criteria.getAllCriteria();
                boolean firstCriterion = true;
                for (int j = 0; j < criterions.size(); j++) {
                    Criterion criterion = criterions.get(j);
                    if (firstCriterion) {
                        firstCriterion = false;
                    } else {
                        sb.append(" and ");
                    }
                    
                    if (criterion.isNoValue()) {
                        sb.append(criterion.getCondition());
                    } else if (criterion.isSingleValue()) {
                        if (criterion.getTypeHandler() == null) {
                            sb.append(String.format(parmPhrase1, criterion.getCondition(), i, j));
                        } else {
                            sb.append(String.format(parmPhrase1_th, criterion.getCondition(), i, j,criterion.getTypeHandler()));
                        }
                    } else if (criterion.isBetweenValue()) {
                        if (criterion.getTypeHandler() == null) {
                            sb.append(String.format(parmPhrase2, criterion.getCondition(), i, j, i, j));
                        } else {
                            sb.append(String.format(parmPhrase2_th, criterion.getCondition(), i, j, criterion.getTypeHandler(), i, j, criterion.getTypeHandler()));
                        }
                    } else if (criterion.isListValue()) {
                        sb.append(criterion.getCondition());
                        sb.append(" (");
                        List<?> listItems = (List<?>) criterion.getValue();
                        boolean comma = false;
                        for (int k = 0; k < listItems.size(); k++) {
                            if (comma) {
                                sb.append(", ");
                            } else {
                                comma = true;
                            }
                            if (criterion.getTypeHandler() == null) {
                                sb.append(String.format(parmPhrase3, i, j, k));
                            } else {
                                sb.append(String.format(parmPhrase3_th, i, j, k, criterion.getTypeHandler()));
                            }
                        }
                        sb.append(')');
                    }
                }
                sb.append(')');
            }
        }
        
        if (sb.length() > 0) {
            WHERE(sb.toString());
        }
    }
}

3.再biz包下創建RedisService工具方法和RangingService業務方法

RedisService工具類

package com.gcxzflgl.redis.biz;


@Service
public class RedisService {

    @Autowired
    private RedisTemplate redisTemplate;

    private static double size = Math.pow(2, 32);


    /**
     * 寫入緩存
     *
     * @param key
     * @param offset   位 8Bit=1Byte
     * @return
     */
    public boolean setBit(String key, long offset, boolean isShow) {
        boolean result = false;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            operations.setBit(key, offset, isShow);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 寫入緩存
     *
     * @param key
     * @param offset
     * @return
     */
    public boolean getBit(String key, long offset) {
        boolean result = false;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            result = operations.getBit(key, offset);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }


    /**
     * 寫入緩存
     *
     * @param key
     * @param value
     * @return
     */
    public boolean set(final String key, Object value) {
        boolean result = false;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 寫入緩存設置時效時間
     *
     * @param key
     * @param value
     * @return
     */
    public boolean set(final String key, Object value, Long expireTime) {
        boolean result = false;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 批量刪除對應的value
     *
     * @param keys
     */
    public void remove(final String... keys) {
        for (String key : keys) {
            remove(key);
        }
    }


    /**
     * 刪除對應的value
     *
     * @param key
     */
    public void remove(final String key) {
        if (exists(key)) {
            redisTemplate.delete(key);
        }
    }

    /**
     * 判斷緩存中是否有對應的value
     *
     * @param key
     * @return
     */
    public boolean exists(final String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 讀取緩存
     *
     * @param key
     * @return
     */
    public Object get(final String key) {
        Object result = null;
        ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
        result = operations.get(key);
        return result;
    }

    /**
     * 哈希 添加
     *
     * @param key
     * @param hashKey
     * @param value
     */
    public void hmSet(String key, Object hashKey, Object value) {
        HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
        hash.put(key, hashKey, value);
    }

    /**
     * 哈希獲取數據
     *
     * @param key
     * @param hashKey
     * @return
     */
    public Object hmGet(String key, Object hashKey) {
        HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
        return hash.get(key, hashKey);
    }

    /**
     * 列表添加
     *
     * @param k
     * @param v
     */
    public void lPush(String k, Object v) {
        ListOperations<String, Object> list = redisTemplate.opsForList();
        list.rightPush(k, v);
    }

    /**
     * 列表獲取
     *
     * @param k
     * @param l
     * @param l1
     * @return
     */
    public List<Object> lRange(String k, long l, long l1) {
        ListOperations<String, Object> list = redisTemplate.opsForList();
        return list.range(k, l, l1);
    }

    /**
     * 集合添加
     *
     * @param key
     * @param value
     */
    public void add(String key, Object value) {
        SetOperations<String, Object> set = redisTemplate.opsForSet();
        set.add(key, value);
    }

    /**
     * 集合獲取
     *
     * @param key
     * @return
     */
    public Set<Object> setMembers(String key) {
        SetOperations<String, Object> set = redisTemplate.opsForSet();
        return set.members(key);
    }

    /**
     * 有序集合添加
     *
     * @param key
     * @param value
     * @param scoure
     */
    public void zAdd(String key, Object value, double scoure) {
        ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
        zset.add(key, value, scoure);
    }

    /**
     * 有序集合獲取
     *
     * @param key
     * @param scoure
     * @param scoure1
     * @return
     */
    public Set<Object> rangeByScore(String key, double scoure, double scoure1) {
        ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
        redisTemplate.opsForValue();
        return zset.rangeByScore(key, scoure, scoure1);
    }


    //第一次加載的時候將數據加載到redis中
    public void saveDataToRedis(String name) {
        double index = Math.abs(name.hashCode() % size);
        long indexLong = new Double(index).longValue();
        boolean availableUsers = setBit("availableUsers", indexLong, true);
    }

    //第一次加載的時候將數據加載到redis中
    public boolean getDataToRedis(String name) {

        double index = Math.abs(name.hashCode() % size);
        long indexLong = new Double(index).longValue();
        return getBit("availableUsers", indexLong);
    }

    /**
     * 有序集合獲取排名
     *
     * @param key 集合名稱
     * @param value 值
     */
    public Long zRank(String key, Object value) {
        ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
        return zset.rank(key,value);
    }


    /**
     * 有序集合獲取排名
     *
     * @param key
     */
    public Set<ZSetOperations.TypedTuple<Object>> zRankWithScore(String key, long start,long end) {
        ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
        Set<ZSetOperations.TypedTuple<Object>> ret = zset.rangeWithScores(key,start,end);
        return ret;
    }

    /**
     * 有序集合添加
     *
     * @param key
     * @param value
     */
    public Double zSetScore(String key, Object value) {
        ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
        return zset.score(key,value);
    }


    /**
     * 有序集合添加分數
     *
     * @param key
     * @param value
     * @param scoure
     */
    public void incrementScore(String key, Object value, double scoure) {
        ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
        zset.incrementScore(key, value, scoure);
    }


    /**
     * 有序集合獲取排名
     *
     * @param key
     */
    public Set<ZSetOperations.TypedTuple<Object>> reverseZRankWithScore(String key, long start,long end) {
        ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
        Set<ZSetOperations.TypedTuple<Object>> ret = zset.reverseRangeByScoreWithScores(key,start,end);
        return ret;
    }

    /**
     * 有序集合獲取排名
     *
     * @param key
     */
    public Set<ZSetOperations.TypedTuple<Object>> reverseZRankWithRank(String key, long start, long end) {
        ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
        Set<ZSetOperations.TypedTuple<Object>> ret = zset.reverseRangeWithScores(key, start, end);
        return ret;
    }

}

RangingService業務方法

package com.gcxzflgl.redis.biz;


@Service
public class RangingService implements InitializingBean {


    private static final String RANKGNAME = "user_score";

    private static final String SALESCORE = "sale_score_rank:";

    @Autowired
    private RedisService redisService;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private ScoreFlowMapper scoreFlowMapper;

    @Autowired
    private UserScoreMapper userScoreMapper;


    /**
     * 添加用戶積分
     *
     * @param uid
     * @param score
     */
    public void increSaleSocre(String uid, Integer score) {
        User user = userMapper.find(uid);
        if (user == null) {
            return;
        }
        int uidInt = Integer.parseInt(uid);
        long socreLong = Long.parseLong(score + "");
        String name = user.getUserName();
        String key = uid + ":" + name;
        scoreFlowMapper.insertSelective(new ScoreFlow(socreLong, uidInt, name));
        userScoreMapper.insertSelective(new UserScore(uidInt, socreLong, name));
        redisService.incrementScore(SALESCORE, key, score);
    }


    public Map<String, Object> userRank(String uid, String name) {
        Map<String, Object> retMap = new LinkedHashMap<>();
        String key = uid + ":" + name;
        Integer rank = redisService.zRank(SALESCORE, key).intValue();
        Long score = redisService.zSetScore(SALESCORE, key).longValue();
        retMap.put("userId", uid);
        retMap.put("score", score);
        retMap.put("rank", rank);
        return retMap;
    }


    public List<Map<String, Object>> reverseZRankWithRank(long start, long end) {
        Set<ZSetOperations.TypedTuple<Object>> setObj = redisService.reverseZRankWithRank(SALESCORE, start, end);
        List<Map<String, Object>> mapList = setObj.stream().map(objectTypedTuple -> {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("userId", objectTypedTuple.getValue().toString().split(":")[0]);
            map.put("userName", objectTypedTuple.getValue().toString().split(":")[1]);
            map.put("score", objectTypedTuple.getScore());
            return map;
        }).collect(Collectors.toList());
        return mapList;
    }

  

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("======enter init bean=======");
        this.rankSaleAdd();
    }
}

4.rest層放入對外訪問的接口地址訪問

package com.gcxzflgl.redis.rest;


@RestController
public class RankingController {


    @Autowired
    private RangingService rankingService;

 
	/**
     * 添加用戶積分
     * @param uid
     * @param score
     * @return
     */
    @RequestMapping("/sale/increScore")
    public String increSaleScore(String uid, Integer score) {
        rankingService.increSaleSocre(uid, score);
        return "success";
    }


    /**
     * 用戶排名查看
     * @param uid
     * @param name
     * @return
     */
    @RequestMapping("/sale/userScore")
    public Map<String,Object> userScore(String uid,String name) {
        return rankingService.userRank(uid,name);
    }

    /**
     * topx
     * @param start
     * @param end
     * @return
     */
    @RequestMapping("/sale/top")
    public List<Map<String,Object>> reverseZRankWithRank(long start,long end) {
        return rankingService.reverseZRankWithRank(start,end);
    }


  
}

5.resources/mapper放入UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.gcxzflgl.redis.mapper.UserMapper">
 
<select id="query"  resultType="com.gcxzflgl.redis.domain.User">
    select id ,user_name 
    from sys_user 
    where 1=1
    <if test="userName != null">
      and user_name like CONCAT('%',#{userName},'%')
    </if>
</select>
</mapper>

6.啓動項目測試
sql腳本中用戶表(sys_user)模擬的是存量用戶方便測試演示
用戶添加積分地址:
http://xxx.xxx.xx.xx:8080/sale/increScore?uid=1&score=2
http://xxx.xxx.xx.xx:8080/sale/increScore?uid=2&score=5
http://xxx.xxx.xx.xx:8080/sale/increScore?uid=3&score=10
http://xxx.xxx.xx.xx:8080/sale/increScore?uid=4&score=15
http://xxx.xxx.xx.xx:8080/sale/increScore?uid=5&score=30

用戶排行查看地址:
http://xxx.xxx.xx.xx:8080/sale/userScore?uid=3&name=張飛

{"userId":"3","score":17,"rank":2}

用戶積分前top10:
http://xxx.xxx.xx.xx:8080/sale/top?start=0&end=9

[{"userId":"5","userName":"關羽","score":40.0},{"userId":"4","userName":"馬超","score":25.0},{"userId":"3","userName":"張飛","score":17.0},{"userId":"2","userName":"瑞燊兒","score":10.0},{"userId":"1","userName":"高晨曦","score":5.0}]

細節之處處理的不夠好,只是爲了說明排行榜思想是什麼,至此本案例演示完畢!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章