redis 缓存


redis 缓存

 

作用:将数据缓存在redis数据库中,快速响应客户端请求,短时间内数据不一致,适用于对数据一致性要求不高的场景

 

缓存使用条件:

频繁查询的数据,对使用不频繁的数据可不用缓存

内存空间较磁盘小,大数据不宜使用缓存

适用于读多写少的场景,如果频繁写入,也不适宜使用缓存

 

spring 默认策略:

数据查询:先查询缓存,如果缓存里面有数据,直接返回数据;如果没有执行方法,返回方法数据,并将返回结果放入缓存

数据更新:执行方法,将方法返回结果放入缓存

数据删除:删除后端数据库与缓存中的数据

 

spring 默认策略可能导致的问题

                                       

缓存一致性:后端数据库里存储最新的数据,缓存里面存储旧的数据

解决方法:后端数据更新后,延时删除缓存

缓存查询时,使用分布式锁让一个线程去后端获取最新数据放入缓存,其余线程从缓存里面获取数据

如果不延时删除,可能存在此种情况导致缓存不一致:线程1查询时缓存刚好失效,去后端查询数据,线程2更新数据并删除,此时线程1将就数据放入缓存

 

延时删除可能会失败,解决方式:消息队列(rocketmq)有重试机制,可使用消息队列删除缓存;

监听bin-log,使用消息队列删除对应的缓存,这种方式可减少对应用程序的侵入


 

**********************

相关注解

 

@Cacheable:查询

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Cacheable {
    @AliasFor("cacheNames")
    String[] value() default {};

    @AliasFor("value")
    String[] cacheNames() default {};  //指定使用缓存的名称

    String key() default "";
    String keyGenerator() default "";

    String cacheManager() default "";
    String cacheResolver() default "";

    String condition() default "";
    String unless() default "";

    boolean sync() default false;
}

 

@CachePut:写入、更新

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface CachePut {
    @AliasFor("cacheNames")
    String[] value() default {};

    @AliasFor("value")
    String[] cacheNames() default {};  //指定使用缓存的名称

    String key() default "";
    String keyGenerator() default "";

    String cacheManager() default "";
    String cacheResolver() default "";

    String condition() default "";
    String unless() default "";
}

说明:将注解所在方法的返回值添加到缓存中,如果方法没有返回值且允许缓存空值,缓存的value为null

 

@CacheEvict:删除

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface CacheEvict {
    @AliasFor("cacheNames")
    String[] value() default {};

    @AliasFor("value")
    String[] cacheNames() default {};

    String key() default "";
    String keyGenerator() default "";

    String cacheManager() default "";
    String cacheResolver() default "";

    String condition() default "";
    boolean allEntries() default false;
    boolean beforeInvocation() default false;
}

 

缓存键key设置

#使用keyGenerator

@Component("keyGenerator")
public class CustomKeyGenerator implements KeyGenerator {
 
    @Override
    public Object generate(Object o, Method method, Object... objects) {
        StringBuilder builder=new StringBuilder();
        builder.append(o.getClass().getName()).append("::").append(method.getName());
 
        for(Object object:objects) {
            builder.append(":").append(object.toString());
        }
        return builder.toString();
    }
}


#示例
    @Cacheable(value = "custom",keyGenerator = "keyGenerator")
    @CachePut(value = "custom",keyGenerator = "keyGenerator")
    @CacheEvict(value = "custom",keyGenerator = "keyGenerator")


*********************
#使用key

    @Cacheable(value = "custom",key = "#id")                  //直接使用方法参数
    public User getById(Integer id) {


    @CachePut(value = "custom",key = "'user '+#user.name")    //使用方法参数属性
    public User save(User user) {

    @CachePut(value = "custom",key = "'user '+#result.id")    //使用方法返回结果属性
    public User save(User user) {


    @CacheEvict(value = "custom",key = "#id")                 //直接使用方法参数
    public void delete(Integer id) {

 

 

**********************

示例

 

*****************

config 层

 

RedisCacheConfig

@Configuration
@EnableCaching
public class RedisCacheConfig {

    @Bean
    public CacheManager initCacheManager(RedisConnectionFactory connectionFactory){
        RedisCacheConfiguration cacheConfiguration=RedisCacheConfiguration.defaultCacheConfig()
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new JdkSerializationRedisSerializer()))
                .entryTtl(Duration.ofMinutes(2L))
                .disableCachingNullValues();

        RedisCacheConfiguration defaultCacheConfiguration=RedisCacheConfiguration.defaultCacheConfig()
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new JdkSerializationRedisSerializer()))
                .entryTtl(Duration.ofMinutes(1L))
                .disableCachingNullValues();

        Map<String,RedisCacheConfiguration> map=new HashMap<>();
        map.put("custom",cacheConfiguration);
        map.put("default",defaultCacheConfiguration);

        return RedisCacheManager.builder(connectionFactory)
                .cacheDefaults(defaultCacheConfiguration)
                .withInitialCacheConfigurations(map)
                .transactionAware()
                .build();
    }
}

说明:配置多个缓存(default、custom),主要是为缓存设置不同的过期时间

 

CustomKeyGenerator:自定义key

@Component("keyGenerator")
public class CustomKeyGenerator implements KeyGenerator {

    @Override
    public Object generate(Object o, Method method, Object... objects) {
        StringBuilder builder=new StringBuilder();
        builder.append(o.getClass().getName()).append("::").append(method.getName());

        for(Object object:objects) {
            builder.append(":").append(object.toString());
        }
        return builder.toString();
    }
}

 

 

*****************

service 层

 

CustomUserService

public interface CustomUserService {

    User getById(Integer id);

    User save(User user);

    void delete(Integer id);
}

 

*****************

serviceImpl 层

 

CustomUserServiceImpl

@Service
public class CustomUserServiceImpl implements CustomUserService {

    @Resource
    private UserMapper userMapper;

    @Override
    @Cacheable(value = "custom",keyGenerator = "keyGenerator")
    public User getById(Integer id) {
        return userMapper.selectById(id);
    }

    @Override
    @CachePut(value = "default",keyGenerator = "keyGenerator")
    public User save(User user) {
        userMapper.insert(user);

        return user;
    }

    @Override
    @CacheEvict(value = "custom",keyGenerator = "keyGenerator")
    public void delete(Integer id) {
        userMapper.deleteById(id);
    }
}

 

 

*****************

controller 层

 

HelloController

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private CustomUserService userService;

    @RequestMapping("/get/{id}")
    public User get(@PathVariable("id") Integer id){
        return userService.getById(id);
    }

    @RequestMapping("/save")
    public User save(){
        User user=new User();
        user.setName("瓜田李下");
        user.setAge(24);

        userService.save(user);

        return user;
    }

    @RequestMapping("/delete")
    public User delete(){
        User user=userService.getById(2);
        userService.delete(user.getId());

        return user;
    }
}

 

 

**************************

使用测试

 

localhost:8080/user/save

          

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值