[Redis] - 高并发下Redis缓存穿透解决
高并发情况下,可能都要访问数据库,因为同时访问的方法,这时需要加入同步锁,当其中一个缓存获取后,其它的就要通过缓存获取数据.
方法一: 在方法上加上同步锁 synchronized
//加同步锁,解决高并发下缓存穿透
@Test
public synchronized void getMyUser(){
//字符串的序列化器 redis
RedisSerializer redisSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(redisSerializer);
//查询缓存
MyUser myUser = (MyUser) redisTemplate.opsForValue().get("myUser");
if(null == myUser){
System.out.println("当缓存没有myUser时显示.");
//缓存为空,查询数据库
myUser = myUserMapper.selectByPrimaryKey(1l);
//把数据库查询出来的数据放入redis
redisTemplate.opsForValue().set("myUser",myUser);
}
System.out.println(myUser);
}
方法二: 使用双层检测锁, 效率高于方法一.
@Test
public void getMyUser(){
//字符串的序列化器 redis
RedisSerializer redisSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(redisSerializer);
//查询缓存
MyUser myUser = (MyUser) redisTemplate.opsForValue().get("myUser"); //双层检测锁
if(null == myUser){
synchronized(this){
myUser = (MyUser) redisTemplate.opsForValue().get("myUser");
if(null == myUser){
System.out.println("当缓存没有myUser时显示.");
//缓存为空,查询数据库
myUser = myUserMapper.selectByPrimaryKey(1l);
//把数据库查询出来的数据放入redis
redisTemplate.opsForValue().set("myUser",myUser);
}
}
} System.out.println(myUser);
}
进行高并发测试:
package com.ykmimi.job.controller; import com.ykmimi.job.bean.MyUser;
import com.ykmimi.job.mapper.MyUserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; @RestController
public class MyUserController { @Autowired
private RedisTemplate<Object,Object> redisTemplate;
@Resource
private MyUserMapper myUserMapper; public Integer insertNew(){ return 0;
} @RequestMapping("/getMyUserTest")
public void getMyUserTest(){
//线程,该线程调用底层查询MyUser的方法
Runnable runnable = new Runnable() {
@Override
public void run() {
getMyUser();
}
}; //多线程测试一下缓存穿透的问题
ExecutorService executorService = Executors.newFixedThreadPool(25);
for(int i=0;i<10000;i++){
executorService.submit(runnable);
} } public void getMyUser(){
//字符串的序列化器 redis
RedisSerializer redisSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(redisSerializer);
//查询缓存
MyUser myUser = (MyUser) redisTemplate.opsForValue().get("myUser"); //双层检测锁
if(null == myUser){
System.out.println("当缓存没有myUser时显示.没有进入同步锁");
synchronized(this){
myUser = (MyUser) redisTemplate.opsForValue().get("myUser");
if(null == myUser){
System.out.println("当缓存没有myUser时显示.已经进入同步锁");
//缓存为空,查询数据库
myUser = myUserMapper.selectByPrimaryKey(1l);
//把数据库查询出来的数据放入redis
redisTemplate.opsForValue().set("myUser",myUser);
}
}
} System.out.println(myUser);
} }
线程池中不要特别大的线程,
随后看打印输出:
当缓存没有myUser时显示.没有进入同步锁
当缓存没有myUser时显示.没有进入同步锁
当缓存没有myUser时显示.没有进入同步锁
当缓存没有myUser时显示.没有进入同步锁
当缓存没有myUser时显示.没有进入同步锁
当缓存没有myUser时显示.没有进入同步锁
当缓存没有myUser时显示.没有进入同步锁
当缓存没有myUser时显示.没有进入同步锁
当缓存没有myUser时显示.没有进入同步锁
当缓存没有myUser时显示.没有进入同步锁
当缓存没有myUser时显示.没有进入同步锁
当缓存没有myUser时显示.没有进入同步锁
当缓存没有myUser时显示.没有进入同步锁
当缓存没有myUser时显示.没有进入同步锁
当缓存没有myUser时显示.没有进入同步锁
当缓存没有myUser时显示.没有进入同步锁
当缓存没有myUser时显示.没有进入同步锁
当缓存没有myUser时显示.没有进入同步锁
当缓存没有myUser时显示.没有进入同步锁
当缓存没有myUser时显示.没有进入同步锁
当缓存没有myUser时显示.没有进入同步锁
当缓存没有myUser时显示.没有进入同步锁
当缓存没有myUser时显示.没有进入同步锁
当缓存没有myUser时显示.没有进入同步锁
当缓存没有myUser时显示.没有进入同步锁
当缓存没有myUser时显示.已经进入同步锁
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@b49b283] was not registered for synchronization because synchronization is not active
2019-01-01 17:10:51.616 INFO 19540 --- [ool-1-thread-14] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2019-01-01 17:10:51.747 INFO 19540 --- [ool-1-thread-14] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
JDBC Connection [HikariProxyConnection@1935473697 wrapping com.mysql.cj.jdbc.ConnectionImpl@4bc0a38] will not be managed by Spring
==> Preparing: select id, user_id, open_id, user_name, user_phone, location from my_user where id = ?
==> Parameters: 1(Long)
<== Columns: id, user_id, open_id, user_name, user_phone, location
<== Row: 1, 111, 111, 123, 111, t
<== Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@b49b283]
MyUser(id=1, userId=111, openId=111, userName=123, userPhone=111, location=t)
MyUser(id=1, userId=111, openId=111, userName=123, userPhone=111, location=t)
MyUser(id=1, userId=111, openId=111, userName=123, userPhone=111, location=t)
MyUser(id=1, userId=111, openId=111, userName=123, userPhone=111, location=t)
MyUser(id=1, userId=111, openId=111, userName=123, userPhone=111, location=t)
MyUser(id=1, userId=111, openId=111, userName=123, userPhone=111, location=t)
MyUser(id=1, userId=111, openId=111, userName=123, userPhone=111, location=t)
MyUser(id=1, userId=111, openId=111, userName=123, userPhone=111, location=t)
MyUser(id=1, userId=111, openId=111, userName=123, userPhone=111, location=t)
MyUser(id=1, userId=111, openId=111, userName=123, userPhone=111, location=t)
MyUser(id=1, userId=111, openId=111, userName=123, userPhone=111, location=t)
MyUser(id=1, userId=111, openId=111, userName=123, userPhone=111, location=t)
MyUser(id=1, userId=111, openId=111, userName=123, userPhone=111, location=t)
MyUser(id=1, userId=111, openId=111, userName=123, userPhone=111, location=t)
MyUser(id=1, userId=111, openId=111, userName=123, userPhone=111, location=t)
MyUser(id=1, userId=111, openId=111, userName=123, userPhone=111, location=t)
MyUser(id=1, userId=111, openId=111, userName=123, userPhone=111, location=t)
MyUser(id=1, userId=111, openId=111, userName=123, userPhone=111, location=t)
MyUser(id=1, userId=111, openId=111, userName=123, userPhone=111, location=t)
MyUser(id=1, userId=111, openId=111, userName=123, userPhone=111, location=t)
MyUser(id=1, userId=111, openId=111, userName=123, userPhone=111, location=t)
MyUser(id=1, userId=111, openId=111, userName=123, userPhone=111, location=t)
MyUser(id=1, userId=111, openId=111, userName=123, userPhone=111, location=t)
MyUser(id=1, userId=111, openId=111, userName=123, userPhone=111, location=t)
...
...
可以看到多个并发同时访问方法时,只有一个进入同步锁查询了数据库,其它还是通过缓存获取数据.
[Redis] - 高并发下Redis缓存穿透解决的更多相关文章
- php结合redis高并发下,悲观锁解决数据二次写入
悲观锁 在悲观锁的情况下,为了保证事务的隔离性,就须要一致性锁定读.读取数据时给加锁,其他事务无法改动这些数据.改动删除数据时也要加锁,其他事务无法读取这些数据. 在做数据缓存的时候,通常都是把数据从 ...
- 高并发下的缓存架构设计演进及redis常见的缓存应用异象解决方案
待总结 缓存穿透 缓存击穿 缓存雪崩等
- Redis高级应用解析:缓存穿透、击穿、雪崩
1 背景 像我们去面试一些大公司的时候,就会遇到一些关于缓存的问题.可能很多同学都是接触过,多多少少了解一些,但是如果没有好好记录这些内容,不熟练精通的话,在真正面试的时候,就很难答出来了. 在我们的 ...
- 高并发下redis
1.================================================================================================== ...
- redis高可用、redis集群、redis缓存优化
今日内容概要 redis高可用 redis集群 redis缓存优化 内容详细 1.redis高可用 # 主从复制存在的问题: 1 主从复制,主节点发生故障,需要做故障转移,可以手动转移:让其中一个sl ...
- Redis高可用方案----Redis主从+Sentinel+Haproxy
安装环境 这里使用三台服务器,每台服务器上开启一个redis-server和redis-sentinel服务,redis-server端口为6379,redis-sentinel的端口为26379. ...
- 高并发下redis缓存穿透问题解决方案
一.使用场景 我们在日常的开发中,经常会遇到查询数据列表的问题,有些数据是不经常变化的,如果想做一下优化,在提高查询的速度的同时减轻数据库的压力,那么redis缓存绝对是一个好的解决方案. 二.需求 ...
- redis缓存穿透解决办法--排它锁
- 高并发下Redis如何保持数据一致性(避免读后写)
通常意义上我们说读后写是指针对同一个数据的先读后写,且写入的值依赖于读取的值. 关于这个定义要拆成两部分来看,一:同一个数据:二:写依赖于读.(记住这个拆分,后续会用到,记为定义一.定义二)只有当这两 ...
随机推荐
- 关于HttpServletRequest报红叉的解决办法
今天导入项目的时候,发现报错了,如题.然后找到了解决办法 解决方法:鼠标右击项目工程——>Build Path——>点击comfigure Build Path进入----->选择j ...
- android 操作SD卡上的文件
(1)说明:操作SD卡上的文件须要增加下面权限 在SD卡上创建和删除文件权限 <uses-permission android:name="android.permission.M ...
- CMSPRESS-PHP无限级分类
原博文地址:http://blog.sina.com.cn/s/blog_75ad10100101mrv0.html 当你学习php无限极分类的时候,大家都觉得一个字“难”我也觉得很难,所以,现在都还 ...
- [py][mx]django分页第三方模块django-pure-pagination
前台的这些数据都是从后台取来的 分页模块django-pure-pagination - 一款基于django pagination封装的更好用的分页模块 https://github.com/jam ...
- PAT 1034 Head of a Gang[难][dfs]
1034 Head of a Gang (30)(30 分) One way that the police finds the head of a gang is to check people's ...
- checkbox选择
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- HTTP请求返回状态码详解
当用户试图通过 HTTP 访问一台正在运行 Internet 信息服务 (IIS) 的服务器上的内容时,IIS 返回一个表示该请求的状态的数字代码.状态代码可以指明具体请求是否已成功,还可以揭示请求失 ...
- jQ live用法
我们给元素绑定单击事件.用得最多的都是$("#id").click(function(){}); 但我们动态添加的元素.这样绑定是不行的.必须借助live $("#id ...
- 015-awk
1.awk的处理方式: 一次处理一行. 对每行可以进行切片处理,针对字段处理.2.awk的格式: awk BEGIN{循环之前初始化} [options] 'command' END{循环之后结尾} ...
- 浏览器css hack
(1)*: IE6+IE7都能识别*,而标准浏览器FF+IE8是不能识别*的; (2)!important: 除IE6不能识别 !important外, FF+IE8+IE7都能识别!import ...