Spring Boot缓存技术-----F04

Spring Boot****缓存技术*

1.Ehcache Redis 的对比

Ehcache

在java项目广泛的使用。它是一个开源的、设计于提高在数据从RDBMS中取出来的高花费、高延迟采取的一种缓存方案。正因为Ehcache具有健壮性(基于java开发)、被认证(具有apache 2.0 license)、充满特色,所以被用于大型复杂分布式web application的各个节点中。够简单就是Ehcache的一大特色,自然用起来 just so easy!

够快

Ehcache 的发行有一段时长了,经过几年的努力和不计其数的性能测试,Ehcache 终被设计于 large, high concurrency systems。

够简单

开发者提供的接口非常简单明了,从 Ehcache 的搭建到运用运行仅仅需要的是你宝贵的几分钟。其实很多编程者都不知道自己在用Ehcache,Ehcache被广泛的运用于其他的开源项目,比如:Hibernate。

够袖珍

关于这点的特性,官方给了一个很可爱的名字 small foot print,一般 Ehcache 的发布版本不会到2M, V2.2.3版本才668KB,目前最新版的V3.8.0版本也不过才1754KB。

够轻量

核心程序仅仅依赖 slf4j 这一个包,没有之一!

好扩展

Ehcache 提供了对大数据的内存和硬盘的存储,最近版本允许多实例、保存对象高灵活性、提供LRU、LFU、FIFO淘汰算法,基础属性支持热配置、支持的插件多。

监听器

缓存管理器监听器 (CacheManagerListener)和 缓存监听器(CacheEvenListener),做一些统计或数据一致性广播挺好用的。

Redis

支持持久化

Redis 的本地持久化支持两种方式:RDB和AOF。RDB 在redis.conf配置文件里配置持久化触发器,AOF指的是Redis每增加一条记录都会保存到持久化文件中(保存的是这条记录的生成命令)。

丰富的数据类型

Redis 支持 String 、List、Set、Sorted Set、hash 多种数据类型。

高性能

内存操作的级别是毫秒级的比硬盘操作秒级操作自然高效不少,减少了磁头寻道、数据读取、页面交换这些高开销的操作!这也是NOSQL冒出来的原因吧,应该是高性能是基于RDBMS的衍生产品,虽然RDBMS也具有缓存结构,但是始终在应用层面达不到我们的需求。

Replication

Redis 提供主从复制方案,跟 MySql 一样增量复制而且复制的实现都很相似,这个复制跟AOF有点类似复制的是新增记录命令,主库新增记录将新增脚本发送给从库,从库根据脚本生成记录,这个过程非常快,就看网络了,一般主从都是在同一个局域网,所以可以说 Redis 的主从近似及时同步,同时它还支持一主多从,动态添加从库,从库数量没有限制。

更新快

Redis 到目前为止已经发了大版本 5 个,小版本没算过。Redis 作者是个非常积极的人,无论是邮件提问还是论坛发帖,他都能及时耐心的为你解答,维护度很高。有人维护的话,让我们用的也省心和放心。目前作者对Redis 的主导开发方向是 Redis 的集群方向。

总结

Ehcache 直接在 jvm 虚拟机中缓存,速度快,效率高;但是缓存共享麻烦,集群分布式应用不方便。如果是单个应用或者对缓存访问要求很高的应用,用 Ehcache。

Redis 是通过 socket 访问到缓存服务,效率比 Ecache 低,比数据库要快很多,处理集群和分布式缓存方便,有成熟的方案。如果是大型系统,存在缓存共享、分布式部署、缓存内容很大的,建议用 Redis。

2.Ehcache

使用 Ehcache 缓存的步骤是:

  • 添加 Ehcache 组件和依赖
  • 添加 Ehcache 配置文件
  • 业务层使用 @Cacheable 处理缓存
  • 启动类使用 @EnableCaching 开启缓存

创建项目

Spring Boot缓存技术-----F04_第1张图片
image.png

添加组件依赖

我们需要在 pom.xml 中添加 cache 组件 和 ehcache 依赖

