SpringBoot——Redis的使用

原文链接:

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

·

·

三,编写配置类,加载配置,返回RedisTemplate:

创建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工具类:

        将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;
	}
}

·

·

五,使用:

1,使用自己封装的工具类:

@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);
	}
 
}

· 

2,使用RedisTemplate:

@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());
        }
    }

}

· 

·

3,使用注解——@Cacheable和@CacheEvict:

        接下来就是如何使用注解啦,这一步反而是最简单的;

        其实只用到了两个注解,@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方法)。

·

·

六,测试:

1,可视化工具查看:

执行完测试方法set后,可以登录到redis上查看数据是否插入成功。
(建议使用RedisDesktopManager可视化工具进行查看):

SpringBoot——Redis的使用_第1张图片

·

·

七,注意:

1,Redis中的对象必须序列化:

        通过redisTemplate存入redis中的key和value都是经过序列化后的对象,如果我们存入的对象的实体类没有实现序列化接口,那么就会报错,如下:

SpringBoot——Redis的使用_第2张图片

2,StringRedisTemplate 和 RedisTemplate的区别:

        两者的关系是StringRedisTemplate继承RedisTemplate。

        两者的数据是不共通的;也就是说StringRedisTemplate只能管理StringRedisTemplate里面的数据,RedisTemplate只能管RedisTemplate中的数据。

        SDR默认采用的序列化策略有两种,一种是String的序列化策略,一种是JDK的序列化策略。

        StringRedisTemplate默认采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。

        RedisTemplate默认采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。

总结

        当你的redis数据库里面本来存的是字符串数据、或者你要存取的数据就是字符串类型数据的时候,那么你就使用StringRedisTemplate即可,

        但是如果你的数据是复杂的对象类型,而取出的时候又不想做任何的数据转换,直接从Redis里面取出一个对象,那么使用RedisTemplate是更好选择。

3,写这个Config类和不写有什么区别呢?

        采用StringRedisTemplate的,不需要写Config配置类,因为Spring给他弄了序列化了,我们不需要在配置了,都是字符串;

        RestTemplate是默认采用JDK的序列化的,这样不便于阅读,所以我们通过配置类去配置RestTemplate序列化的方式。

你可能感兴趣的:(项目相关+项目工具,分布式微服务系列,java)