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

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

      

  • 相关阅读:
    C# Mongo Client 2.4.2创建索引
    MongoDB Driver:使用正确的姿势连接复制集
    C# Mongo Client 2.4.2判断是否存在表
    c# Mongodb批量更新
    c# Mongodb创建自增列
    class A where T:new()是什么意思
    Dapper Extensions中修改Dialect
    golang 中的 sizeof 以及 golang中的 union
    将c语言的结构体定义变成对应的golang语言的结构体定义,并将golang语言结构体变量的指针传递给c语言,cast C struct to Go struct
    golang 与 c语言 之间传递指针的规则提案
  • 原文地址:https://www.cnblogs.com/wangzhengyu/p/10621464.html
Copyright © 2011-2022 走看看