(一)、添加依赖,SpringBoot中已经将Redis引入进来,直接添加redis模块

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

(二)、配置Redis

redis:
    host: 127.0.0.1
    port: 6379
    database: 0  //redis数据库索引序号,标识使用哪个数据库
    password:    //默认没有
    jedis:       //连接池
      pool:
        max-active: 8    //最大连接数(使用负值表示没有限制)
        max-wait: -1ms   //连接池最大阻塞等待时间(使用负值表示没有限制)
        max-idle: 8      //连接池种最大空闲连接数
        min-idle: 0      //连接池种最小空闲连接数
    timeout: 3000ms      //连接超时时间毫秒

(三)、添加接口RedisService,用于定义一些常用的redis操作

/**
 * redis操作Service,
 * 对象和数组都以json形式进行存储
 * Created by macro on 2018/8/7.
 */
public interface RedisService {
    /**
     * 存储数据
     */
    void set(String key, String value);

    /**
     * 获取数据
     */
    String get(String key);

    /**
     * 设置超期时间
     */
    boolean expire(String key, long expire);

    /**
     * 删除数据
     */
    void remove(String key);

    /**
     * 自增操作
     * @param delta 自增步长
     */
    Long increment(String key, long delta);

}

(四)、添加RedisService实现类RedisServiceImpl

/**
 * redis操作Service的实现类
 * Created by macro on 2018/8/7.
 */
@Service
public class RedisServiceImpl implements RedisService {
    
    //注入RedisTemplate类,SpringBoot自动将其注入到了容器中了
    @Autowired
    private RedisTemplate stringRedisTemplate;

    @Override
    public void set(String key, String value) {
        stringRedisTemplate.opsForValue().set(key, value);
    }

    @Override
    public String get(String key) {
        return stringRedisTemplate.opsForValue().get(key);
    }

    @Override
    public boolean expire(String key, long expire) {
        return stringRedisTemplate.expire(key, expire, TimeUnit.SECONDS);
    }

    @Override
    public void remove(String key) {
        stringRedisTemplate.delete(key);
    }

    @Override
    public Long increment(String key, long delta) {
        return stringRedisTemplate.opsForValue().increment(key,delta);
    }
}

在SpringBoot中,如果没有自定义RedisTemplate的话,SpringBoot会自动往容器里注入一个默认的RedisTemplate,如果自定义了就使用的自定义的。

向redis缓存数据时会将数据进行序列化,

RedisTemplate默认使用JdkSerializationRedisSerializer进行序列化,即key, value需要实现Serializable接口。

StringRedisTemplate默认使用的是StringRedisSerializer序列化。这个bean的key,value都为String,所以要存储复杂数据时,要先将数据转换为String类型,一般转为json格式进行读取

(五)、自定义RedisTemplate

一般我们存取redis使用json格式的数据,为了存取方便,我们可以自定义序列化器来将数据自动使用json格式序列化。

可用fashjson工具提供的GenericFastJsonRedisSerializer来进行序列化

自定义并注入RedisTemplate

