• 练习二级缓存Reedis


    练习二级缓存Reedis

    1.创建一个maven项目

    配置基础pom.xml

    <!-- 父级项目 -->
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>1.5.7.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
    
    <!-- 属性设置 -->
    <properties>
    	 <!-- jdK版本 -->
        <java.version>1.8</java.version>
    </properties>
    
    <!-- 依赖关系 -->
    <dependencies>
        <!-- 测试 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- springmvc -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
    
    <!-- 编译 -->
    <build>
        <!-- 插件 -->
        <plugins>
            <!-- maven插件 -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
    
    2.使用简单的缓存

    ​ 1.同时引入支持二级缓存的jar

    <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>
    

    ​ 2.在启动类上加上@EnableCaching 开启二级缓存注解

    @SpringBootApplication
    @EnableCaching//打开二级缓存
    public class Application {
    	public static void main(String[] args) {
    		SpringApplication.run(Application.class, args);
    	}
    }
    

    ​ 3.在service实现层中

    @Override
    	//主要针对方法配置,能够根据方法的请求参数对其进行缓存
    	@Cacheable(value="users",key="methodName + targetClass")
    	public String show() {
    		System.out.println("show");
    		return "进入showc";
    	}
    
    @Override
    //清空缓存
    @CacheEvict(value="users",allEntries=true)
    public String evict() {
    	System.out.println("清空缓存");
    	return "清空缓存";
    }
    

    ​ 缓存注解解释

    名称 解释
    Cache 缓存接口,定义缓存操作。实现有:RedisCache、EhCacheCache、ConcurrentMapCache等
    CacheManager 缓存管理器,管理各种缓存(cache)组件
    @Cacheable 主要针对方法配置,能够根据方法的请求参数对其进行缓存
    @CacheEvict 清空缓存
    @CachePut 保证方法被调用,又希望结果被缓存。与@Cacheable区别在于是否每次都调用方法,常用于更新
    @EnableCaching 开启基于注解的缓存
    keyGenerator 缓存数据时key生成策略
    serialize 缓存数据时value序列化策略
    @CacheConfig 统一配置本类的缓存注解的属性

    @Cacheable/@CachePut/@CacheEvict 主要的参数

    名称 解释
    value 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 例如:@Cacheable(value=”mycache”) 或者@Cacheable(value={”cache1”,”cache2”}
    key 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合例如:@Cacheable(value=”testcache”,key=”#id”)
    condition 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存/清除缓存 例如:@Cacheable(value=”testcache”,condition=”#userName.length()>2”)
    unless 否定缓存。当条件结果为TRUE时,就不会缓存。@Cacheable(value=”testcache”,unless=”#userName.length()>2”)
    allEntries(@CacheEvict ) 是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存 例如:@CachEvict(value=”testcache”,allEntries=true)
    beforeInvocation(@CacheEvict) 是否在方法执行前就清空,缺省为 false,如果指定为 true,

    则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法
    执行抛出异常,则不会清空缓存 例如:@CachEvict(value=”testcache”,beforeInvocation=true)

    3.SpEL上下文数据

    Spring Cache提供了一些供我们使用的SpEL上下文数据,下表直接摘自Spring官方文档:

    名称 位置 描述 示例
    methodName root对象 当前被调用的方法名 #root.methodname
    method root对象 当前被调用的方法 #root.method.name
    target root对象 当前被调用的目标对象实例 #root.target
    targetClass root对象 当前被调用的目标对象的类 #root.targetClass
    args root对象 当前被调用的方法的参数列表 #root.args[0]
    caches root对象 当前方法调用使用的缓存列表 #root.caches[0].name
    Argument Name 执行上下文 当前被调用的方法的参数,如findArtisan(Artisan artisan),可以通过#artsian.id获得参数 #artsian.id
    result 执行上下文 方法执行后的返回值(仅当方法执行后的判断有效,如 unless cacheEvict的beforeInvocation=false) #result

    注意:

    1.当我们要使用root对象的属性作为key时我们也可以将“#root”省略,因为Spring默认使用的就是root对象的属性。 如 :
    @Cacheable(key = "targetClass + methodName +#p0")

    2.使用方法参数时我们可以直接使用“#参数名”或者“#p参数index”。 如:
    @Cacheable(value="users", key="#id")
    @Cacheable(value="users", key="#p0")

    SpEL提供了多种运算符

    类型 运算符
    关系 <,>,<=,>=,==,!=,lt,gt,le,ge,eq,ne
    算术 +,- ,* ,/,%,^
    逻辑 &&,!,and,or,not,between,instanceof
    条件 ?: (ternary),?: (elvis)
    正则表达式 matches
    其他类型 ?.,?[…],![…],[1],$[…]

    二级缓存作用: 当访问到开启二级缓存方法时,第一次访问配置了二级缓存的方法的返回值存在二级缓存之中(内存中),后面在访问这个方法时就会直接返回结果,不在执行方法

    4.项目配置Redis

    1.导入依赖

    就只需要这一个依赖!不需要spring-boot-starter-cache

     <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-data-redis</artifactId>
      </dependency>
    

    当你导入这一个依赖时,SpringBoot的CacheManager就会使用RedisCache。

    2.配置springboot的关于redis文件application.properties

    # Redis数据库索引(默认为0)
    spring.redis.database=0
    # Redis服务器地址
    spring.redis.host=127.0.0.1
    # Redis服务器连接端口
    spring.redis.port=6379
    # Redis服务器连接密码(默认为空)
    spring.redis.password=
    # 连接池最大连接数(使用负值表示没有限制)
    spring.redis.jedis.pool.max-active=8
    # 连接池最大阻塞等待时间(使用负值表示没有限制)
    spring.redis.jedis.pool.max-wait=-1
    # 连接池中的最大空闲连接
    spring.redis.jedis.pool.max-idle=8
    # 连接池中的最小空闲连接
    spring.redis.jedis.pool.min-idle=0
    # 连接超时时间(毫秒)
    spring.redis.timeout=5000
    

    3.配置Redis的缓存配置和序列化 CacheConfig类(要放在项目可以扫描到的包下面)

    @Configuration
    @EnableCaching
    public class CacheConfig{
    	/**
    	 * 配置缓存管理器RedisCacheManager
    	 * Redis采用key-value存储的存储方式,对key和value需要序列化
    	 * Redis的序列化方式由StringRedisSerializer,JdkSerializationRedisSerializer,GenericJackson2JsonRedisSerializer,GenericJackson2JsonRedisSerializer等
    	 * RedisCacheManager默认采用StringRedisSerializer序列化key,JdkSerializationRedisSerializer序列化value
    	 * @param redisConnectionFactory
    	 * @return
    	 */
    	@Bean
    	public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
    //		StringRedisSerializer序列器:
    //		优点:开发者友好,轻量级,效率也比较高
    //		缺点:只能序列化String类型,如果key使用该序列化器,则key必须为String类型
    		RedisSerializer<String> redisSerializer = new StringRedisSerializer();
    		
    //		jdkSerializationRedisSerializer序列化器:RestTemplate类默认的序列化方式,如果指定序列化器,则为它
    //		优点:反序列化时不需要提供类型信息(class)
    //		缺点:1、首先它要求存储的对象都必须实现java.io.Serializable接口,比较笨重
    //			  2、其次,他存储的为二进制数据,这对开发者是不友好的
    //			  3、序列化后的结果非常庞大,是JSON格式的5倍左右,这样就会消耗redis服务器的大量内存。		
    //		ClassLoader loader = this.getClass().getClassLoader();
    //		JdkSerializationRedisSerializer jdkSerializationRedisSerializer = new JdkSerializationRedisSerializer(loader);
    		
    //		Jackson2JsonRedisSerializer序列化器:把一个对象以Json的形式存储,效率高且对调用者友好
    //		优点:速度快,序列化后的字符串短小精悍,不需要存储对象实现java.io.Serializable接口
    //		缺点:那就是此类的构造函数中有一个类型参数,必须提供要序列化对象的类型信息(.class对象),反序列化用到了该类型信息
    //		Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
    //		ObjectMapper objectMapper = new ObjectMapper();
    //		objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    		
    //		GenericJackson2JsonRedisSerializer序列化器:基本和上面的Jackson2JsonRedisSerializer功能差不多,使用方式也差不多,
    //		但不需要提供类型信息,推荐使用
    		GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
    		RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
    				.entryTtl(Duration.ofMinutes(10))	//设置失效时间
    				.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
    				.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(genericJackson2JsonRedisSerializer));
    		
    
    		RedisCacheManager redisCacheManager = RedisCacheManager.builder(redisConnectionFactory)
    				.cacheDefaults(config)
    				.build();
    		
    		return redisCacheManager;
    	}
    	
    	@Bean
    	public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
    		RedisTemplate<String, Object> template = new RedisTemplate<>();
    		template.setConnectionFactory(redisConnectionFactory);
    		GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();		
    		template.setKeySerializer(new StringRedisSerializer());
    		template.setValueSerializer(genericJackson2JsonRedisSerializer);		
    		template.setHashKeySerializer(new StringRedisSerializer());
    		template.setHashValueSerializer(genericJackson2JsonRedisSerializer);
    		template.afterPropertiesSet();
    		return template;
    	}
    
    }
    

    配置完以上步骤,cache的缓存在本机的数据就可以存储在Redis上

    例1:
    //servlet实现层
    //主要针对方法配置,能够根据方法的请求参数对其进行缓存
    	@Cacheable(value="users",key="methodName + targetClass + #p0") // "#p0"表示方法参数列表的第一个参数
    	public String show(String id) {
    		System.out.println("进入show");
    		return "进入showid:"+id;
    	}
    
    //controller层
    @RequestMapping("show")
    @ResponseBody
    public String show(String id) {
    	return testServlet.show(id);
    }
    

    在浏览器请求接口为:http://127.0.0.1:8080/show?id=0

    在查看Redis中

    同时修改value的值

    再次请求接口http://127.0.0.1:8080/show?id=0

    就会发现我们由于没有清除缓存,后台是直接获取的缓存数据没有在执行这个方法,同时在项目中也会导致缓存与数据库双写不一致。


    1. ↩︎

  • 相关阅读:
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
  • 原文地址:https://www.cnblogs.com/A-Nan-q/p/14337754.html
Copyright © 2020-2023  润新知