[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如何保持数据一致性(避免读后写)
通常意义上我们说读后写是指针对同一个数据的先读后写,且写入的值依赖于读取的值. 关于这个定义要拆成两部分来看,一:同一个数据:二:写依赖于读.(记住这个拆分,后续会用到,记为定义一.定义二)只有当这两 ...
随机推荐
- Android(一) 动态菜单
1.android的一个activity可以再选中某项之后按menu键弹出特定的菜单,也就是动态菜单.动态菜单的实现是靠menu类中的addIntentOptions函数实现的,具体的声明如下: in ...
- Java-mybatis-一次执行多条SQL语句
mysql数据库 1.修改数据库连接参数加上allowMultiQueries=true,如: hikariConfig.security.jdbcUrl=jdbc:mysql://xx.xx.xx: ...
- [LeetCode] 680. Valid Palindrome II_Easy tag: Two Pointers
Given a non-empty string s, you may delete at most one character. Judge whether you can make it a pa ...
- 关闭Oracle 11g的DPR特性
关闭Oracle 11g的DPR(Direct Path Read)特性 查看event参数值: SQL> show parameter event NAME TYPE VALUE ------ ...
- 安装PHP及Memcache扩展
安装PHP及Memcache扩展 地址:http://blog.csdn.net/poechant/article/details/6802312 1. 下载 (1)libevent 官方网页:h ...
- 后台维护常用SQL
OU.库存组织与子库存 select hou.organization_id ou_org_id, --org_id hou.name ou_name, --ou名称 ood.organization ...
- js文本框字数限制
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...
- Object-C-Foundation-NSNuber
NSNumber 是一个数值类型封装起来的数值. 装箱:基础类型->对象类型 NSNumber *number=[NSNumber numberWithInt:12]; 拆箱:对象类型-> ...
- BabelMap 12.0.0.1 汉化版(2019年3月11日更新)
软件简介 BabelMap 是一个免费的字体映射表工具,可辅助使用<汉字速查>程序. 该软件可使用系统上安装的所有字体浏览 Unicode 中的十万个字符,还带有拼音及部首检字法,适合文献 ...
- 论文笔记:语音情感识别(四)语音特征之声谱图,log梅尔谱,MFCC,deltas
一:原始信号 从音频文件中读取出来的原始语音信号通常称为raw waveform,是一个一维数组,长度是由音频长度和采样率决定,比如采样率Fs为16KHz,表示一秒钟内采样16000个点,这个时候如果 ...