Spring Boot 2.x整合Redis

最近在学习Spring Boot 2.x整合Redis,在这里和你们分享一下,但愿对你们有帮助。html

Redis是什么

Redis 是开源免费高性能的key-value数据库。有如下的优点(源于Redis官网http://www.redis.net.cn/):redis

  • 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。spring

  • 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操做。数据库

  • 原子 – Redis的全部操做都是原子性的,意思就是要么成功执行要么失败彻底不执行。单个操做是原子性的。多个操做也支持事务,即原子性,经过MULTI和EXEC指令包起来。缓存

  • 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过时等等特性。服务器

若是想了解更多关于Redis是什么,能够参考:Redis初识并发

为何要使用Redis

  1. 性能:若是碰到须要执行耗时特别久,且结果不频繁变更的SQL,就特别适合将运行结果放入缓存。这样,后面的请求就去缓存中读取,使得请求可以迅速响应。
  2. 并发: 在大并发的状况下,全部的请求直接访问数据库,数据库会出现链接异常。这个时候,就须要使用redis作一个缓冲操做,让请求先访问到Redis,而不是直接访问数据库。

为何要使用Redis来自博客园【原创】分布式之redis复习精讲 ,这篇博文关于Redis的讲解我以为超赞,谢谢做者的耐心分享。app

Spring Boot 2.x如何整合Redis

我使用的Spring Boot版本是2.1.0,根据网上的一些旧的教程进行整合Redis 3.2的时候,会有许多地方有错误提示。这是由于Spring Boot 2.x作了一些修改,这些修改对使用而有没有影响呢?咱们改怎么整合呢?下面就进入正式的整合过程。分布式

1. pom.xnl引入依赖

这是以前的依赖:
        <dependency>
            <groupId>org.springframework.boot</groupId>  
            <artifactId>spring-boot-starter-redis</artifactId>
        </dependency>  

如今会提示Project build error: 'dependencies.dependency.version' for org.springframework.boot:spring-boot-starter-redis:jar is missing. 提示spring-boot-starter-redis:jar找不到。ide

这是由于Spring Boot 1.4以后再也不支持spring-boot-starter-redis,更换spring-boot-starter-data-redis以后就能够了。若是你的pom文件报错,请检查是否将spring-boot-starter-redis 改为了spring-boot-starter-data-redis。

Spring Boot 2.x要使用下面的依赖:

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

2. application.properties添加配置文件

这是以前版本的配置文件:

# REDIS (RedisProperties)
# 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.pool.max-active=8  
# 链接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1 
# 链接池中的最大空闲链接
spring.redis.pool.max-idle=8  
# 链接池中的最小空闲链接
spring.redis.pool.min-idle=0  
# 链接超时时间(毫秒)
spring.redis.timeout=0  

若是Spring Boot 2.x这么配置,有错误提示 Property 'spring.redis.pool.max-active' is Deprecated: Use 'spring.redis.jedis.pool.max-idle' instead. 'spring.redis.pool.max-active'已经被弃用了,推荐使用'spring.redis.jedis.pool.max-idle'来代替。

这是由于在2.x中配置redis的链接池信息时,再也不使用spring.redis.pool的属性,而是直接使用redis的lettuce或jedis客户端来配置。如今的配置以下:

# REDIS (RedisProperties)
# 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=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=0  

3. 配置CacheManager

这是以前的RedisConfig配置类:

@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
    @Bean
    public CacheManager cacheManager(RedisTemplate<?, ?>  redisTemplate) {
        CacheManager cacheManager = new  RedisCacheManager(redisTemplate);
        return cacheManager;
    }

    @Bean
    public RedisTemplate<String, String>  redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, String> redisTemplate = new  RedisTemplate<String, String>();
        redisTemplate.setConnectionFactory(factory);
        return redisTemplate;
    }
}

