zoukankan      html  css  js  c++  java
  • 解决高并发下的缓存穿透问题

      目前我们针对高并发场景,这种问题很常见,一般有如下两种解决方式:

      一:在方法上加上同步锁 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);
        }

      二:使用双重检测锁(常用)

      

     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);
        }

      三:进行高并发测试

      

    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);
        }
    
    
    }

      住:线程池中不要特别大的线程

      

  • 相关阅读:
    Java后端WebSocket的Tomcat实现
    Shiro session和Spring session一样吗?
    HTTP请求类
    JSP页面中的时间显示问题
    Oracle在linux中相关设置操作
    关于BigDecimal类型在jsp页面中进行除法运算问题
    Spring与Redis的实现
    gson介绍
    busybox介绍
    vsftp中426 Failure writing network stream的错误解决
  • 原文地址:https://www.cnblogs.com/wangzhengyu/p/10621464.html
Copyright © 2011-2022 走看看