[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如何保持数据一致性(避免读后写)
通常意义上我们说读后写是指针对同一个数据的先读后写,且写入的值依赖于读取的值. 关于这个定义要拆成两部分来看,一:同一个数据:二:写依赖于读.(记住这个拆分,后续会用到,记为定义一.定义二)只有当这两 ...
随机推荐
- python中执行shell命令行read结果
+++++++++++++++++++++++++++++ python执行shell命令1 os.system 可以返回运行shell命令状态,同时会在终端输出运行结果 例如 ipython中运行如 ...
- HBase-0.95.1源码分析之split
split操作执行的是将HBase中较大的Region分为两个.因为split比较耗时,因此split是在独立的线程中完成的,相关类是CompactSplitThread. 首先,CompactSpl ...
- IO操作文件的复制与删除
import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IO ...
- sklearn总览
- JS 转整型
1.丢弃小数部分,保留整数部分 js:parseInt(7/2) 2.向上取整,有小数就整数部分加1 js: Math.ceil(7/2) 3,四舍五入. js: Math.round(7/2) 4, ...
- C++编译器模板机制剖析
思考:为什么函数模板可以和函数重载放在一块.C++编译器是如何提供函数模板机制的? 一.编译器编译原理 什么是gcc gcc(GNU C Compiler)编译器的作者是Richard Stallma ...
- Hdu dp
4856 这题说的是给了一个图 这个图有很多的隧道每个隧道是单向的 只能从一个入口进入从另一个入口出来 要求计算出走完这些隧道花的总时间 因为这个图是一个网格行的然后 先用bfs算出隧道的出口到每个隧 ...
- Linux(CentOS)下同时启动两个tomcat
问题背景:在配置nginx时,配置了两个tomcat,tomcat01和tomcat02,改了tomcat02中server.xml的端口,可是还是启动不起来. 解决方法: 一.编辑环境变量: 1 v ...
- SVN版本服务器搭建
windows: https://blog.csdn.net/lu1024188315/article/details/74082227 SVN 的下载地址如下 http://torto ...
- 教你如何在linux下查看服务是否已经启动或者关闭
1. # ps aux | grep 服务名称(ps 的参数是可以颠倒使用没问题) 2. # netstat -tunple | grep 服务端口 3.bind() 80 in using 代表的含 ...