public class RedisConfig {
    /**
     * 重写Redis序列化方式,使用Json方式:
     * RedisTemplate默认使用的是JdkSerializationRedisSerializer,
     * 在此我们将自己配置RedisTemplate并定义使用fastjson提供的Serializer。
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory 
                                                               redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // 设置键(key)的序列化采用StringRedisSerializer。
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        // 设置值(Value)的序列化采用fastJson序列化
        redisTemplate.setValueSerializer(new GenericFastJsonRedisSerializer());
        return redisTemplate;
    }
}

(六)、使用声明式注解进行缓存

对于缓存的使用,Spring也提供了一组注解

其序列化是使用的默认的,所以在使用前需要进行配置

public class RedisConfig {
    /**
     * 重写Redis序列化方式,使用Json方式:
     * RedisTemplate默认使用的是JdkSerializationRedisSerializer,
     * 在此我们将自己配置RedisTemplate并定义使用fastjson提供的Serializer。
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory 
                                                               redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // 设置键(key)的序列化采用StringRedisSerializer。
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        // 设置值(Value)的序列化采用fastJson序列化
        redisTemplate.setValueSerializer(new GenericFastJsonRedisSerializer());
        return redisTemplate;
    }
    
    //使用注解进行缓存,配置序列化方式
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        GenericFastJsonRedisSerializer genericFastJsonRedisSerializer = new     
                                                        GenericFastJsonRedisSerializer();
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()            .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(genericFastJsonRedisSerializer))
                .disableCachingNullValues();
        RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
        return cacheManager;
    }
}

然后使用注解进行缓存

1.@Cacheable设置缓存,当缓存中没有这条key数据时就执行方法内容并进行缓存,下次调用方法就不会执行方法内容了,会自动在缓存中取数据

 参数解释

cacheNames:缓存的名称
key       :缓存中一条数据的key,可以自定义,也可以通过EL表达式用方法的参数。

//自定义key
@Cacheable(cacheNames = "product",key = "123")
public ProductInfo findById(String productInfoId) {
    return repository.findById(productInfoId).get();
}

//用方法的参数作为key
@Cacheable(cacheNames = "product",key = "#productInfoId")
public ProductInfo findById(String productInfoId) {
    return repository.findById(productInfoId).get();
}

//如果方法中参数为对象,还可用对象的属性
@Cacheable(cacheNames = "product",key = "#productInfo.productInfoId")
public ProductInfo findById(ProductInfo productInfo) {
    return repository.findById(productInfo.getProductInfoId).get();
}

keyGenerator:定义key生成的类,但注意和属性key的不能同时存在,上面 的例子使用默认的keyGenerator,对应spring的SimpleKeyGenerator

//使用自定义key生成器
@Cacheable(cacheNames="book3",  keyGenerator="myKeyGenerator")
public ProductInfo queryCacheableUseMyKeyGenerator(String id){
    .........
    return productInfo ;
}

//自定义key生成器,实现KeyGenerator接口,并实现generate方法
@Component
public class MyKeyGenerator implements KeyGenerator {
    @Override
    public Object generate(Object target, Method method, Object... params) {
        .......
        .......
        return 123456;
    }

}

sync:设置sync=true

                1. 如果缓存中没有数据,多个线程同时访问这个方法,则只有一个方法会执行到方法,其它方法需要等待;

                2. 如果缓存中已经有数据,则多个线程可以同时从缓存中获取数据

condition:判断条件,在所在方法调用前进行判断,如果为true就进行缓存,false就不缓存

unless :判断条件,在所在方法调用后进行判断,如果为true就不缓存,为false就进行缓存

condition和unless可同时使用

//判断条件condition实例
@Cacheable(cacheNames="book11",key="#id" condition="T(java.lang.Integer).parseInt(#id)<3")
public ProductInfo queryCacheableWithCondition(String id) {
      .........
      .........
      return productInfo;
}


//判断条件unless 实例
@Cacheable(cacheNames="book11",key="#id" unless ="T(java.lang.Integer).parseInt(#id)<3")
public ProductInfo queryCacheableWithCondition(String id) {
      .........
      .........
      return productInfo;
}

2.@CacheEvict,删除缓存数据

属性: allEntries ,默认为false,只删除key对应的数据;如果设置为true,则删除cacheNames=“product”中的所有数据

//删除缓存productInfo中的所有数据
@CacheEvict(cacheNames="productInfo", key="#id",allEntries=true)
public void updateBook(String id, String name){
     productInfoService.updateById(id);
}

//删除缓存productInfo中key为id的那条数据
@CacheEvict(cacheNames="productInfo", key="#id")
public void updateBook(String id, String name){
     productInfoService.updateById(id);
}

3.@CachePut,每次方法调用都会进行缓存替换,常用做更新数据操作。

//更新缓存中key为id的数据
@CachePut(cacheNames="productInfo", key="#id")
public ProductInfo queryUpdate(String id){
     ..........
     return productInfo;
}

4.@CacheConfig,可以用此注解在类上定义并设置类全局属性cacheNames,则此类中的所有方法上 @Cacheable的cacheNames默认都是此值。当然@Cacheable也可以重定义cacheNames的值

@CacheConfig(cacheName="produvt")
public class ProductServiceImpl implements ProductService {
    @Autowired
    private ProductInfoRepository repository;

    @Override
    @Cacheable(key = "123")
    public ProductInfo findById(String productInfoId) {
        return repository.findById(productInfoId).get();
    }
    //重定义cacheNames的值
    @Override
    @Cacheable(cacheNames = "product1111",key = "123")
    public ProductInfo findById(String productInfoId) {
        return repository.findById(productInfoId).get();
    }
}