(ehcache 依赖可以不用添加,本案例添加是为了获取 ehcache 配置文件模板

pom.xml

 
        
        
            org.springframework.boot
            spring-boot-starter-cache
        
        
        
            net.sf.ehcache
            ehcache
        
        
        
            org.springframework.boot
            spring-boot-starter-thymeleaf
        
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter
            2.1.0
        
        
        
            mysql
            mysql-connector-java
        
        
        
            com.alibaba
            druid
            1.1.19
        

        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    

    
    
        
        
            
                src/main/resources
            
            
                src/main/java
                
                    **/*.xml
                    **/*.properties
                    **/*.tld
                
                false
            
        
    

ehcache 配置文件

我们可以参考 ehcache 项目源码中的配置文件模板。

Spring Boot缓存技术-----F04_第2张图片
image.png

diskStore

diskStore 元素是可选的,非必须的。如果不使用磁盘存储,只需要将 diskStore 注释掉即可;如果使用,需要在 ehcache.xml 文件中的 ehcahce 元素下的定义一个 diskStore 元素并指定其 path 属性。

path 属性可以配置的目录有:

user.home(用户的家目录)

user.dir(用户当前的工作目录)

java.io.tmpdir(默认的临时目录)

ehcache.disk.store.dir(ehcache的配置目录)

绝对路径(如:D:\ehcache)

DiskStore 中驱除元素跟 MemoryStore 中驱除元素的规则是不一样的。当往 DiskStore 中添加元素且此时DiskStore 中的容量已经超出限制时将采用 LFU(最不常用)驱除规则将对应的元素进行删除,而且该驱除规则是不可配置的(通过 cache 中的 diskExpiryThreadIntervalSeconds 属性完成)。

缓存策略

name :缓存名称

maxElementsInMemory :内存缓存中最多可以存放的元素数量,若放入 Cache 中的元素超过这个数值,则有以下两种情况:

  1. 若 overflowToDisk=true,则会将 Cache 中多出的元素放入磁盘文件中
  1. 若 overflowToDisk=false,则根据 memoryStoreEvictionPolicy 策略替换 Cache 中原有的元素

eternal :缓存中对象是否永久有效,是否永驻内存,true时将忽略timeToIdleSeconds和 timeToLiveSeconds

timeToIdleSeconds :设置对象的空闲时间

timeToLiveSeconds :设置对象的存活时间

overflowToDisk :内容溢出是否写入磁盘

memoryStoreEvictionPolicy :内存存储与释放策略,即达到 maxElementsInMemory 限制时,Ehcache 会根据指定策略清理内存。共有三种策略:

LRU(最近最少使用)

LFU(最常用的)

FIFO(先进先出)

ehcache 中缓存的 3 种清空策略:

  1. FIFO: first in first out,这个是大家最熟的,先进先出,不多讲了
  2. LFU: Less Frequently Used,直白一点就是讲一直以来最少被使用的。缓存的元素有一个 hit 属性, hit 值最小的将会被清出缓存。
  3. LRU: Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。

对于 EhCache 的配置文件也可以通过 application.properties 文件中使用 spring.cache.ehcache.config 属性来指定,比如: spring.cache.ehcache.config=classpath:config/ehcache.xml

resources/ehcache.xml




    

    
    
        
    

    
    
        
    


properties 配置文件

# 配置数据库驱动
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=shsxt
# 配置数据库连接池
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
# 配置MyBatis数据返回类型别名(默认别名是类名)
mybatis.type-aliases-package=com.springboot.pojo
# 配置MyBatis Mapper映射文件
mybatis.mapper-locations=classpath:com/springboot/mapper/*.xml
# 配置SQL打印
# 指定某个包下的SQL打印
logging.level.com.springboot.mapper=debug
# 所有包下的SQL打印
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

添加 application.properties 全局配置文件,配置SQL打印。

SQL****文件

CREATE TABLE `user` (
`id` INT (11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR (255) DEFAULT NULL,
`age` INT (11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4;

实体类

User.java

package com.springboot.pojo;

import java.io.Serializable;

public class User implements Serializable {

    private Integer id;
    private String name;
    private Integer age;

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Mapper 接口

UserMapper.java

public interface UserMapper {

    // 添加用户
    int insertUser(User user);

    // 查询用户
    List selectUserList();

    // 根据主键查询用户
    User selectUserById(Integer id);

    // 修改用户
    int updateUser(User user);

    // 删除用户
    int deleteUser(Integer id);

}

映射配置文件

UserMapper.xml






    
    
        insert into user (name, age) values (#{name}, #{age})
    

    
    

    
    

    
    
        update user set name = #{name}, age = #{age} where id = #{id};
    

    
    
        delete from user where id = #{id}
    


业务层

业务层使用 @Cacheable 处理缓存

UserServiceI.java

public interface UserServiceI {

    int insertUser(User user);

    // 查询用户
    List selectUserList();

    // 根据主键查询用户
    User selectUserById(Integer id);

    // 修改用户
    int updateUser(User user);

    // 删除用户
    int deleteUser(Integer id);

}

UserServiceImpl.java

@Service
@Transactional
@CacheConfig(cacheNames = "userCache")
public class UserServiceImpl implements UserServiceI {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private CacheManager cacheManager;

    // 清除缓存中以 userCache 缓存策略缓存的对象
    @CacheEvict(allEntries = true)
    @Override
    public int insertUser(User user) {
        return userMapper.insertUser(user);
    }

    @Cacheable
    @Override
    public List selectUserList() {
        return userMapper.selectUserList();
    }

    @Cacheable(key = "#id")
    @Override
    public User selectUserById(Integer id) {
        return userMapper.selectUserById(id);
    }

    // 清除缓存中以 userCache 缓存策略缓存的对象
    @CacheEvict(allEntries = true)
    @Override
    public int updateUser(User user) {
        return userMapper.updateUser(user);
    }

    // 清除缓存中以 userCache 缓存策略缓存的对象
    //@CacheEvict(allEntries = true)
    @Override
    public int deleteUser(Integer id) {
        Cache cache = cacheManager.getCache("userCache");
        cache.clear();
        return userMapper.deleteUser(id);
    }

}


控制层

UserController.java

@Controller
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserServiceI userService;

    /**
     * 页面跳转
     */
    @RequestMapping("/{page}")
    public String page(@PathVariable String page) {
        return page;
    }

    /**
     * 添加用户
     */
    @PostMapping("/insertUser")
    public String insertUser(User user) {
        int result = userService.insertUser(user);
        return "success";
    }

    /**
     * 查询用户列表
     */
    @GetMapping("/selectUserList")
    public String selectUserList(Model model) {
        model.addAttribute("userList", userService.selectUserList());
        return "user-list";
    }

    /**
     * 修改用户跳转页面
     */
    @GetMapping("/edit/{id}")
    public String edit(@PathVariable Integer id, Model model) {
        model.addAttribute("user", userService.selectUserById(id));
        return "updateUser";
    }

    /**
     * 修改用户保存
     */
    @PostMapping("/updateUser")
    public String updateUser(User user) {
        userService.updateUser(user);
        return "success";
    }

    /**
     * 删除用户
     */
    @GetMapping("/deleteUser/{id}")
    public String deleteUser(@PathVariable Integer id) {
        userService.deleteUser(id);
        return "success";
    }

}


