• redis学习八spring.data.redis、连接、序列化、high/low api


    redis学习八spring.data.redis、连接、序列化、high/low api

    redis 缓存击穿

    客户端访问redis,redis的下级还有有mysql,击穿发生在redis做缓存的时候
    ,redis中的key设置了过期时间或者过期策略(LRU和LFU),如果key过期了
    那么很多请求会直达数据库。【前置肯定是发生了高并发,且key过期了】
    在这里插入图片描述

    解决方案

    并发有了:要组织并发到达DB,redis没有请求的key【redis单进程单实例的】
    所有客户端增加一个逻辑,使用setnx()-》约等于是一把锁,所有的人去抢这把锁,
    只有获得所得去访问DB。
    整个流程是:
    先去getkey如果失败了以后,大家都去setnx,拿到锁的人去DB,其他的人则去随机等待。
    在这里插入图片描述
    产生问题:
    如果第一个人挂了,会产生让其他人一直等待【死锁】,所以可以设置锁的过期时间,
    但是这样会产生,如果第一个人没挂,但是锁超时了,其他的人来也超时了,【此时使用多线程一个线程取DB另一个线程去监控是否取回来,更新锁时间,但是会提高客户端代码逻辑复杂度】
    在这里插入图片描述

    缓存穿透

    从业务接收查询的是你系统根本不存在的数据,(缓存和数据库里面没有),这样会造成数据库压力变大

    解决方案:
    使用布隆过滤器:
    1、客户端包含布隆过滤器的算法,对客户端内存要求大
    2、客户端只包含算法,然后使用redis的bitmap来存,这样客户端是无状态的
    3、redis里面集成一个bloom的模块指令(算法数据都有,客户端比较简单)
    但是会有如下问题:
    1、不能删除(换成布谷鸟等布隆过滤器,设置一个空key【有key无value】)
    在这里插入图片描述

    缓存雪崩

    客户端访问redis,redis做缓存用,出现情况,大量的key同时失效,间接造成大量的访问到达DB。
    解决方案:
    随机过期时间:
    分为时点性无关【随机过期时间】
    时点性有关的【必须要零点去刷新DB的数据到内存】,则需要强依赖击穿的方案,在业务层里面
    加一个判断,零点延时(业务层只要到了十二点了就做一个延时,等待更新完毕)
    在这里插入图片描述

    分布式锁

    1、setnx
    2、过期时间
    3、多线程(守护线程)延长过期时间使用
    使用redisson 和zookeeper做分布式锁

    常用API

    jedis,多线程不安全,需要做池化技术
    ,如客户端1开启的事务未提交,客户端2的请求又来了,那么是拿不到结果的
    在这里插入图片描述

    基本API演示

    在这里插入图片描述
    在这里插入图片描述

    本地连接时配置
    在这里插入图片描述
    在这里插入图片描述
    redis常用操作:
    首先引入如下依赖:

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.2.7.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.example</groupId>
        <artifactId>demo</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>demo</name>
        <description>Demo project for Spring Boot</description>
        <properties>
            <java.version>1.8</java.version>
        </properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-json</artifactId>
            </dependency>
        </dependencies>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    </project>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    启动类通过如下方式去调用:

    @SpringBootApplication
    public class DemoApplication {
    
    	public static void main(String[] args) {
    		ConfigurableApplicationContext ctx = SpringApplication.run(DemoApplication.class, args);
    		TestRedis redis = ctx.getBean(TestRedis.class);
    		redis.testRedis();
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    @Autowired
        private RedisTemplate  redisTemplate;
    
        //这种方式redis的key是序列化了的
        @Autowired
        private StringRedisTemplate  stringRedisTemplate;
    
        @Autowired
        private ObjectMapper objectMapper;
    
        public void testRedis(){
    
            redisTemplate.opsForValue().set("hello01","china");
            System.out.println(redisTemplate.opsForValue().get("hello01"));
    
            RedisConnection conn = redisTemplate.getConnectionFactory().getConnection();
    
            conn.set("hello02".getBytes(),"test".getBytes());
            System.out.println(new String(conn.get("hello02".getBytes())));
    
    
            HashOperations<String, Object, Object> hash = stringRedisTemplate.opsForHash();
            hash.put("sean","name","lsd");
            hash.put("sean","age","22");
            System.out.println(hash.entries("sean"));
    
    
            Person p = new Person();
            p.setName("zhangsan");
            p.setAge(16);
            //value是个Integer,此处通过json的方式去转换
           stringRedisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
            //第二个参数是是否展开,就是说是否包含内部类
            Jackson2HashMapper jm = new Jackson2HashMapper(objectMapper, false);
            stringRedisTemplate.opsForHash().putAll("sean01",jm.toHash(p));
            Map map = stringRedisTemplate.opsForHash().entries("sean01");
            //转换取出的map
            Person per = objectMapper.convertValue(map, Person.class);
            System.out.println(per.getName());
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    也能自定义template:

    /**
     * 自定义template
     */
    @Configuration
    public class MyTemplate {
    
        @Bean
        public StringRedisTemplate ooxx(RedisConnectionFactory fc){
    
            StringRedisTemplate tp = new StringRedisTemplate(fc);
    
            tp.setHashValueSerializer(new Jackson2JsonRedisSerializer<Object>(Object.class));
            return  tp ;
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    @Component
    public class TestRedis {
    
        @Autowired
        private RedisTemplate  redisTemplate;
    
        //这种方式redis的key是序列化了的
        @Autowired
        @Qualifier("ooxx")
        private StringRedisTemplate  stringRedisTemplate;
    
        @Autowired
        private ObjectMapper objectMapper;
    
        public void testRedis(){
    
            redisTemplate.opsForValue().set("hello01","china");
            System.out.println(redisTemplate.opsForValue().get("hello01"));
    
            RedisConnection conn = redisTemplate.getConnectionFactory().getConnection();
    
            conn.set("hello02".getBytes(),"test".getBytes());
            System.out.println(new String(conn.get("hello02".getBytes())));
    
    
            HashOperations<String, Object, Object> hash = stringRedisTemplate.opsForHash();
            hash.put("sean","name","lsd");
            hash.put("sean","age","22");
            System.out.println(hash.entries("sean"));
    
    
            Person p = new Person();
            p.setName("zhangsan");
            p.setAge(16);
            //value是个Integer,此处通过json的方式去转换
           stringRedisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
            //第二个参数是是否展开,就是说是否包含内部类
            Jackson2HashMapper jm = new Jackson2HashMapper(objectMapper, false);
            stringRedisTemplate.opsForHash().putAll("sean01",jm.toHash(p));
            Map map = stringRedisTemplate.opsForHash().entries("sean01");
            //转换取出的map
            Person per = objectMapper.convertValue(map, Person.class);
            System.out.println(per.getName());
    
    
    
            stringRedisTemplate.convertAndSend("ooxx","hello");
    
            RedisConnection cc = stringRedisTemplate.getConnectionFactory().getConnection();
            cc.subscribe(new MessageListener() {
                @Override
                public void onMessage(Message message, byte[] pattern) {
                    byte[] body = message.getBody();
                    System.out.println(new String(body));
                }
            }, "ooxx".getBytes());
    
            while(true){
                stringRedisTemplate.convertAndSend("ooxx","hello  from wo zi ji ");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
            }
    
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
  • 相关阅读:
    共享办公室行业当前发展现状和未来发展前景
    【华为OD机试真题 python】 最大N个数与最小N个数的和【2022 Q4 | 100分】
    1-6月中国ADAS供应商占比9% 又一家零部件巨头全面布局智驾新赛道
    第19章 并发与竞争实验(iTOP-RK3568开发板驱动开发指南 )
    Spring 拦截器实现请求拦截与参数处理【拦截器(Interceptor)和过滤器(Filter)的区别】
    缓解缓存击穿的大杀器之---singleflight深入浅出
    数据结构的定义以及其相关概念
    程序员工作只能做到 45 岁吗?之后的路该怎么走?
    c++ int 精度计算问题
    DDD(领域驱动设计)
  • 原文地址:https://blog.csdn.net/lsdstone/article/details/126336762