关注公众号“Java 后端技术全栈”**
回复“面试”获取全套大厂面试资料
缓存的简单认识
在项目中存在很多地方使用缓存,缓存是我们提高系统的一项必不可少的技术,无论是前端还是后端,都应用到了缓存技术,Mysql数据库也有使用缓存,所以认识缓存是非常有必要的。
前端缓存
服务端缓存
其中我们可以使用Redis做分布式缓存。
Redis 简单认识
Redis是一个速度非常快的非关系型数据库(Non-Relational Database),Redis 可以存储键值(key-value)数据。其中 value 可以用 5 种类型。可以将存储在内存的键值对数据持久化到硬盘上,可以使用复制特性来扩展读性能,还可以做客户端分片来扩展写性能。
为了满足 Redis 的高性能,它采用了(in-memory)数据集(Dataset),根据使用场景,可以通过每隔一段时间转存数据集到磁盘,或者追加没挑明了到日志来持久化。也可以禁用持久化,如果你只是需要一个功能丰富、网络传输化的内存缓存。
Redis 数据模型
Redis 数据模型不仅与关系型数据库不同,也不同于其他简单的 NoSQL 键值数据存储。
Redis 数据类型类似于编程语言的基础类型数据,因此在对于咱们开发人员来说就更易于理解和使用。每个数据类型都支持适用于其类型的操作,受支持的数类型约束。
场景类型五种:
- String 字符串 
- Hash 哈希 
- List 列表 
- Set 集合 
- ZSet 有序集合 
Spring Boot 集成 Redis
增加依赖
 <dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- 连接池--><dependency>    <groupId>org.apache.commons</groupId>    <artifactId>commons-pool2</artifactId></dependency>
   复制代码
 
添加配置
 properties# Redis数据库索引(默认为0)spring.redis.database=0# Redis服务器地址spring.redis.host=127.0.0.1# Redis服务器连接端口spring.redis.port=6379# Redis服务器连接密码(默认为空)spring.redis.password=# 连接池最大连接数(使用负值表示没有限制)spring.redis.jedis.pool.max-active=20# 连接池最大阻塞等待时间(使用负值表示没有限制)spring.redis.jedis.pool.max-wait=-1# 连接池中的最大空闲连接spring.redis.jedis.pool.max-idle=10# 连接池中的最小空闲连接spring.redis.jedis.pool.min-idle=0# 连接超时时间(毫秒)spring.redis.timeout=1000
   复制代码
 