视图层

templates/register.html




    
    注册用户


    
姓名:
年龄:

templates/success.html




    
    提示


    成功



templates/updateUser.html




    
    修改用户


    
姓名:
年龄:

templates/user-list.html




    
    用户列表


    
ID NAME AGE 操作
修改 删除

启动类

启动类使用 @EnableCaching 开启缓存

App.java

@SpringBootApplication
// 扫描 mapper 接口和映射配置文件
@MapperScan("com.springboot.mapper")
// 开启缓存
@EnableCaching
public class App {

    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }

}


测试

数据库

Spring Boot缓存技术-----F04_第3张图片
image.png

访问:http://localhost:8080/user/selectUserList

Spring Boot缓存技术-----F04_第4张图片
image.png

删除数据库


Spring Boot缓存技术-----F04_第5张图片
image.png

再次查询,控制台无任何打印消息,依然可以查询到数据,缓存配置成功。

Cache 常用注解详解

@Cacheable

value 、 cacheNames :两个等同的参数( cacheNames 为Spring 4新增,作为 value 的别名),用于 指定缓存存储的集合名。由于Spring 4中新增了 @CacheConfig ,因此在Spring 3中原本必须有的 value 属性,也成为非必需项了。

key :缓存对象存储在Map集合中的key值,非必需,缺省按照函数的所有参数组合作为 key 值,若自己配置需使用 SpEL 表达式,比如: @Cacheable(key = "#p0") :使用函数第一个参数作为缓存的 key 值,在查询时如果key 存在,那么直接从缓存中将数据返回。更多关于SpEL表达式的详细内容可参考官方文档。

UserServiceImpl.java