如今这么写会有报错The constructor RedisCacheManager(RedisTemplate<capture#1-of ?,capture#2-of ?>) is undefined。

这是由于Spring Boot 2.x版本删除了RedisCacheManager这个构造器, 也不能够经过以前的setDefaultExpiration方法设置默认的缓存过时时间等。

那么要怎样构造一个 RedisCacheManager?看看官方文档中怎么说?文档地址:https://docs.spring.io/spring-data/data-redis/docs/2.1.x/reference/html/#new-in-2.1.0

官方文档5.13.1. Support for the Spring Cache Abstraction(对Spring Cache Abstraction的支持)是关于怎么配置缓存的说明,我尝试着翻译了一下(蓝色部分),英文水平有限,各位轻喷。

Spring Redis provides an implementation for the Spring cache abstraction through the org.springframework.data.redis.cache package. To use Redis as a backing implementation, add RedisCacheManager to your configuration, as follows:

Spring Redis在 org.springframework.data.redis.cache 包中为Spring缓存抽象提供了一个实现方案。要使用Redis做为支持实现,须要将RedisCacheManager添加到配置中,以下所示:

@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
    return RedisCacheManager.create(connectionFactory);
}

RedisCacheManager behavior can be configured with RedisCacheManagerBuilder, letting you set the default RedisCacheConfiguration, transaction behavior, and predefined caches.

RedisCacheManager能够用 RedisCacheManagerBuilder 进行配置,容许自定义设置默认的RedisCacheConfiguration、事务行为和预约义的缓存。

RedisCacheManager cm = RedisCacheManager.builder(connectionFactory)
    .cacheDefaults(defaultCacheConfig())
    .initialCacheConfigurations(singletonMap("predefined", defaultCacheConfig().disableCachingNullValues()))
    .transactionAware()
    .build();

As shown in the preceding example, RedisCacheManager allows definition of configurations on a per-cache basis.

正如上面的例子所示,RedisCacheManager 容许基于每一个缓存进行配置。

The behavior of RedisCache created with RedisCacheManager is defined with RedisCacheConfiguration. The configuration lets you set key expiration times, prefixes, and RedisSerializer implementations for converting to and from the binary storage format, as shown in the following example:

RedisCacheManager建立RedisCache的行为被定义为RedisCacheConfiguration。该配置容许设置键值过时时间、前缀和RedisSerializer实现等属性,以便与二进制存储格式进行转换,以下所示:

RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(1))
    .disableCachingNullValues();

RedisCacheManager defaults to a lock-free RedisCacheWriter for reading and writing binary values. Lock-free caching improves throughput. The lack of entry locking can lead to overlapping, non-atomic commands for the putIfAbsent and clean methods, as those require multiple commands to be sent to Redis. The locking counterpart prevents command overlap by setting an explicit lock key and checking against presence of this key, which leads to additional requests and potential command wait times.

RedisCacheManager默认是无锁的,用于读写二进制值的RedisCacheWriter。无锁缓存可提升吞吐量。缺乏锁定可能致使putIfAbsent和clean方法的非原子命令重叠,由于这些方法须要向Redis发送多条命令。锁对应程序经过设置显式锁定的key并检查是否存在该key来防止命令重叠,这会致使额外的请求和潜在的命令等待时间。

It is possible to opt in to the locking behavior as follows:

也能够选择锁定行为,以下所示:

RedisCacheManager cm = RedisCacheManager.build(RedisCacheWriter.lockingRedisCacheWriter())
    .cacheDefaults(defaultCacheConfig())
    ...

By default, any key for a cache entry gets prefixed with the actual cache name followed by two colons. This behavior can be changed to a static as well as a computed prefix.

默认状况下,缓存条目的任何key目以实际缓存名称为前缀,后跟两个冒号。此行为能够更改成静态前缀和计算前缀。

The following example shows how to set a static prefix:

如下示例显示如何设置静态前缀:

// static key prefix
RedisCacheConfiguration.defaultCacheConfig().prefixKeysWith("( ͡° ᴥ ͡°)");

The following example shows how to set a computed prefix:

// computed key prefix
RedisCacheConfiguration.defaultCacheConfig().computePrefixWith(cacheName -> "¯\_(ツ)_/¯" + cacheName);

