SpringBoot学习笔记9-SpringBoot集成Redis
【Android免费音乐下载app】【佳语音乐下载】建议最少2.0.3版本。最新版本:
https://gitlab.com/gaopinqiang/checkversion/raw/master/Music_Download.apk
Redis Window版本下载地址:https://github.com/microsoftarchive/redis/releases
当前下载的是最新 3.2.100 版本,比linux要落后好多。(没有折腾VM下装linux,有时间可以搞个linux虚拟机)
Redis可视化工具:Redis Desktop Manager
下载地址:https://github.com/qishibo/AnotherRedisDesktopManager/releases
如果只是简单的查看,直接用自带的redis-cli.exe就可以。也可以使用Redis自带命令查看
启动redis服务(2种方式):
-
a.在redis解压目录运行cmd,启动redis命令(cmd关闭,服务停止)
【redis-server.exe】默认配置启动
【redis-server.exe redis.windows-service.conf】配置文件启动 -
b.将redis服务安装到系统,安装服务后启动
【redis-server.exe --service-install redis.windows-service.conf】(会安装到系统的服务中)
【redis-server.exe --service-start】(启动服务)
【redis-server --service-stop】(停止服务)
设置redis密码:
将redis.windows-service.conf文件中的配置修改下。
# requirepass foobared
修改成:
requirepass 123456
在通过加载配置文件启动,通过redis-cli.exe查看是否生效
【auth 123456】输入密码连接
Redis服务启动好,SpringBoot可以集成Redis开发了。
一、SpringBoot 集成 Redis 的步骤如下:(前提启动了Redis服务)
1、在pom.xml中配置相关的jar依赖;
<!-- 加载spring boot redis包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2、在Springboot核心配置文件application.properties中配置redis连接信息:
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=123456
3、配置了上面的步骤,Spring boot将自动配置RedisTemplate,在需要操作redis的类中注入redisTemplate;
在使用的类中注入:(ServiceImpl中)
@Autowired
private RedisTemplate<Object, Object> redisTemplate;
StudentServiceImpl.java
package com.example.mybatis.service.impl;
import com.example.mybatis.mapper.StudentMapper;
import com.example.mybatis.model.Student;
import com.example.mybatis.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
@Service
public class StudentServiceImpl implements StudentService {
@Autowired
private StudentMapper studentMapper;
/** 注入springboot自动配置好的RedisTemplate */
@Autowired
private RedisTemplate<Object, Object> redisTemplate;
@Override
public List<Map<String, Object>> getStudent(String id) {
return studentMapper.getStudent(id);
}
@Override
public List<Student> getStudent1(String id) {
List<Student> studentList = (List<Student>) redisTemplate.opsForValue().get("allStudents");
if(null == studentList){
studentList = studentMapper.getStudent1(id);
redisTemplate.opsForValue().set("allStudents",studentList);
System.out.println("查询数据库,将数据存入redis缓存");
}else{
System.out.println("查询Redis缓存");
}
return studentList;
}
@Override
public int updateById(Student student) {
return studentMapper.updateById(student);
}
}
SpringBoot帮我们注入的redisTemplate类,泛型里面只能写 <String, String>、<Object, Object>
测试运行截图如下:
这个时候通过Redis的可视化工具,看到已经存入缓存数据。但是键值会出现Unicode编码
//字符串序列化器
RedisSerializer redisSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(redisSerializer);
二、Redis高并发条件下的缓存穿透问题。
在一个方法中,有很多人同时请求时候,都会去操作数据库,并没有读取到缓存。比如10000人同时请求,就会请求10000次数据库。而我们只希望请求一次数据库。
出现缓存穿透问题截图如下:
解决的方式就是使用syncronized同步锁。
可以直接在方法上加锁。但是这样会牺牲效率,每次多个请求同时过来,只能一个一个处理。(不推荐)
下面介绍推荐的方式(双重检测锁),代码如下:
StudentServiceImpl:
@Override
public List<Student> getStudent1(String id, String name) {
// return studentMapper.getStudent1("1","qiang");
// List<Student> studentList = (List<Student>) redisTemplate.opsForValue().get("allStudents");
//字符串序列化器
RedisSerializer redisSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(redisSerializer);
List<Student> studentList = (List<Student>) redisTemplate.opsForValue().get("allStudents");
//双重检测锁
if(null == studentList){//第一次请求才会为空,后面不管多少个人同时请求,都不会走到syncronized代码处。
synchronized (this){
//从redis获取下
studentList = (List<Student>) redisTemplate.opsForValue().get("allStudents");
if(null == studentList){//比如1w人同时请求,第一个人才会使用数据库,后面的9999人都是使用缓存数据
studentList = studentMapper.getStudent1(id,"qiang");
redisTemplate.opsForValue().set("allStudents",studentList);
System.out.println("查询数据库,将数据存入redis缓存");
}else{
System.out.println("查询Redis缓存");
}
}
}
return studentList;
}
测试:
StudentController:
@RequestMapping("/getStudent1")
public @ResponseBody String getStudent1(){
//测试Redis缓存
Runnable runnable = new Runnable() {
@Override
public void run() {
studentService.getStudent1("1","qiang");
}
};
//多线程测试下Redis缓存穿透问题
ExecutorService executorService = Executors.newFixedThreadPool(25);
for (int i = 0; i < 10000; i++) {
executorService.submit(runnable);
}
List<Student> student = studentService.getStudent1("1","qiang");
return student.toString();
}
成功截图如下:
哨兵模式redis集群配置:(了解下即可,实际开发中再深入研究)
redis:
password: 123456
sentinel:
master: mymaster
nodes: 127.0.0.1:26380,127.0.0.1:26382,127.0.0.1:26384