Redis 使用
 @RestController()public class RedisController {    @Resource    private RedisTemplate redisTemplate;    /**     * 普通存储key-value     */    @GetMapping("/setKeyAndValue")    public String setKeyAndValue() {        redisTemplate.opsForValue().set("name", "java后端技术全栈");        String value = (String) redisTemplate.opsForValue().get("name");        System.out.println("name value =" + value);        //设置有效期         redisTemplate.opsForValue().set("name1", "java后端技术栈", 100,                                                                         TimeUnit.MILLISECONDS);        value =  redisTemplate.opsForValue().get("name1") == null ? "" : (String)                                 redisTemplate.opsForValue().get("name1");        System.out.println("name1 value =" + value);        return "ok";    }} 
   复制代码
 
请求 http://localhost:8080/setKeyAndValue  输出
 name value =java后端技术全栈name1 value =java后端技术栈
   复制代码
 
OK,到此,Redis 已经成功集成到 Spring Boot 项目中了。
集成进来后,我们就可以使用 Redis 来做很多事情了。
1,使用 Redis 来存储用户登录 session
2,使用 Redis 的 setnx 和 expire 来做分布式锁
3,使用 Redis 的 List 来做队列
4,使用 Redis 的 ZSet 来做排行榜
5,使用自增 inrc 来确保不会超卖。
…..
上述这些使用场景是有前提条件的,因为没有绝对完美的技术,只能是选择相对能满足业务场景的就 OK。
这里我们来做一个排行榜的场景。
Redis 实现排行榜
需求是做一个用户购买理财产品金额的排行榜,相同的金额的以购买时间来排名。
 public class UserAccount {    private Integer userId;    private String userName;    private BigDecimal amount;    private Date createTime;//get set}
   复制代码
 
写一个 controller 演示
 @RestController()public class RedisController {    @Resource    private RedisTemplate redisTemplate;    private static final String RANK_KEY_PRE = "user_amount_redis_key";    @GetMapping("/rank")    public String rank() {        List<UserAccount> userAccountList = new ArrayList<>();        UserAccount userAccount = new UserAccount();        userAccount.setAmount(new BigDecimal("100001"));        userAccount.setUserId(10001);        userAccount.setUserName("zhangsan");        userAccount.setCreateTime(new Date());        userAccountList.add(userAccount);        UserAccount userAccount1 = new UserAccount();        userAccount1.setAmount(new BigDecimal("100000"));        userAccount1.setUserId(10002);        userAccount1.setUserName("lisi");        userAccount1.setCreateTime(new Date());        userAccountList.add(userAccount1);        UserAccount userAccount2 = new UserAccount();        userAccount2.setAmount(new BigDecimal("100000"));        userAccount2.setUserId(10003);        userAccount2.setUserName("wangwu");        userAccount2.setCreateTime(DateUtil.parseDate("2020-08-15 10:10:10", DateUtil.DATE_TIME_FORMAT));        userAccountList.add(userAccount2);        UserAccount userAccount3 = new UserAccount();        userAccount3.setAmount(new BigDecimal("100002"));        userAccount3.setUserId(10004);        userAccount3.setUserName("laoliu");        userAccount3.setCreateTime(new Date());        userAccountList.add(userAccount3);        for (UserAccount ua : userAccountList) {            zadd(ua.getUserName(), RANK_KEY_PRE, ua.getAmount().longValue(), ua.getCreateTime().getTime());        }        List<ZSetOperations.TypedTuple> tuples = getRankCache(RANK_KEY_PRE, 0, 10);        for (int i =0;  i <=tuples.size()-1; i++) {            ZSetOperations.TypedTuple tuple = tuples.get(i);            System.out.println(tuple.getValue() + " 第" +( i )+ "名,分数=" + tuple.getScore());        }        return "ok";    }    private void zadd(String userName, String key, long points, long updateTime) {        double timeRank = points + 1 - updateTime / Math.pow(10, (int) Math.log10(updateTime) + 1);        redisTemplate.opsForZSet().add(key, userName, timeRank);    }private List<ZSetOperations.TypedTuple> getRankCache(String key, int start, int end) {        Set<ZSetOperations.TypedTuple> scoreSet = redisTemplate.opsForZSet().rangeWithScores(key, start, end);        if (CollectionUtils.isEmpty(scoreSet)) {            return new ArrayList<>();        }        List<ZSetOperations.TypedTuple> scoreList = new ArrayList<>();        for (ZSetOperations.TypedTuple item : scoreSet) {            scoreList.add(item);        }        return scoreList;    }  }
   复制代码
 
时间处理工具类
 import java.text.DateFormat;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;public class DateUtil {    public static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";    /**     * 字符转Date类型     *     * @param dateString   String 时间字符串     * @param formatString String 字符串格式;如:yyyy-MM-dd hh:mm:ss,年-月-日 时:分:秒     */    public static Date parseDate(String dateString, String formatString) {        if (formatString == null) {            formatString = DATE_TIME_FORMAT;        }        DateFormat dd = new SimpleDateFormat(formatString);        try {            return dd.parse(dateString);        } catch (ParseException e) {            throw new RuntimeException(e);        }    }}
   复制代码
 
启动项目,然后请求
http://localhost:8080/rank
输出
 lisi 第4名,分数=100000.84024399419wangwu 第3名,分数=100000.840254259zhangsan 第2名,分数=100001.84024399419laoliu 第1名,分数=100002.84024399419
   复制代码
 
排名依据出来了。
redis 的其他功能后面继续完善,本文就搞到这里。
码字不易,期待你们  点在看+分享。
推荐阅读
如何优雅的导出 Excel
终于明白为什么要加 final 关键字了!
评论