SpringBoot集成Redis

Redis使用场景比较广泛,常用的就是缓存一些高频数据,这样不需要每次获取都去查询DB,但是相应的,如果数据发生增改善,缓存需要更新,这个Spring做的比较好,下面介绍注解的方式实现Redis缓存。

添加依赖

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.5.0</version>
        </dependency>

注意,本示例是基于SpringBoot2版本的,添加上述依赖即可,SpringBoot1.5版本依赖不太一样,需要格外注意!

配置Redis

本地开发环境建议使用Docker起一个Redis服务,很方便。

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

单元测试

接下来创建一个单元测试来测试一下set和get


@SpringBootTest
@RunWith(SpringRunner.class)
@Component
public class RedisTests {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void set(){
        redisTemplate.opsForValue().set("test:key","test:Value1");
        Object str = redisTemplate.opsForValue().get("test:key");
        System.out.println(str);
    }

}

执行单元用力,可以看到控制台输出了test:Value1.

what? so easy?

没错,就是这么简单,下面我们继续,在service层通过注解的方式使用Redis缓存。

编码

1、User实现Serializable接口

2、UserMapper新增

 List<User> selects();

3、UserMapper.xml新增

<select id="selects" resultType="cc.koit.hulk.dao.entity.User">
        SELECT * FROM k_user
    </select>

4、UserService新增

    public List<User> listAll();

5、UserServiceImpl使用缓存注解

@Service
public class UserServiceImpl implements UserService {

    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

    @Autowired
    private UserMapper userMapper;

    @Override
    @CacheEvict(value="koit_cache", key="'user_list'")
    public void create(User user) {
        userMapper.insert(user);
        logger.info("插入成功,返回id:"+user.getId());
    }


    @Override
    @Cacheable(value="koit_cache", key="'user_list'")
    public List<User> listAll() {
        return userMapper.selects();
    }
}

6、redis配置类

package cc.koit.hulk.common.configuration;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
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 org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;

@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(60))
                .disableCachingNullValues();

        return RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .transactionAware()
                .build();
    }

    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
        StringRedisTemplate template = new StringRedisTemplate(factory);

        RedisSerializer keySerializer = new StringRedisSerializer(); // 设置key序列化类,否则key前面会多了一些乱码
        template.setKeySerializer(keySerializer);
        setValueSerializer(template);//设置value序列化
        template.afterPropertiesSet();
        template.setEnableTransactionSupport(true);
        return template;
    }

    private void setValueSerializer(StringRedisTemplate template) {
        @SuppressWarnings({"rawtypes", "unchecked"})
        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.setValueSerializer(jackson2JsonRedisSerializer);
    }

}

7、UserController新增接口

 @RequestMapping("/list")
    public List<User> getUserList(){
        return userService.listAll();
    }

运行程序

HulkApplication类添加@EnableCaching注解,启动服务。

访问http://localhost:9090/user/list接口,我们看到有DB访问日志输出:

2018-09-28 16:48:30.285 DEBUG 8864 --- [nio-9090-exec-1] c.k.hulk.dao.mapper.UserMapper.selects   : ==>  Preparing: SELECT * FROM k_user 
2018-09-28 16:48:30.318 DEBUG 8864 --- [nio-9090-exec-1] c.k.hulk.dao.mapper.UserMapper.selects   : ==> Parameters: 
2018-09-28 16:48:30.347 DEBUG 8864 --- [nio-9090-exec-1] c.k.hulk.dao.mapper.UserMapper.selects   : <== 1="" total:="" <="" code="">

再次访问接口,我们获得了接口结果,但是并没有看到DB访问日志输出,说明这次是从缓存中获取的数据。

注解@Cacheable @CacheEvict @CachePut的使用

@Cacheable标记在方法上表示该方法支持缓存,如果标记在类上表示该类所有方法都支持缓存。
属性:
value:value属性是必须指定的,其表示当前方法的返回值是会被缓存在哪个Cache上的,对应Cache的名称。其可以是一个Cache也可以是多个Cache,当需要指定多个Cache时其是一个数组。

key: key属性是用来指定Spring缓存方法的返回结果时对应的key的。该属性支持SpringEL表达式。当我们没有指定该属性时,Spring将使用默认策略生成key。

condition:有的时候我们可能并不希望缓存一个方法所有的返回结果。通过condition属性可以实现这一功能。condition属性默认为空,表示将缓存所有的调用情形。其值是通过SpringEL表达式来指定的,当为true时表示进行缓存处理;当为false时表示不进行缓存处理,即每次调用该方法时该方法都会执行一次。

@CacheEvict是用来标注在需要清除缓存元素的方法或类上的。当标记在一个类上时表示其中所有的方法的执行都会触发缓存的清除操作。@CacheEvict可以指定的属性有value、key、condition、allEntries和beforeInvocation。其中value、key和condition的语义与@Cacheable对应的属性类似。即value表示清除操作是发生在哪些Cache上的(对应Cache的名称);key表示需要清除的是哪个key,如未指定则会使用默认策略生成的key;condition表示清除操作发生的条件。

allEntries:allEntries是boolean类型,表示是否需要清除缓存中的所有元素。默认为false,表示不需要。当指定了allEntries为true时,Spring Cache将忽略指定的key。有的时候我们需要Cache一下清除所有的元素,这比一个一个清除元素更有效率。

beforeInvocation:清除操作默认是在对应方法成功执行之后触发的,即方法如果因为抛出异常而未能成功返回时也不会触发清除操作。使用beforeInvocation可以改变触发清除操作的时间,当我们指定该属性值为true时,Spring会在调用该方法之前清除缓存中的指定元素。

@CachePut标注的方法,Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素,如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,否则才会执行并将返回结果存入指定的缓存中。@CachePut也可以声明一个方法支持缓存功能。与@Cacheable不同的是使用@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。@CachePut也可以标注在类上和方法上。使用@CachePut时我们可以指定的属性跟@Cacheable是一样的。

,
© 2019 FunGa技术札记 All Rights Reserved. 本站访客数人次 本站总访问量
Theme by hiero