SpringBoot + Redis:基本配置及使用

2020-04-21 15:14:20

参考地址 SpringBoot + Redis:基本配置及使用

一、SpringBoot 配置Redis

  1.1 pom 引入spring-boot-starter-data-redis 包

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

  1.2 properties配置文件配置redis信息

  默认连接本地6379端口的redis服务,一般需要修改配置,例如:

复制代码

# Redis数据库索引(默认为0)
spring.redis.database=0# Redis服务器地址
spring.redis.host=127.0.0.1# Redis服务器连接端口
spring.redis.port=6379# Redis服务器连接密码(默认为空)
spring.redis.password=# 连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=20# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=-1# 连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=10# 连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=0# 连接超时时间(毫秒)
spring.redis.timeout=1000

复制代码

二、RedisTemplate<K,V>类的配置

  Spring 封装了RedisTemplate<K,V>对象来操作redis。

  2.1 Spring对RedisTemplate<K,V>类的默认配置(了解即可)

  Spring在 org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration类下配置的两个RedisTemplate的Bean。

  (1) RedisTemplate<Object, Object>

  这个Bean使用JdkSerializationRedisSerializer进行序列化,即key, value需要实现Serializable接口,redis数据格式比较难懂,例如

  

  (2) StringRedisTemplate,即RedisTemplate<String, String>

  key和value都是String。当需要存储实体类时,需要先转为String,再存入Redis。一般转为Json格式的字符串,所以使用StringRedisTemplate,需要手动将实体类转为Json格式。如

复制代码

ValueOperations<String, String> valueTemplate = stringTemplate.opsForValue();
Gson gson = new Gson();

valueTemplate.set("StringKey1", "hello spring boot redis, String Redis");
String value = valueTemplate.get("StringKey1");
System.out.println(value);

valueTemplate.set("StringKey2", gson.toJson(new Person("theName", 11)));
Person person = gson.fromJson(valueTemplate.get("StringKey2"), Person.class);
System.out.println(person);

复制代码

  

  2.2 配置一个RedisTemplate<String,Object>的Bean

   Spring配置的两个RedisTemplate都不太方便使用,所以可以配置一个RedisTemplate<String,Object> 的Bean,key使用String即可(包括Redis Hash 的key),value存取Redis时默认使用Json格式转换。如下

复制代码

    @Bean(name = "template")    public RedisTemplate<String, Object> template(RedisConnectionFactory factory) {        // 创建RedisTemplate<String, Object>对象
        RedisTemplate<String, Object> template = new RedisTemplate<>();        // 配置连接工厂        template.setConnectionFactory(factory);        // 定义Jackson2JsonRedisSerializer序列化对象
        Jackson2JsonRedisSerializer<Object> jacksonSeial = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper om = new ObjectMapper();        // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);        // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会报异常        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jacksonSeial.setObjectMapper(om);
        StringRedisSerializer stringSerial = new StringRedisSerializer();        // redis key 序列化方式使用stringSerial        template.setKeySerializer(stringSerial);        // redis value 序列化方式使用jackson        template.setValueSerializer(jacksonSeial);        // redis hash key 序列化方式使用stringSerial        template.setHashKeySerializer(stringSerial);        // redis hash value 序列化方式使用jackson        template.setHashValueSerializer(jacksonSeial);
        template.afterPropertiesSet();        return template;
    }

复制代码

  所以可以这样使用

复制代码

@Autowired
private RedisTemplate<String, Object> template;
public void test002() {
   ValueOperations<String, Object> redisString = template.opsForValue();
   // SET key value: 设置指定 key 的值
   redisString.set("strKey1", "hello spring boot redis");
   // GET key: 获取指定 key 的值
   String value = (String) redisString.get("strKey1");
   System.out.println(value);

   redisString.set("strKey2", new User("ID10086", "theName", 11));
   User user = (User) redisString.get("strKey2");
   System.out.println(user);
}  

复制代码

  

  2.3 配置Redis operations 的Bean

  RedisTemplate<K,V>类以下方法,返回值分别对应操作Redis的String、List、Set、Hash等,可以将这些operations 注入到Spring中,方便使用

  

复制代码

  /**
     * redis string     */
    @Bean    public ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate) {        return redisTemplate.opsForValue();
    }    /**
     * redis hash     */
    @Bean    public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {        return redisTemplate.opsForHash();
    }    /**
     * redis list     */
    @Bean    public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {        return redisTemplate.opsForList();
    }    /**
     * redis set     */
    @Bean    public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {        return redisTemplate.opsForSet();
    }    /**
     * redis zset     */
    @Bean    public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {        return redisTemplate.opsForZSet();
    }

复制代码

三、RedisTemplate类的API使用

   RedisTemplate是Spring封装的类,它的API基本上对应了Redis的命令,下面列举了一小部分的使用,更多的请查看Javadoc。

复制代码

    @Autowired    private HashOperations<String, String, Object> redisHash;// Redis Hash

    @Test    public void test003() {
        Map<String, Object> map = new HashMap<>();
        map.put("id", "10010");
        map.put("name", "redis_name");
        map.put("amount", 12.34D);
        map.put("age", 11);
        redisHash.putAll("hashKey", map);        // HGET key field 获取存储在哈希表中指定字段的值
        String name = (String) redisHash.get("hashKey", "name");
        System.out.println(name);        // HGET key field
        Double amount = (Double) redisHash.get("hashKey", "amount");
        System.out.println(amount);        // HGETALL key 获取在哈希表中指定 key 的所有字段和值
        Map<String, Object> map2 = redisHash.entries("hashKey");
        System.out.println(map2);        // HKEYS key 获取在哈希表中指定 key 的所有字段
        Set<String> keySet = redisHash.keys("hashKey");
        System.out.println(keySet);        // HVALS key 获取在哈希表中指定 key 的所有值
        List<Object> valueList = redisHash.values("hashKey");
        System.out.println(valueList);
    }

