《springboot》 @Cacheable、@CachePut、@CacheEvict, redis

 SpringBoot 整合缓存Cacheable实战详细使用

https://www.jianshu.com/p/075da3070186

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

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

 

import java.time.Duration;

import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

/**
 * 
 * @author guokaige
 *
 */
@Configuration
@EnableCaching 
public class RedisConfig extends CachingConfigurerSupport {

	public static final int EXPIRE_SECONDS = 60 * 60 * 3;
	public static final int MY_EXPIRE_SECONDS = 60 * 10;

	@Bean
	@Override
	public KeyGenerator keyGenerator() {
		return new RedisKeyGenerator();
	}

	@Bean
	@Primary
	public CacheManager cacheManager(RedisConnectionFactory factory) {
		return new RedisCacheManager(RedisCacheWriter.nonLockingRedisCacheWriter(factory),
				// 默认策略,未配置的 key 会使用这个
				this.getRedisCacheConfigurationWithTtl(RedisConfig.EXPIRE_SECONDS));
	}


	/**
	 * 设置缓存过期时间
	 * 
	 * @param seconds
	 * @return
	 */
	private RedisCacheConfiguration getRedisCacheConfigurationWithTtl(Integer seconds) {
		RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
		redisCacheConfiguration = redisCacheConfiguration.entryTtl(Duration.ofSeconds(seconds));
		return redisCacheConfiguration;
	}


    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        template.setKeySerializer(getSerializer());
        template.setValueSerializer(getSerializer());
        template.setHashKeySerializer(getSerializer());
        template.setHashValueSerializer(getSerializer());

        template.afterPropertiesSet();
        return template;
    }
    
    @SuppressWarnings({ "unchecked", "rawtypes", "deprecation" })
	private Jackson2JsonRedisSerializer getSerializer() {
        // 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
		Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper mapper = new ObjectMapper();
        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 解决jackson2无法反序列化LocalDateTime的问题
        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        mapper.registerModule(new JavaTimeModule());
        mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        serializer.setObjectMapper(mapper);
        return serializer;
    }

}

import org.springframework.cache.interceptor.KeyGenerator;

/**
 * 
 * @author guokaige
 *
 */
public class RedisKeyGenerator implements KeyGenerator{

	@Override
	public Object generate(Object target, Method method, Object... params) {
		StringBuilder sb = new StringBuilder();
		sb.append(target.getClass().getName());
		sb.append(method.getName());
		for (Object obj : params) {
			sb.append(obj.toString());
		}
		return sb.toString();
	}
}

@Cacheable

@Cacheable 能够根据方法的请求参数对其结果进行缓存.

value属性是必须指定的,其表示当前方法的返回值是会被缓存在哪个Cache上的,对应Cache的名称。

key属性是用来指定Spring缓存方法的返回结果时对应的key的。该属性支持SpringEL表达式。当我们没有指定该属性时,Spring将使用默认策略生成key。


@Cacheable(value="findTree")  //缓存名叫 findTree
public List<OrganZtreeNodes> findTree(String orgName) {	
	List<Organ> list= organDao.findAll();
	return list;
}


@Cacheable(value="findTree", key="#orgName")  //缓存名叫 findTree
public List<OrganZtreeNodes> findTree(String orgName) {	
	List<Organ> list= organDao.findAll();
	return list;
}

@CachePut

@CachePut 这个注释可以确保方法在执行前不会去检查缓存中是否存在,而是每次都会执行该方法,并将执行结果覆盖到指定的缓存。

@CachePut(value="accountCache",key="#account.getName()")// 更新accountCache 缓存中当前用户数据
public Account updateAccount(Account account) { 
  return updateDB(account); 
}

@CacheEvict

@CachEvict 的作用 主要针对方法配置,能够根据一定的条件对缓存进行清空

@CacheEvict(value="accountCache",key="#account.getName()")// 更新accountCache 当前用户缓存 
public void updateAccount(Account account) {
   updateDB(account); 
} 
 
@CacheEvict(value="accountCache",allEntries=true)// 清空accountCache 所有缓存
public void reload() {
   reloadAll()
}
 
@Cacheable(value="accountCache",condition="#userName.length() <=4") // 缓存accountCache 用户名长度小于4的数据更新
public Account getAccountByName(String userName) { 
 // 方法内部实现不考虑缓存逻辑,直接实现业务
 return getFromDB(userName); 
}

@Caching

@Caching注解来讲,如果有两种不同的需求,都是放在同一个方法上,这种需求如果只是使用@CacheEvict或者@CachePut是无法实现,因为他们不能多样化的作用在同一个方法上。可以使用

 @Caching(evict = { @CacheEvict(value = "cache1", allEntries = true),
                    @CacheEvict(value = "cache2", allEntries = true),
                    @CacheEvict(value = "cache3", allEntries = true)} )

以上可以批量删除一些缓存

 模糊匹配删除

如果批量删除的cache比较多,  就需要我们统一规划缓存vaule和key

根据经验来说:

1.缓存value 首先需指明是哪个entity的缓存,末尾拼接Cache,

userListCache

2.然后指明范围

_allEnable

3.参数

_userName=张三

4.最后指明用途,或者方法名

_searchUser

userListCache_allEnable_userName=张三_searchUser

@Cacheable(value = "userListCache", key = "'_allEnable_userName='+#userName+'_searchUser' ")

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface CacheRemove {
 
    /**
     * 需要清除的大类 例如 autocms 所有缓存
     *
     * @return
     */
    String value() default "";
 
 
    /**
     * 需要清除的具体的额类型
     *
     * @return
     */
    String[] key() default {};
}

@Component
@Aspect
public class CacheRemoveAspect {
 
    Logger logger = LoggerFactory.getLogger(this.getClass());
 
    @Resource(name = "redisTemplate")
    RedisTemplate<String, String> redisTemplate;
 
    //截获标有@CacheRemove的方法
    @Pointcut(value = "(execution(* *.*(..)) && @annotation(com.topsoft.aaf.common.cache.CacheRemove))")
    private void pointcut() {
    }
 
    /**
     * 正则匹配删除缓存
     * @param joinPoint
     */
    @AfterReturning(value = "pointcut()")
    private void process(JoinPoint joinPoint) {
        //获取被代理的类
        Object target = joinPoint.getTarget();
        //获取切入方法的数据
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //获取切入方法
        Method method = signature.getMethod();
        //获得注解
        CacheRemove cacheRemove = method.getAnnotation(CacheRemove.class);
 
        if (cacheRemove != null) {
            //清除当前类的缓存
            cleanRedisCache("*" + target.getClass().toString() + "*");
 
            String value = cacheRemove.value();
            if (!value.equals("")) {
                //缓存的项目所有redis业务部缓存
                cleanRedisCache("*" + value + "*");
            }
            //需要移除的正则key
            String[] keys = cacheRemove.key();
            for (String key : keys) {
                //指定清除的key的缓存
                cleanRedisCache("*" + key + "*");
            }
        }
    }
 
    private void cleanRedisCache(String key) {
        if (key != null) {
            Set<String> stringSet = redisTemplate.keys(key);
            redisTemplate.delete(stringSet);//删除缓存
            logger.info("清除 " + key + " 缓存");
        }
    }
}

参考Spring缓存注解@Cacheable、@CacheEvict、@CachePut使用 - fashflying - 博客园

redis 下载

Redis Windows 64位下安装Redis详细教程_创客公元的博客-CSDN博客_redis64

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值