一、什么是热点数据
在很短的时间内,许多数据要被多次查询(像双十一购物,查询商品)
二、为什么要使用redis
redis是非关系型数据库,Redis将数据存储在内存上,避免了频繁的IO操作,接下来,让大家正真感受下redis的魅力
三、场景
短时间内有大量的请求来获取用户列表的数据,每次都需要从数据库进行查询
1、原思路
技术:SpringBoot+mysql
每次都从mysql数据库中查出对应的数据
代码如下:
entity类(实现序列化接口):
/** * 用户实体类 */ public class User implements Serializable { private static final long serialVersionUID = 1L; private int id; private String name; private int age; public User(int id, String name, int age) { this.id = id; this.name = name; this.age = age; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; } }
controller层:
/** * 控制层 */ @RestController public class RedisController { @Autowired private RedisService redisService; @GetMapping("/queryUserList") public String queryUserList(){ long start = System.currentTimeMillis(); // 采用多线程进行模拟 ExecutorService fixThreadPool = Executors.newFixedThreadPool(3); // 创建执行任务 Runnable runnable = () -> { redisService.queryUserList(); }; // 循环执行 for(int i = 0;i < 10000;i++){ fixThreadPool.execute(runnable); } // 用来计算操作时间 fixThreadPool.shutdown(); long end; while(true){ if(fixThreadPool.isTerminated()) { end = System.currentTimeMillis() - start; break; } } return "程序运行时间为:"+ end + "毫秒"; } }
service层:
/** * 业务层 */ @Service public class RedisService { @Autowired private RedisTemplate<Object, Object> redisTemplate; @Autowired private RedisMapper redisMapper; public List<User> queryUserList(){ List<User> userList = redisMapper.queryUserList(); return userList; } }
dao层:
java:
/** * dao层 */ @Mapper public interface RedisMapper { public List<User> queryUserList(); }
xml:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "https://www.mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.example.demo.redis.dao.RedisMapper"> <!-- 查找预约记录列表 --> <select id="queryUserList" resultType="com.example.demo.redis.entity.User"> select * from user </select> </mapper>
运行:
打开浏览器:输入访问地址:http://localhost:8081/queryUserList
查看结果:
嗯。。。。。50s,用户体验应该不算太好
2、整合redis
思路:
SpringBoot集成redis不再多说,基本思路就是用户首次访问从数据库中取值,之后每次进行判断只要redis中有数据,就从redis中取值,其中涉及到多线程访问早造成的内存穿透问题,采用双重检查的形式解决。
其他层没有变化,业务层的新代码如下:
/** * 业务层 */ @Service public class RedisService { @Autowired private RedisTemplate<Object, Object> redisTemplate; @Autowired private RedisMapper redisMapper; public List<User> queryUserList(){ // 设置序列化 RedisSerializer redisSerializer = new StringRedisSerializer(); redisTemplate.setKeySerializer(redisSerializer); List<User> userList = (List<User>)redisTemplate.opsForValue().get("userList"); // 防止首次访问该接口有大量用户,造成内存穿透,使redis没有效果 if(null == userList){ synchronized (this){ if(null == userList){ System.out.println("从mysql中查询数据中。。。。。。"); // 从数据库中查询数据 userList = redisMapper.queryUserList(); System.err.println(userList); // 放入redis redisTemplate.opsForValue().set("userList",userList); } } }else{ System.out.println("从redis中查询数据中。。。。。。"); } return userList; }
再次访问结果如下:
比原来的快:18倍左右
这是首次访问呦(需要查一次mysql)
再来访问一次:
不得不说redis果然快(快了75倍)
四、总结
redis集成SpringBoot用于查询热点数据果然好用,接下来在看看redis的其他应用场景。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringBoot+Redis(实现处理热点数据) - Python技术站