复制代码

四、使用Redis缓存数据库数据

   Redis有很多使用场景,一个demo就是缓存数据库的数据。Redis作为一个内存数据库,存取数据的速度比传统的数据库快得多。使用Redis缓存数据库数据,可以减轻系统对数据库的访问压力,及加快查询效率等好处。下面讲解如何使用 SpringBoot + Redis来缓存数据库数据(这里数据库使用MySql)。

  4.1 配置Redis作为Spring的缓存管理

  Spring支持多种缓存技术:RedisCacheManager、EhCacheCacheManager、GuavaCacheManager等,使用之前需要配置一个CacheManager的Bean。配置好之后使用三个注解来缓存数据:@Cacheable,@CachePut 和 @CacheEvict。这三个注解可以加Service层或Dao层的类名上或方法上(建议加在Service层的方法上),加上类上表示所有方法支持该注解的缓存;三注解需要指定Key,以返回值作为value操作缓存服务。所以,如果加在Dao层,当新增1行数据时,返回数字1,会将1缓存到Redis,而不是缓存新增的数据。

  RedisCacheManager的配置如下:

复制代码

   /**
     * <p>SpringBoot配置redis作为默认缓存工具</p>
     * <p>SpringBoot 2.0 以上版本的配置</p>     */
    @Bean    public CacheManager cacheManager(RedisTemplate<String, Object> template) {
        RedisCacheConfiguration defaultCacheConfiguration =
                RedisCacheConfiguration
                        .defaultCacheConfig()                        // 设置key为String                        .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(template.getStringSerializer()))                        // 设置value 为自动转Json的Object                        .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(template.getValueSerializer()))                        // 不缓存null                        .disableCachingNullValues()                        // 缓存数据保存1小时
                        .entryTtl(Duration.ofHours(1));
        RedisCacheManager redisCacheManager =
                RedisCacheManagerBuilder                        // Redis 连接工厂                        .fromConnectionFactory(template.getConnectionFactory())                        // 缓存配置                        .cacheDefaults(defaultCacheConfiguration)                        // 配置同步修改或删除 put/evict                        .transactionAware()
                        .build();        return redisCacheManager;
    }

复制代码

  4.2 @Cacheabl、@CachePut、@CacheEvict的使用

复制代码

= "user" = "user", key = "#id"="'list'" List<User>= "#id", condition = "#number ge 20") 
     User selectUserByIdWithCondition(String id, = "#id", unless = "#number lt 20") 
     User selectUserByIdWithUnless(String id, = "#user.id"= "#user.id", condition = "#user.age ge 20"= "#user.id"= "#id" = "#id", allEntries =

复制代码

五、项目地址

  项目github地址,里面的测试类均有对上面涉及的内容进行测试。喜欢的帮忙点个Star

  https://github.com/caizhaokai/spring-boot-demo

 


  • 2019-08-19 10:24:29

    浅析Express中的路由与应用模式

    Express是一个基于Node.js的轻量级web开发框架,具有体积小,使用灵活等特点。查看Express的源码,如果不计供使用的中间件,主体框架只有一千余行代码,非常简练。

  • 2019-08-19 15:50:17

    记录PHP的进程和线程理解

    线程是进程的一个执行流,线程不能分配系统资源,它是进程的一部分,比进程更小的独立运行的单位。 解释一下:进程有两个特性:一是资源的所有权,一个是调度执行(指令集),线程是调度执行中的一部分,是指进程执行过程的路径,也叫程序执行流。线程有时候也叫轻量级进程。

  • 2019-08-20 08:51:52

    一台Linux服务器可以负载多少个连接?

    我们在压测一台目标服务器,想看下负载的连接数,当我们压到一定数量的时候,控制台突然报"too many open files",这是因为linux系统创建一个TCP连接的时候,都会创建一个socket句柄,每个socket句柄就是一个文件句柄。

  • 2019-08-20 08:56:42

    Linux下Http高并发参数优化之TCP参数

    Linux 内核参数考虑的是最通用场景,并不符合用于支持高并发访问的Web服务器的定义,所以需要修改Linux内核参数。其次,对 Nginx 的一些参数,也需要根据服务情况进行调整。

  • 2019-08-20 11:05:30

    php,nginx,线程和进程分析

    大多数的 Linux 程序都倾向于使用进程而不是线程,因为 Linux 下相对来说创建进程的开销比较小,而 Linux 的线程功能又不是很强大。

  • 2019-08-20 11:22:36

    Node.js 单线程与多进程比较

    进过上面两种方式的对比,结果很明显,多进程处理速度是单线程处理速度的 4 倍多。而且有条件的情况下,如果电脑 CPU 足够,进程数更多,那么速度也会更快。

  • 2019-08-22 13:35:27

    Generator函数的语法

    执行Generator函数会返回一个遍历器对象,也就是说,Generator函数除了是状态机还是一个遍历器对象生成函数。 返回遍历器对象,可以依次遍历Generator函数内部的每一个状态。