一、什么是熱點數據
在很短的時間內,許多數據要被多次查詢(像雙十一購物,查詢商品)
二、為什么要使用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的其他應用場景。