// 对当前查询的结果做缓存处理,不配置 cacheNames 属性时使用默认缓存策略
@Cacheable(cacheNames = "userCache")
@Override
public List selectUserList() {
return userMapper.selectUserList();
} /
*
设置缓存的 key
#p0:使用第一个参数作为 key
#id:使用参数 id 作为 key
#user.id:使用参数 user 的 id 作为 key (user 是对象 id 是 user 的属性)
*/
@Cacheable(cacheNames = "userCache", key = "#id")
@Override
public User selectUserById(Integer id) {
return userMapper.selectUserById(id);
}

@CacheConfig

@CacheConfig is a class-level annotation that allows to share the cache names.

主要用于配置某些类中会用到的一些共用的缓存配置,比如本案例中我们多次使用到

@Cacheable(cacheNames= "userCache") 我们便可以在该类上添加 @CacheConfig(cacheNames = "userCache") 注解,方法上只需要使用 @Cacheable 即可。如果在方法上使用别的缓存名称,那么依然以方法的缓存名称为准。

@CacheEvict

配置于函数上,通常用在写操作方法上,用来从缓存中移除相应数据。除了同 @Cacheable 一样的参数之外,它还有下面两个参数:

allEntries :非必需,默认为 false。当为 true 时,会移除所有数据;

beforeInvocation :非必需,默认为 false,会在调用方法之后移除数据。当为 true 时,会在调用方法之前移除数据。

// 清除缓存中以 userCache 缓存策略缓存的对象
@CacheEvict(cacheNames = "userCache", allEntries = true)
@Override
public int insertUser(User user) {
return userMapper.insertUser(user);
} 
// 如果该类配置了@CacheConfig(cacheNames = "userCache"),可以简写
@CacheEvict(allEntries = true)
@Override
public int updateUser(User user) {
return userMapper.updateUser(user);
} 
// 如果该类配置了@CacheConfig(cacheNames = "userCache"),可以简写
@CacheEvict(allEntries = true)
@Override
public int deleteUserById(Integer id) {
return userMapper.deleteUserById(id);
}

当我们执行写操作时,缓存的内容会被清除,查询时会重新查询关系数据库再次放入缓存。

CacheManager

我们还可以通过 CacheManager 对象来管理缓存。

UserServiceImpl.java

@Autowired
private CacheManager cacheManager;
@Override
public int deleteUserById(Integer id) {
// 清除缓存中以 userCache 缓存策略缓存的对象
cacheManager.getCache("userCache").clear();
return userMapper.deleteUserById(id);
}j

3.Redis

Redis 是一个开源的使用 ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。no-sql 型的数据库。

2008年,意大利一家创业公司Merzia的创始人Salvatore Sanfilippo为了避免MySQL的低性能,亲自定做一个数据库,并于2009年开发完成,这个就是Redis。

从2010年3月15日起,Redis的开发工作由VMware主持。

从2013年5月开始,Redis的开发由Pivotal赞助。

安装****Redis

下载地址:http://redis.io/;

将 redis.tar.gz 上传至服务器,解压 tar zxvf redis.tar.gz ;

安装依赖: yum -y install gcc-c++ autoconf automake ;

创建安装目录 mkdir -p /usr/local/redis ;

切换至解压目录 cd redis ;预编译 make ;

安装 make PREFIX=/usr/local/redis install ;

安装成功如下图:


Spring Boot缓存技术-----F04_第6张图片
image.png

redis-cli:客户端

redis-server:服务端

修改配置文件并启动

复制解压目录下 redis.conf 至安装目录 /usr/local/redis/bin

修改 redis.conf,将 daemonize 修改为 yes(后台启动);

注释掉 bind127.0.0.1 使所有的 ip 访问 redis,若是想指定多个 ip 访问,并不是全部的 ip 访问,可以 bind设置;

添加访问认证 requirepass root ;

处理防火墙;

启动时,指定配置文件路径即可 bin/redis-server bin/redis.conf ;

安装可视化客户端访问:

Spring Boot缓存技术-----F04_第7张图片
image.png

Spring Data Redis

Spring Data Redis 是 Spring 大家族的一部分,提供了在 Srping 应用中通过简单的配置访问 Redis 服务,对Reids 底层开发包(Jedis,JRedis,RJC)进行了高度封装,RedisTemplate 提供了 Redis 各种操作、异常处理及序列化,支持发布订阅,对 Redis Sentinel 和 Redis Cluster 支持,并对 Spring 3.1 cache进行了实现。

