原创
SpringBoot集成Redis以及解决高并发问题
工程结构图:
提前说明:
注意:JavaBean必须实现序列化,不然数据无法存入Redis。
public class User implements Serializable
1.SpringBoot集成Redis实现缓存
首先需要引入SpringBoot的Redis依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
关键代码:
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
/**注入SpringBoot自动配置好的redisTemplate**/
//注意:spring boot帮我们注入的redisTemplate类,泛型里面只能写 <String, String>、<Object, Object>,不能一个String一个Object!
@Autowired
private RedisTemplate<Object,Object> redisTemplate;
@Override
public List<User> findAllUser() {
//字符串的序列化器(这里只将key序列化--->AllUser),为了在Redis管理工具更好看一点(AllUser不会出现前面的类似乱码的)
RedisSerializer redisSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(redisSerializer);
//查询缓存
List<User> userList = (List<User>) redisTemplate.opsForValue().get("AllUser");
if (userList == null){
//缓存为空,查询数据库
userList = userMapper.findAllUser();
//把查询出来的数据放入Redis中
redisTemplate.opsForValue().set("AllUser",userList);
}
return userList;
}
@Override
public User findUserById(Integer id) {
//字符串的序列化器(这里只将key序列化--->AllUser),为了在Redis管理工具更好看一点(AllUser不会出现前面的类似乱码的)
RedisSerializer redisSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(redisSerializer);
//查询缓存
User user = (User) redisTemplate.opsForValue().get("User");
if (user == null){
//缓存为空,查询数据库
user = userMapper.findUserById(id);
//把查询出来的数据放入到Redis中
redisTemplate.opsForValue().set("User",user);
}
return user;
}
}
总结思路:
1.字符串序列化(名字)。
2.查询Redis缓存,如果为空,查询数据库。
3.将查询出来的数据放入Redis缓存中。
4.返回结果。
思考:
如果一万个人同时访问(高并发条件下),上面的代码是否有什么不恰当?
2.高并发下SpringBoot集成Redis缓存的问题
关键代码:
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
/**注入SpringBoot自动配置好的redisTemplate**/
//注意:spring boot帮我们注入的redisTemplate类,泛型里面只能写 <String, String>、<Object, Object>,不能一个String一个Object!
@Autowired
private RedisTemplate<Object,Object> redisTemplate;
/**
* 测试高并发问题
* @param name
* @return
*/
@Override
public List<User> findUserByName(String name) {
//字符串的序列化器(这里只将key序列化--->AllUser),为了在Redis管理工具更好看一点(AllUser不会出现前面的类似乱码的)
RedisSerializer redisSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(redisSerializer);
List<User> userList = (List<User>) redisTemplate.opsForValue().get("findByLikeName");
if (userList == null){
synchronized (this){
//查询Redis缓存
userList = (List<User>) redisTemplate.opsForValue().get("findByLikeName");
if (userList == null){
//查询数据库
userMapper.findUserByName(name);
System.out.println("查询的数据库...");
//将查询的结果放入Redis缓存中
redisTemplate.opsForValue().set("findUserByName",userList);
}else {
System.out.println("查询的缓存...");
}
}
System.out.println("查询的缓存...");
}
return userList;
}
}
Controller:
@Controller
public class UserController {
@Autowired
private UserService userService;
/**
* 高并发问题
* @param name
* @return
*/
@RequestMapping("/findUserByName/{name}")
@ResponseBody
public List<User> findUserByName(@PathVariable("name") String name){
Runnable runnable = new Runnable() {
@Override
public void run() {
userService.findUserByName(name);
}
};
ExecutorService executorService = Executors.newFixedThreadPool(25);
for (int i = 0; i < 10000; i++) {
executorService.submit(runnable);
}
List<User> userList = userService.findUserByName(name);
return userList;
}
}
效果图:
可以看到查询数据的次数非常非常多,这样对数据库的压力十分大,甚至我查询不出结果!
3.解决高并发问题
关键代码:
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
/**注入SpringBoot自动配置好的redisTemplate**/
//注意:spring boot帮我们注入的redisTemplate类,泛型里面只能写 <String, String>、<Object, Object>,不能一个String一个Object!
@Autowired
private RedisTemplate<Object,Object> redisTemplate;
/**
* 测试解决高并发问题
* @param id
* @return
*/
@Override
public User findUserById(Integer id) {
//字符串的序列化器(这里只将key序列化--->AllUser),为了在Redis管理工具更好看一点(AllUser不会出现前面的类似乱码的)
RedisSerializer redisSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(redisSerializer);
//查询Redis缓存
User user = (User) redisTemplate.opsForValue().get("User");
//解决高并发问题:双重监测锁
if (user == null){
synchronized (this){
//查询Redis缓存
user = (User) redisTemplate.opsForValue().get("User");
if (user == null){
//缓存为空,查询数据库
user = userMapper.findUserById(id);
System.out.println("查询的数据库...");
//把查询出来的数据放入到Redis中
redisTemplate.opsForValue().set("findUserById",user);
}else {
System.out.println("查询的缓存...");
}
}
}else {
System.out.println("查询的缓存...");
}
return user;
}
}
Controller:
@Controller
public class UserController {
@Autowired
private UserService userService;
/**
* 测试解决高并发问题
* @param id
* @return
*/
@RequestMapping("/findUserById/{id}")
@ResponseBody
public User findUserById(@PathVariable("id") Integer id){
//多线程,该线程调用底层根据id查询学生的方法
Runnable runnable = new Runnable() {
@Override
public void run() {
userService.findUserById(id);
}
};
//多线程测试高并发条件下内网穿透问题
ExecutorService executorService = Executors.newFixedThreadPool(25); //线程池根据CPU来选择适当的值
for (int i = 0; i < 10000; i++) {
//提交线程runnable方法
executorService.submit(runnable);
}
User user = userService.findUserById(id);
return user;
}
}
效果图:
或者配置好Druid数据源:
发现只查询了一次数据库!
正文到此结束
- 本文标签: SpringBoot
- 本文链接: http://www.lzhpo.com/article/52
- 版权声明: 本文由lzhpo原创发布,转载请遵循《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》许可协议授权