1.注解方式使用 Redis 缓存
使用缓存有两个前置步骤
-
在
pom.xml
引入依赖<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 整合redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- springboot测试 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
-
在启动类上加注解
@EnableCaching
@SpringBootApplication @EnableCaching public class RedisApplication { public static void main(String[] args) { SpringApplication.run(RedisApplication.class, args); } }
常用的注解有以下几个@Cacheable、@CachePut、@CacheEvict
1.1 添加缓存
缓存的key就是配置在注解里面的值product::123,值是你方法的返回值,如果没有返回值,值就是org.springframework.cache.support.NullValue
在需要加缓存的方法上添加注解 @Cacheable(cacheNames = "product", key = "123")
,
cacheNames
和 key
都必须填,如果不填 key
,默认的 key
是当前的方法名,更新缓存时会因为方法名不同而更新失败。
如在订单列表上加缓存
@RequestMapping(value = "/list", method = RequestMethod.GET)
@Cacheable(cacheNames = "product", key = "123")
public List<Product> list() {
List<Product> products=new ArrayList<>();
for (int i = 0; i < 3; i++) {
Product product=new Product();
product.setId(i+1);
product.setName("第"+(i+1)+"件商品");
product.setPrice((double) ((i+1)*100));
products.add(product);
}
return products;
}
可能会报错,原因是对象未序列化。让对象实现 Serializable
方法即可。
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Product implements Serializable {
private Integer id;
private String name;
private Double price;
}
重启项目访问订单列表,在 rdm 里查看 Redis 缓存,有 product::123
说明缓存成功。
1.2 更新缓存
在需要更新缓存的方法上加注解: @CachePut(cacheNames = "product", key = "123")
注意
cacheNames
和key
要跟@Cacheable()
里的一致,才会正确更新。@CachePut()
和@Cacheable()
注解的方法返回值要一致
1.3 删除缓存
在需要删除缓存的方法上加注解:@CacheEvict(cacheNames = "product", key = "123")
,执行完这个方法之后会将 Redis 中对应的记录删除。
1.4 其他常用功能
-
cacheNames
也可以统一写在类上面,@CacheConfig(cacheNames = "product")
,具体的方法上就不用写啦。@RestController @CacheConfig(cacheNames = "product") public class ProdectController { }
-
Key 也可以动态设置为方法的参数
@GetMapping("/detail") @Cacheable(cacheNames = "product", key = "#id") public Product detail(@RequestParam("id") Integer id){ if (id==1){ return new Product(1,"电冰箱",20d); }else if (id==2){ return new Product(2,"洗衣机",30d); }else { return new Product(3,"彩电",40d); } }
如果参数是个对象,也可以设置对象的某个属性为 key。比如其中一个参数是 user 对象,key 可以写成
key="#user.id"
-
缓存还可以设置条件。
设置当 openid 的长度大于3时才缓存
@GetMapping("/detailOnCondition") @Cacheable(cacheNames = "product", key = "#id", condition = "#id > 2") public void detail(@RequestParam("id") String id){ System.out.println("id是"+id); }
还可以指定
unless
即条件不成立时缓存。#result
代表返回值,意思是当返回码不等于 0 时不缓存,也就是等于 0 时才缓存。@GetMapping("/detailOnConditionAndUnless") @Cacheable(cacheNames = "product", key = "#id", condition = "#id > 2", unless = "#result!= 0") public Integer detailOnConditionAndUnless(@RequestParam("id") Integer id){ if (id==3){ return 0; }else { return 1; } }
##2.RedisTemplate 使用 Redis 缓存
与使用注解方式不同,注解方式可以零配置,只需引入依赖并在启动类上加上 @EnableCaching
注解就可以使用;而使用 RedisTemplate 方式麻烦些,需要做一些配置。
2.1 Redis 配置
第一步还是引入依赖和在启动类上加上 @EnableCaching
注解。
然后在 application.yml
文件中配置 Redis
spring:
redis:
port: 6379
database: 0
host: 127.0.0.1
password:
jedis:
pool:
max-active: 8
max-wait: -1ms
max-idle: 8
min-idle: 0
timeout: 5000ms
然后写个 RedisConfig.java
配置类
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import java.net.UnknownHostException;
@Configuration
public class RedisConfig {
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<String, Object> redisTemplate(
RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(redisConnectionFactory);
template.setKeySerializer(jackson2JsonRedisSerializer);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashKeySerializer(jackson2JsonRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
@Bean
@ConditionalOnMissingBean(StringRedisTemplate.class)
public StringRedisTemplate stringRedisTemplate(
RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
Redis 的配置就完成了。
使用方式
package io.redis.demo;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
/**
* @Date: 2019/5/4 下午12:23
* @Version 1.0
*/
@SpringBootTest
@RunWith(SpringRunner.class)
public class RedisTemplateTest {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Test
public void test1(){
redisTemplate.opsForValue().set("name","zhangsan");
String name = (String)redisTemplate.opsForValue().get("name");
System.out.println(name);
}
@Test
public void test2(){
stringRedisTemplate.opsForValue().set("name","zhangsan");
String name = stringRedisTemplate.opsForValue().get("name");
System.out.println(name);
}
@Test
public void test3(){
redisTemplate.opsForHash().put("produce","1","电视机");
redisTemplate.opsForHash().put("produce","2","冰箱");
redisTemplate.opsForHash().put("produce","3","彩电");
redisTemplate.opsForHash().put("produce","4","自行车");
String name = (String) redisTemplate.opsForHash().get("produce", "4");
System.out.println(name);
}
@Test
public void test4(){
redisTemplate.opsForList().leftPush("name","zhangfei");
redisTemplate.opsForList().leftPush("name","liubei");
redisTemplate.opsForList().leftPush("name","guanyu");
List names = redisTemplate.opsForList().range("name", 0, -1);
for (Object name : names) {
System.out.println(name);
}
}
}