案例中我们分别讲解 Lettuce 和 Jedis 两种实现, Lettuce 和 Jedis 的都是连接 Redis Server 的客户端程序。

因为 Spring Boot2.0 之后,底层默认不再采用 Jedis 作为实现了。而是采用效率更高,线程更安全的 Lettuce客户端。

Jedis 是一个优秀的基于 Java 语言的 Redis 客户端,但是,其不足也很明显:Jedis 在实现上是直接连接 Redis-Server,在多个线程间共享一个 Jedis 实例时是线程不安全的,如果想要在多线程场景下使用 Jedis,需要使用连接池,每个线程都使用自己的 Jedis 实例,当连接数量增多时,会消耗较多的物理资源。

Lettuce 则完全克服了其线程不安全的缺点:Lettuce 是基于 Netty 的连接实例(StatefulRedisConnection)

Lettuce 是一个可伸缩的线程安全的 Redis 客户端,支持同步、异步和响应式模式。多个线程可以共享一个连接实例,而不必担心多线程并发问题。它基于优秀 Netty NIO 框架构建,支持 Redis 的高级功能,如Sentinel,集群,流水线,自动重新连接和 Redis 数据模型。

3.1Lettuce

我们先来讲 Spring Boot2.x 版本以后的默认方式 Lettuce。

创建项目

创建Spring Boot项目,选择 Web 组件 Redis 组件。需要手动添加 commons-pool2 对象池依赖。 !
Spring Boot缓存技术-----F04_第8张图片
image.png

pom.xml



            org.springframework.boot
            spring-boot-starter-data-redis
        
        
        
            org.apache.commons
            commons-pool2
        
        
        
            org.springframework.boot
            spring-boot-starter-web
        
            
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    



properties 配置文件

application.properties

# 最大连接数,默认8
spring.redis.lettuce.pool.max-active=1024
# 最大连接阻塞等待时间,单位毫秒,默认-1
spring.redis.lettuce.pool.max-wait=10000
# 最大空闲连接,默认8
spring.redis.lettuce.pool.max-idle=200
# 最小空闲连接,默认0
spring.redis.lettuce.pool.min-idle=5
# 连接超时时间
spring.redis.timeout=10000
# Redis服务器地址
spring.redis.host=192.168.190.10
# Redis服务器端口
spring.redis.port=6379
# Redis服务器密码
spring.redis.password=root
# 选择哪个库,默认0库
spring.redis.database=0


自定义模板

默认情况下的模板 RedisTemplate ,默认序列化使用的是 JdkSerializationRedisSerializer ,存储二进制字节码。这时需要自定义模板,当自定义模板后又想存储String 字符串时,可以使用 StringRedisTemplate 的方式,他们俩并不冲突。

序列化问题:

要把 domain object 做为 key-value 对保存在 redis 中,就必须要解决对象的序列化问题。Spring Data Redis给我们提供了一些现成的方案:

JdkSerializationRedisSerializer 使用JDK提供的序列化功能。 优点是反序列化时不需要提供类型信息(class),但缺点是序列化后的结果非常庞大,是JSON格式的5倍左右,这样就会消耗 Redis 服务器的大量内存。

Jackson2JsonRedisSerializer 使用 Jackson 库将对象序列化为JSON字符串。优点是速度快,序列化后的字符串短小精悍。但缺点也非常致命,那就是此类的构造函数中有一个类型参数,必须提供要序列化对象的类型信息(.class对象)。 通过查看源代码,发现其只在反序列化过程中用到了类型信息。

GenericJackson2JsonRedisSerializer 通用型序列化,这种序列化方式不用自己手动指定对象的Class。

RedisConfigForLettuce.java

@Configuration
public class RedisConfigForLettuce {
// 重写 RedisTemplate 序列化
@Bean
public RedisTemplate redisTemplate(
LettuceConnectionFactory redisConnectionFactory) {
RedisTemplate template = new RedisTemplate<>();
// 为 String 类型 key 设置序列化器
template.setKeySerializer(new StringRedisSerializer());
// 为 String 类型 value 设置序列化器
template.setValueSerializer(new
GenericJackson2JsonRedisSerializer());
// 为 Hash 类型 key 设置序列化器
template.setHashKeySerializer(new StringRedisSerializer());
// 为 Hash 类型 value 设置序列化器
template.setHashValueSerializer(new
GenericJackson2JsonRedisSerializer());
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}

debug 模式运行 RedisConnectionFactory 信息如下:

Spring Boot缓存技术-----F04_第9张图片
image.png

实体类

user.java

package com.springboot.pojo;

import java.io.Serializable;

public class User implements Serializable {

