SpringBoot中使用Redis_Firm陈的博客-CSDN博客_springboot使用redis
springboot使用redis(从配置到实战) - Python研究者 - 博客园
24-springboot操作redis - 不是孩子了 - 博客园
SpringBoot使用redis-阿里云开发者社区
·
·
添加Redis依赖包:
org.springframework.boot
spring-boot-starter-data-redis
·
·
配置Redis数据库连接,在application.properties中配置redis数据库连接信息,如下:
#redis配置
#Redis服务器IP地址
spring.redis.host=127.0.0.1
#Redis服务器端口号
spring.redis.port=6379
#Redis数据库索引(默认为0)
spring.redis.database=0
#Jedis连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=50
#Jedis连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=3000
#Jedis连接池中的最大空闲连接数
spring.redis.jedis.pool.max-idle=20
#Jedis连接池中的最小空闲连接数
spring.redis.jedis.pool.min-idle=2
#连接超时时间(毫秒)
spring.redis.timeout=5000
·
·
创建RedisConfig文件:
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import ...
@EnableCaching
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.timeout}")
private int timeout;
@Value("${spring.redis.pool.max-idle}")
private int maxIdle;
@Value("${spring.redis.pool.max-wait}")
private long maxWaitMillis;
/**
* 返回一个Jedis连接池
*/
@Bean
public JedisPool redisPoolFactory() {
Logger.getLogger(getClass()).info("JedisPool注入成功!!");
Logger.getLogger(getClass()).info("redis地址:" + host + ":" + port);
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout);
return jedisPool;
}
/**
* 返回一个RedisTemplate对象
*/
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
RedisTemplate template = new RedisTemplate<>();
RedisSerializer redisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setConnectionFactory(factory);
//key序列化方式
template.setKeySerializer(redisSerializer);
//value序列化
template.setValueSerializer(jackson2JsonRedisSerializer);
//value hashmap序列化
template.setHashValueSerializer(jackson2JsonRedisSerializer);
return template;
}
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisSerializer redisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
//解决查询缓存转换异常的问题
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// 配置序列化(解决乱码的问题),过期时间600秒
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(600)) //缓存过期10分钟 ---- 业务需求。
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))//设置key的序列化方式
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)) //设置value的序列化
.disableCachingNullValues();
RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
return cacheManager;
}
}
·
·
将RedisTemplate实例包装成一个工具类,便于对redis进行数据操作。
package com.xcbeyond.springboot.redis;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
@Component
public class RedisUtils {
@Autowired
private RedisTemplate redisTemplate;
/**
* 读取缓存
*
* @param key
* @return
*/
public String get(final String key) {
return redisTemplate.opsForValue().get(key);
}
/**
* 写入缓存
*/
public boolean set(final String key, String value) {
boolean result = false;
try {
redisTemplate.opsForValue().set(key, value);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 更新缓存
*/
public boolean getAndSet(final String key, String value) {
boolean result = false;
try {
redisTemplate.opsForValue().getAndSet(key, value);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 删除缓存
*/
public boolean delete(final String key) {
boolean result = false;
try {
redisTemplate.delete(key);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
·
·
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class RedisTest {
@Resource
private RedisUtils redisUtils;
/**
* 插入缓存数据
*/
@Test
public void set() {
redisUtils.set("redis_key", "redis_vale");
}
/**
* 读取缓存数据
*/
@Test
public void get() {
String value = redisUtils.get("redis_key");
System.out.println(value);
}
}
·
@SpringBootTest
public class SpringbootRedisApplicationTests {
@Autowired
private redisTemplate redisTemplate;
@Test
void contextLoads() {
//操作redis中字符串 opsForValue实际操作就是redis中的String类型
redisTemplate.opsForValue().set("name", "张三");
redisTemplate.opsForValue().set("k3","v3");
System.out.println(redisTemplate.opsForValue().get("name"));
//设置该key的过期时间
redisTemplate.expire("k3", 60, TimeUnit.SECONDS);
System.out.println(redisTemplate.getExpire("k3"));
//获取所有的key
Set keys = redisTemplate.keys("*");
System.out.println(keys);
}
//操作redis中的key
@Test
public void testKey(){
//删除一个key
redisTemplate.delete("name");
//判断一个key是否存在
Boolean name = redisTemplate.hasKey("name");
System.out.println(name);
redisTemplate.type("name");//判断key所对应的类型
redisTemplate.keys("*");//获取所有的key
Long name1 = redisTemplate.getExpire("name");//获取key的超时时间 -1 永不超时 -2 key不存在
System.out.println(name1);
redisTemplate.rename("age", "age1");//修改key的名字 要求key必须存在 不存在会报错
redisTemplate.renameIfAbsent("age", "age1");//如果key存在才修改名字,否则不修改
redisTemplate.move("name", 1);//移动key到指定库
}
//操作redis中字符串 opsForValue实际操作就是redis中的String类型
@Test
public void testString(){
redisTemplate.opsForValue().set("name", "小陈");//set用来设置一个key value
String name = redisTemplate.opsForValue().get("name");//用来获取一个key对应的value
System.out.println(name);
//设置一个key的超时时间(我们短信验证码的超时时间就是用这个做的)
redisTemplate.opsForValue().set("code", "2357", 120, TimeUnit.SECONDS);
redisTemplate.opsForValue().append("name", "他是一个好人");//给key的value追加内容
}
//操作list redisTemplate.opsForList()
@Test
public void testList(){
redisTemplate.opsForList().leftPush("names", "xiaochen");//创建列表,放入一个元素
redisTemplate.opsForList().leftPushAll("names", "xiaowang", "xiaoming", "xiaohei");//放入多个元素
List names = new ArrayList<>();
names.add("aaa");
names.add("bbb");
redisTemplate.opsForList().leftPushAll("names", names);//创建一个列表,放入多个元素
List names = redisTemplate.opsForList().range("names", 0, -1);//循环遍历
for (String name : names) {
System.out.println(name);
}
redisTemplate.opsForList().trim("names", 1, 3); //获取列表中的部分元素
}
//操作set redisTemplate.opsForSet()
@Test
public void testSet(){
redisTemplate.opsForSet().add("sets", "zhangsan", "lisi", "wangwu");//创建set,并放入多个元素
Set sets = redisTemplate.opsForSet().members("sets"); //获取Redis中的key为"sets"的set集合:
for (String name : sets) {
System.out.println(name);
}
Long sets1 = redisTemplate.opsForSet().size("sets");
System.out.println(sets1);
}
//操作hash redisTemplate.opsForHash()
@Test
public void tetstHash(){
redisTemplate.opsForHash().put("maps", "name", "zhangsan");//创建一个hash类型
Map map = new HashMap<>();
map.put("age", "12");
map.put("bir", "2012-12-12");
redisTemplate.opsForHash().putAll("maps", map); //将一个key为"maps"的hash集合存入Redis;
redisTemplate.opsForHash().get("maps", "name");//获取key为"maps"的hash集合中的某个key的value值
redisTemplate.opsForHash().values("maps");//获取key为"maps"的hash集合中的所有key的值
redisTemplate.opsForHash().keys("maps");//获取key为"maps"的hash集合中的所有key
redisTemplate.opsForHash().multiGet("maps", Arrays.asList("name", "age"));//获取key为"maps"的hash集合中的多个key的value值
}
//操作zset redisTemplate.opsForZSet()
@Test
public void testZset(){
redisTemplate.opsForZSet().add("zsets", "zhangsan", 100);//创建并放入元素
redisTemplate.opsForZSet().add("zsets", "lisi", 90);//创建并放入元素
redisTemplate.opsForZSet().add("zsets", "wangwu", 80);//创建并放入元素
Set zsets = redisTemplate.opsForZSet().range("zsets", 0, -1);//获取所有元素
for (String zset : zsets) {
System.out.println(zset);
}
//获取指定分数范围的值
Set> zsets = redisTemplate.opsForZSet().rangeByScoreWithScores("zsets", 0, 100);
for (ZSetOperations.TypedTuple zset : zsets) {
System.out.println(zset.getValue() + "::" + zset.getScore());
}
}
}
·
·
接下来就是如何使用注解啦,这一步反而是最简单的;
其实只用到了两个注解,@Cacheable和@CacheEvict,
第一个注解@Cacheable代表从缓存中查询指定的key,如果有,从缓存中取,不再执行方法。如果没有则执行方法,并且将方法的返回值和指定的key关联起来,放入到缓存中。
而@CacheEvict则是从缓存中清除指定的key对应的数据。
使用的代码如下:
//有参数
@Cacheable(value="thisredis", key="'users_'+#id")
public User findUser(Integer id) {
User user = new User();
user.setUsername("hlhdidi");
user.setPassword("123");
user.setUid(id.longValue());
System.out.println("log4j2坏啦?");
logger.info("输入user,用户名:{},密码:{}",user.getUsername(),user.getPassword());
return user;
}
@CacheEvict(value="thisredis", key="'users_'+#id",condition="#id!=1")
public void delUser(Integer id) {
// 删除user
System.out.println("user删除");
}
//无参数
@RequestMapping("/get")
@Cacheable(value="thisredis")
@ResponseBody
public List xx(){
return userMapper.selectAll();
}
@RequestMapping("/get3")
@CacheEvict(value="thisredis")
@ResponseBody
public String xx3(){
return "ok";
}
可以看出,我们用@Cacheable的value属性指定具体缓存,并通过key将其放入缓存中。
这里key非常灵活,支持spring的el表达式,可以通过方法参数产生可变的key(见findUser方法),也可以通过其指定在什么情况下,使用/不使用缓存(见delUser方法)。
·
·
执行完测试方法set后,可以登录到redis上查看数据是否插入成功。
(建议使用RedisDesktopManager可视化工具进行查看):
·
·
通过redisTemplate存入redis中的key和value都是经过序列化后的对象,如果我们存入的对象的实体类没有实现序列化接口,那么就会报错,如下:
两者的关系是StringRedisTemplate继承RedisTemplate。
两者的数据是不共通的;也就是说StringRedisTemplate只能管理StringRedisTemplate里面的数据,RedisTemplate只能管RedisTemplate中的数据。
SDR默认采用的序列化策略有两种,一种是String的序列化策略,一种是JDK的序列化策略。
StringRedisTemplate默认采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。
RedisTemplate默认采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。
总结:
当你的redis数据库里面本来存的是字符串数据、或者你要存取的数据就是字符串类型数据的时候,那么你就使用StringRedisTemplate即可,
但是如果你的数据是复杂的对象类型,而取出的时候又不想做任何的数据转换,直接从Redis里面取出一个对象,那么使用RedisTemplate是更好选择。
采用StringRedisTemplate的,不需要写Config配置类,因为Spring给他弄了序列化了,我们不需要在配置了,都是字符串;
RestTemplate是默认采用JDK的序列化的,这样不便于阅读,所以我们通过配置类去配置RestTemplate序列化的方式。