The following table lists the default settings for RedisCacheManager:

下表列出了RedisCacheManager的默认设置:

Setting
Value
Cache Writer
Non-locking
Cache Configuration
RedisCacheConfiguration#defaultConfiguration
Initial Caches
None
Trasaction Aware
No

The following table lists the default settings for RedisCacheConfiguration:

下表列出了RedisCacheConfiguration的默认设置:

Key Expiration
None
Cache null
Yes
Prefix Keys
Yes
Default Prefix
The actual cache name
Key Serializer
StringRedisSerializer
Value Serializer
JdkSerializationRedisSerializer
Conversion Service
DefaultFormattingConversionService with default cache key converters

对于Spring Boot 2.x,这里我使用RedisCacheConfiguration简单配置一下缓存时间,完成RedisCacheManager的配置,代码以下:

@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory  factory) {
        RedisCacheConfiguration config =  RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(1));
        RedisCacheManager cacheManager =  RedisCacheManager.builder(factory).cacheDefaults(config).build();
        return cacheManager;
    }
}

4. Service层

使用缓存的状况通常是这样的:第一次访问的时候先从数据库读取数据,而后将数据写入到缓存,再次访问同一内容的时候就从缓存中读取,若是缓存中没有则从数据库中读取。
添加缓存逻辑的时候,从数据库中将内容读取出来以后,先set入缓存,而后再从缓存中添加读取行为,若是缓存为空则从数据库中进行读取。

在这里仅建立一个简单的RedisService,来进行存取缓存数据。

@Service
public class RedisService {
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    public void set(String key, Object value) {
        //更改在redis里面查看key编码问题
        RedisSerializer redisSerializer = new  StringRedisSerializer();
        redisTemplate.setKeySerializer(redisSerializer);
        ValueOperations<String, Object> vo =  redisTemplate.opsForValue();
        vo.set(key, value);
    }

    public Object get(String key) {
        ValueOperations<String, Object> vo =  redisTemplate.opsForValue();
        return vo.get(key);
    }
}

5. Model层

实体类没有修改,和以前文章里面用的同样:

@Entity
@Table(name = "user")
public class User implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue
    private Long id;
    @Column(name = "username")
    private String userName;
    @Column(name = "password")
    private String passWord;

    public User() {
        super();
    }

    public User(String userName, String passWord) {
        super();
        this.userName = userName;
        this.passWord = passWord;
    }

    public User(Long id, String userName, String passWord) {
        super();
        this.id = id;
        this.userName = userName;
        this.passWord = passWord;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassWord() {
        return passWord;
    }

    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }

}

 6. Controller层

在user.Controller添加两个测试方法,一个写入Redis,一个从Redis读取:
@RestController
@RequestMapping("user")
public class UserController {
    @Autowired
    private UserRepository userRepository;

    @Autowired
    private RedisService redisService;

    @RequestMapping("/saveUser")
    public String saveUser(Long id, String userName, String  passWord) {
        User user = new User(id, userName, passWord);
        redisService.set(id + "", user);
        return "success";
    }

    @RequestMapping("/getUserById")
    public User getUserById(Long id) {
        User res = (User) redisService.get(id + "");
        return res;
    }
}

7. 测试

使用Postman进行测试,访问http://localhost:8080//user/saveUser?id=12&userName=Howard&passWord=magician,添加了一个User。

看看Redis数据库,使用get key查看,获得一个对象:

http://localhost:8080//user/getUserById?id=12,经过id获取User。

这是过滤器和拦截器的日志信息,能够看到没有进行MySQL数据库的操做,直接从缓存中读取,说明Redis配置生效了:

若是访问以前的接口,是有操做数据库的:

总结

以上就是Spring Boot 2.x整合Redis的全过程,和Spring Boot以前的版本在使用上有些细微的差异。
本文水平有限,或多或少有欠妥之处,还望各位大佬指正!
相关文章
相关标签/搜索