    private Integer id;
    private String username;
    private Integer age;

    public User() {
    }

    public User(Integer id, String username, Integer age) {
        this.id = id;
        this.username = username;
        this.age = age;
    }

    public Integer getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", age=" + age +
                '}';
    }

}

测试类

SpringbootRedisApplicationTests.java

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {App.class})
public class SpringbootRedisApplicationTests {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Test
    public void testSet() {
        User user = new User();
        user.setId(1);
        user.setUsername("张三");
        user.setAge(18);
        redisTemplate.opsForValue().set("user:" + user.getId(), user);

        User u = (User) redisTemplate.opsForValue().get("user:1");
        System.out.println(u);
    }

    @Test
    public void testGet() {
        User user = (User) redisTemplate.opsForValue().get("user:1");
        System.out.println(user);
    }

}

结果

Spring Boot缓存技术-----F04_第10张图片
image.png
3.2Jedis

创建项目

创建Spring Boot项目,选择 Web 组件 Redis 组件。需要手动添加 commons-pool2 对象池依赖,排除 Lettuce依赖,添加 Jedis 依赖。

pom.xml



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.1.7.RELEASE
         
    
    com.springboot
    springboot-redis
    0.0.1-SNAPSHOT
    springboot-redis
    Demo project for Spring Boot

    
        1.8
    

    
        
            org.springframework.boot
            spring-boot-starter-data-redis
            
         
             
                      io.lettuce
                         lettuce-core
               
          
        
        
      
     redis.clients
      jedis
     
        
            org.apache.commons
            commons-pool2
        
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    





properties 配置文件

application.properties

# 最大连接数,默认8
spring.redis.lettuce.pool.max-active=1024
# 最大连接阻塞等待时间,单位毫秒,默认-1
spring.redis.lettuce.pool.max-wait=10000
# 最大空闲连接,默认8
spring.redis.lettuce.pool.max-idle=200
# 最小空闲连接,默认0
spring.redis.lettuce.pool.min-idle=5
# 连接超时时间
spring.redis.timeout=10000
# Redis服务器地址
spring.redis.host=192.168.190.10
# Redis服务器端口
spring.redis.port=6379
# Redis服务器密码
spring.redis.password=root
# 选择哪个库,默认0库
spring.redis.database=0


自定义模板

RedisConfigForJedis.java

//@Configuration
public class RedisConfigForJedis {

    // 重写 RedisTemplate 序列化
    //@Bean

    public RedisTemplate redisTemplate(
            JedisConnectionFactory redisConnectionFactory) {
        RedisTemplate template = new RedisTemplate<>();
        // 为 String 类型 key 设置序列化器
        template.setKeySerializer(new StringRedisSerializer());
        // 为 String 类型 value 设置序列化器
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        // 为 Hash 类型 key 设置序列化器
        template.setHashKeySerializer(new StringRedisSerializer());
        // 为 Hash 类型 value 设置序列化器
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }


}


debug 模式运行 RedisConnectionFactory 信息如下:

Spring Boot缓存技术-----F04_第11张图片
image.png

实体类

User.java

测试类

SpringbootRedisApplicationTests.java

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {App.class})
public class SpringbootRedisApplicationTests {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Test
    public void testSet() {
        User user = new User();
        user.setId(1);
        user.setUsername("张三");
        user.setAge(18);
        redisTemplate.opsForValue().set("user:" + user.getId(), user);

        User u = (User) redisTemplate.opsForValue().get("user:1");
        System.out.println(u);
    }

    @Test
    public void testGet() {
        User user = (User) redisTemplate.opsForValue().get("user:1");
        System.out.println(user);
    }

}


结果

Spring Boot缓存技术-----F04_第12张图片
image.png
3.3Sentinel

Redis 哨兵是为 Redis 提供一个高可靠解决方案,Redis 主节点挂掉会自动帮我们提升从为主,对一定程序上的错误可以不需要人工干预自行解决。哨兵功能还有监视、事件通知、配置功能等。以下是哨兵的功能列表:

监控:不间断的检查主从服务是否如预期一样正常工作;

事件通知:对被监视的 Redis 实例的异常,能通知系统管理员,或者以API接口通知其他应用程序;

智能援救:当被监视的主服务异常时,哨兵会智能的把某个从服务提升为主服务,同时其他从服务与新的主服务之间的关系将得到重新的配置。应用程序将通过redis服务端重新得到新的主服务的地址并重新建立连接;

配置服务:客户端可连接哨兵的接口,获得主从服务的相关信息,如果发生改变,哨兵新通知客户端。

Spring Boot 也提供了对于哨兵连接的配置,关于哨兵主从服务,我们先来看看本案例使用的环境。


Spring Boot缓存技术-----F04_第13张图片
image.png

properties 配置文件

application.properties

# 最大连接数,默认8
spring.redis.lettuce.pool.max-active=1024
# 最大连接阻塞等待时间,单位毫秒,默认-1
spring.redis.lettuce.pool.max-wait=10000
# 最大空闲连接,默认8
spring.redis.lettuce.pool.max-idle=200
# 最小空闲连接,默认0
spring.redis.lettuce.pool.min-idle=5
# 连接超时时间
spring.redis.timeout=10000
# Redis服务器地址
spring.redis.host=192.168.18.10
# Redis服务器端口,哨兵模式下不一定非要配置为主节点,只要是主从环境中任何一个节点即可
spring.redis.port=6379
# Redis服务器密码
spring.redis.password=root
# 选择哪个库,默认0库
spring.redis.database=0
# 哨兵主从服务
# 主节点名称
spring.redis.sentinel.master=mymaster
# 主从服务器地址
spring.redis.sentinel.nodes=192.168.18.10:26379,192.168.18.10:26380,192.168.18.10:26381

@Bean

除了使用配置文件或者使用 @Bean 配置 Sentinel

Lettuce 配置 Sentinel

@Configuration
public class RedisConfigForLettuce {

    /**
     * Lettuce
     */
    //@Bean
    public RedisConnectionFactory lettuceConnectionFactory() {
        RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration()
                .master("mymaster")// 主节点名称
                .sentinel("192.168.10.10", 26379)
                .sentinel("192.168.10.10", 26380)
                .sentinel("192.168.10.10", 26381);
        sentinelConfig.setPassword("root");// 设置密码
        return new LettuceConnectionFactory(sentinelConfig);
    }

    // 重写 RedisTemplate 序列化
    @Bean
    public RedisTemplate redisTemplate(
            LettuceConnectionFactory redisConnectionFactory) {
        RedisTemplate template = new RedisTemplate<>();
        // 为 String 类型 key 设置序列化器
        template.setKeySerializer(new StringRedisSerializer());
        // 为 String 类型 value 设置序列化器
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        // 为 Hash 类型 key 设置序列化器
        template.setHashKeySerializer(new StringRedisSerializer());
        // 为 Hash 类型 value 设置序列化器
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

}


Jedis 配置 Sentinel

package com.springboot.config;

//@Configuration
public class RedisConfigForJedis {

    /**
     * Jedis
     */
    //@Bean
    /*
    public RedisConnectionFactory jedisConnectionFactory() {
        RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration()
                .master("mymaster")// 主节点名称
                .sentinel("192.168.10.10", 26379)
                .sentinel("192.168.10.10", 26380)
                .sentinel("192.168.10.10", 26381);
        sentinelConfig.setPassword("root");
        return new JedisConnectionFactory(sentinelConfig);
    }
     */

    // 重写 RedisTemplate 序列化
    //@Bean
    /*
    public RedisTemplate redisTemplate(
            JedisConnectionFactory redisConnectionFactory) {
        RedisTemplate template = new RedisTemplate<>();
        // 为 String 类型 key 设置序列化器
        template.setKeySerializer(new StringRedisSerializer());
        // 为 String 类型 value 设置序列化器
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        // 为 Hash 类型 key 设置序列化器
        template.setHashKeySerializer(new StringRedisSerializer());
        // 为 Hash 类型 value 设置序列化器
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
    */

}


测试类

测试同上

不需要配置主节点,哨兵可以可以自动查找

Spring Boot缓存技术-----F04_第14张图片

你可能感兴趣的:(Spring Boot缓存技术-----F04)