中间件:SpringBoot集成Redis
一.Redis简介
Redis(Remote Dictionary Server,远程字典服务)是一个开源的、使用ANSI C语言编写的、支持网络交互的、可基于内存亦可持久化的日志型Key-Value数据库,它提供了多种语言的API。Redis通常被称为数据结构服务器,因为它不仅支持简单的key-value类型的数据,还提供了如字符串(String)、哈希(Hash)、列表(List)、集合(Set)和有序集合(Sorted Set)等多种数据结构。以下是Redis的详细简介:
1.Redis的基本特点
- 高性能:Redis将数据存储在内存中,因此具有极高的读写速度,每秒可以处理超过10万次读写操作。这使得Redis非常适合用于缓存场景。
- 原子性:Redis的所有操作都是原子性的,这保证了数据的一致性。
- 支持多种数据类型:Redis不仅支持简单的key-value类型数据,还支持字符串、哈希、列表、集合和有序集合等多种数据结构,这使得Redis可以灵活地应用于各种场景。
- 持久化:Redis支持RDB和AOF两种持久化方式,可以将内存中的数据保存到磁盘上,以确保数据的可靠性和安全性。
- 复制和集群:Redis支持主从复制和集群模式,可以实现数据的备份、读写分离和水平扩展。
2.Redis的数据类型
- 字符串(String):Redis最基本的数据类型,可以存储任何类型的字符串,包括二进制数据。
- 哈希(Hash):Redis的Hash是一个键值对的集合,其中的每个键值对都是一个字符串类型的field和value。Hash特别适合存储对象。
- 列表(List):Redis的List是一个字符串列表,按照插入顺序排序。它支持从列表两端进行push和pop操作。
- 集合(Set):Redis的Set是一个无序的字符串集合,具有唯一性。它支持集合间的交集、并集和差集等操作。
- 有序集合(Sorted Set):Redis的Sorted Set是一个有序且不重复的字符串集合。每个元素都会关联一个double类型的分数(score),Redis正是通过分数来为集合中的成员进行从小到大的排序。
3.Redis的应用场景
- 缓存:Redis最常用的场景之一,它可以作为数据库的前置缓存,减少数据库的访问压力,提高应用的响应速度。
- 分布式锁:Redis具有原子性操作,可以利用其特性实现分布式锁,以保证在分布式环境下的数据一致性。
- 消息队列:Redis的List类型可以模拟消息队列,实现生产者-消费者模式。
- 计数器:Redis的原子性操作使得它可以作为计数器,用于统计网站的访问量、点赞数等。
- 社交网络:Redis可以用于存储用户的关注关系、粉丝列表等社交数据。
4.Redis的安装与配置
Redis的安装相对简单,可以从Redis官网下载相应的安装包或源码进行安装。安装完成后,需要配置redis.conf文件以满足特定的需求,如设置内存限制、连接数限制、持久化策略等。
5.Redis的维护与监控
为了确保Redis的稳定运行,需要定期对其进行维护和监控。可以使用Redis自带的监控工具,如Redis Monitor,也可以使用第三方监控工具,如Redis Insight。这些工具可以帮助我们实时监控Redis的运行状态和数据变化,以便及时发现并解决问题。
二.Redis基本使用
Redis是一款开源的、基于内存的数据结构存储系统,它可以用作数据库、缓存和消息中间件。Redis支持多种类型的数据结构,如字符串(strings)、哈希(hashes)、列表(lists)、集合(sets)、有序集合(sorted sets)等,并提供了丰富的命令来操作这些数据。以下是Redis的基本使用方法:
安装Redis
Redis支持多种操作系统,包括Linux、Windows等。安装Redis的方法因操作系统而异。
Linux系统
- 从Redis官网下载相应的安装包,或使用包管理器(如apt-get、yum等)安装。
- 解压安装包,并按照系统要求进行编译和安装。
- 配置Redis(可选),修改redis.conf文件以满足特定需求。
- 启动Redis服务,通常是通过运行redis-server命令并指定配置文件路径。
Windows系统
- 从Redis官网下载Windows版本的安装包。
- 双击安装包进行安装,按照提示完成安装过程。
- 启动Redis服务,可以通过双击redis-server.exe文件或使用命令行启动。
连接Redis
使用redis-cli命令连接到Redis服务器。在命令行中输入redis-cli,然后回车。如果Redis服务器设置了密码,连接时可以使用-a参数指定密码,如redis-cli -a yourpassword。
基本数据类型操作
Redis支持多种数据类型,每种数据类型都有相应的操作命令。
字符串(String)
- 设置键值对:
SET key value
- 获取指定键的值:
GET key
- 删除键:
DEL key
列表(List)
- 从列表左边插入元素:
LPUSH key value [value ...]
- 从列表右边插入元素:
RPUSH key value [value ...]
- 获取列表中的元素:
LRANGE key start stop
集合(Set)
- 添加元素到集合:
SADD key member [member ...]
- 移除集合中的元素:
SREM key member [member ...]
- 获取集合中的所有元素:
SMEMBERS key
有序集合(Sorted Set)
- 添加元素到有序集合:
ZADD key [NX|XX] [CH] [INCR] score member [score member ...]
- 移除有序集合中的元素:
ZREM key member [member ...]
- 获取有序集合中的元素:
ZRANGE key start stop [WITHSCORES]
哈希(Hash)
- 在哈希表中设置字段的值:
HSET key field value
- 获取哈希表中字段的值:
HGET key field
- 移除哈希表中一个或多个字段:
HDEL key field [field ...]
其他常用操作
- 查看所有键:
KEYS pattern
(注意:在生产环境中慎用,因为它会阻塞服务器) - 删除一个或多个键:
DEL key [key ...]
- 切换数据库:
SELECT index
(Redis默认有16个数据库,索引从0开始) - 清空当前数据库:
FLUSHDB
- 清空所有数据库:
FLUSHALL
配置和性能调优
Redis的性能和稳定性很大程度上取决于其配置。通过调整配置文件(redis.conf)中的参数,如内存限制、连接数限制、持久化策略等,可以优化Redis的性能。此外,还可以利用Redis提供的监控工具(如Redis Monitor、Redis Insight等)来实时监控Redis的运行状态和数据变化,以便及时发现并解决问题
持久化
Redis提供了两种持久化方式:RDB(快照)和AOF(追加文件)。快照方式通过定期创建数据库快照文件来保存数据,而日志方式则将每个写操作追加到日志文件中,以便恢复数据。根据实际需求选择合适的持久化方式,以确保数据的安全性和可靠性。
主从复制和集群
Redis支持主从复制模式,可以实现数据备份和读写分离。主节点负责写入数据,从节点负责读取数据。此外,Redis还支持集群模式,可以将数据分散到多个Redis节点上,以提高系统的整体性能和容错能力。
综上所述,Redis的基本使用包括安装、连接、数据类型操作、其他常用操作、配置和性能调优、持久化以及主从复制和集群等方面。通过掌握这些基本使用方法,可以更好地利用Redis来存储和访问数据。
三.Jedis操作Redis
Jedis 是 Java 实现的 Redis 客户端,提供了丰富的接口来操作 Redis 数据库。使用 Jedis,你可以在 Java 应用中方便地连接到 Redis 服务器,执行各种 Redis 命令,并处理返回的数据。
以下是如何使用 Jedis 来操作 Redis 的一些基本步骤:
添加 Jedis 依赖
首先,你需要在你的 Java 项目中添加 Jedis 的依赖。如果你使用 Maven,可以在 pom.xml
文件中添加如下依赖:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>最新版本</version>
</dependency>
编写junit单元测试JedisTester:
public class JedisTester {
private Jedis jedis;
@Before
public void setup(){
//连接redis服务器,127.0.0.1:6379
jedis = new Jedis("127.0.0.1",6379);
//权限认证,指定密码
jedis.auth("123456");
}
}
操作字符串:
@Test
public void testString(){
//添加数据
jedis.set("name","ktjiaoyu");
System.out.println(jedis.get("name"));
jedis.append("name","czkt");//拼接
System.out.println(jedis.get("name"));
jedis.del("name");//删除某个键
System.out.println(jedis.get("name"));
//设置多个键值对
jedis.mset("name","ktjiaoyu","age","17","add","cz");
jedis.incr("age");//对某个键值对进行加一操作
System.out.println(jedis.get("name")+"-"+jedis.get("age")+"-"+jedis.get("add"));
}
连接池
在我们实际使用过程中,不会在每次使用时创建Jedis对象,一般会使用连接池,并提供一个工具类来对外使用。
使用连接池的好处:1. 效率更高;2.线程安全。
连接池:
public final class RedisPool {
//Redis服务器IP
private static String ADDR = "192.168.0.100";
//Redis的端口号
private static int PORT = 6379;
//访问密码
private static String AUTH = "123456";
//可用连接实例的最大数目,默认值为8;
//如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。
private static int MAX_ACTIVE = 1024;
//控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。
private static int MAX_IDLE = 200;
//等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException;
private static int MAX_WAIT = 10000;
private static int TIMEOUT = 10000;
//在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;
private static boolean TEST_ON_BORROW = true;
private static JedisPool jedisPool=null;
/**
* 初始化Redis连接池
*/
static {
try {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(MAX_ACTIVE);
config.setMaxIdle(MAX_IDLE);
config.setMaxWaitMillis(MAX_WAIT);
config.setTestOnBorrow(TEST_ON_BORROW);
jedisPool = new JedisPool(config, ADDR, PORT, TIMEOUT, AUTH);
}catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取Jedis实例
* @return
*/
public synchronized static Jedis getJedis() {
try {
if (jedisPool != null) {
Jedis resource = jedisPool.getResource();
return resource;
} else {
return null;
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 释放jedis资源
* @param jedis
*/
public static void returnResource(final Jedis jedis) {
if (jedis != null) {
jedisPool.returnResource(jedis);
}
}
}
工具类:
public class RedisUtil {
/**
* 设置key的有效期,单位是秒
* @param key
* @param exTime
* @return
*/
public static Long expire(String key, long exTime) {
Jedis jedis=null;
Long result = null;
try {
jedis= RedisPool.getJedis();
result = jedis.expire(key, exTime);
}catch (Exception e){
e.printStackTrace();
return result;
}finally {
RedisPool.returnResource(jedis);
}
return result;
}
public static String estEx(String key, long exTime, String value) {
Jedis jedis=null;
String result = null;
try {
jedis= RedisPool.getJedis();
result = jedis.setex(key, exTime, value);
}catch (Exception e){
e.printStackTrace();
return result;
}finally {
RedisPool.returnResource(jedis);
}
return result;
}
public static String set(String key,String value) {
Jedis jedis=null;
String result = null;
try {
jedis= RedisPool.getJedis();
result = jedis.set(key, value);
}catch (Exception e){
e.printStackTrace();
return result;
}finally {
RedisPool.returnResource(jedis);
return result;
}
}
public static String get(String key) {
Jedis jedis=null;
String result = null;
try {
jedis = RedisPool.getJedis();
result = jedis.get(key);
}catch (Exception e){
e.printStackTrace();
return result;
}finally {
RedisPool.returnResource(jedis);
}
return result;
}
public static Long del(String key) {
Jedis jedis=null;
Long result = null;
try {
jedis = RedisPool.getJedis();
result = jedis.del(key);
}catch (Exception e){
e.printStackTrace();
return result;
}finally {
RedisPool.returnResource(jedis);
}
return result;
}
}
SpringBoot操作Redis
Spring Boot 集成 Redis 是一种常见的方式,用于在应用程序中存储和检索数据,特别是在需要快速访问和更新数据的情况下。Redis 是一个开源的、内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。Spring Boot 通过 spring-boot-starter-data-redis
提供了对 Redis 的支持。
1. 添加依赖
首先,你需要在你的 Spring Boot 项目的 pom.xml
(如果你使用的是 Maven)中添加 Redis 的起步依赖:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
2. application.properties配置相关信息
spring.redis.dtabase=0
spring.redis.host=localhost
spring.data.redis.port=6379
spring.data.redis.password=123456
spring.redis.lettuce.pool.max-active=8
spring.data.redis.lettuce.pool.max-wait=-1
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0
3.测试使用
在单元测试中,注入 StringRedisTemplate和RedisTemplate
@SpringBootTest
@RunWith(SpringRunner.class)
public class RedisTemplateTester {
@Resource
private StringRedisTemplate stringRedisTemplate;
@Resource
private RedisTemplate redisTemplate;
}
StringRedisTemplate和RedisTemplate区别
1. 使用范围与数据类型
- StringRedisTemplate:专门用于操作Redis中的String类型数据,提供了一系列简化操作String类型数据的方法。其泛型参数固定为
<String, String>
,表示键和值都是字符串类型的数据。 - RedisTemplate:是一个泛型类,通过指定泛型参数可以支持Redis中的多种数据类型操作(如字符串、列表、集合、有序集合、散列等)。它提供了对Redis常见数据类型的操作方法,并且支持批量插入和删除,可以一次性执行多个命令。
2. 序列化策略
- StringRedisTemplate:在序列化和反序列化数据时,使用
StringRedisSerializer
,这意味着在存储字符串类型数据时,可以直接将Java字符串类型转换为Redis字符串类型,效率较高。 - RedisTemplate:默认使用
JdkSerializationRedisSerializer
进行序列化和反序列化,这种方式会将Java对象序列化成字节数组存储在Redis中。虽然这种方式支持所有Java对象的序列化,但在Redis中查看时可能显示为乱码。不过,RedisTemplate的序列化策略可以根据需要进行自定义,例如使用Jackson2JsonRedisSerializer
将对象序列化为JSON字符串,这样在Redis中查看时会更友好
3. 特殊方法
- StringRedisTemplate:提供了一些专门用于操作字符串类型数据的特殊方法,如
append
(追加字符串)、getBit
(获取字符串指定位置的位)、decrement
(递减指定键的值)等。 - RedisTemplate:虽然也支持对字符串类型数据的操作,但相对于StringRedisTemplate来说,它更侧重于提供对多种Redis数据类型的通用操作方法。
4. 依赖与集成
- 两者都是Spring Data Redis提供的工具类,可以与Spring Boot应用程序无缝集成,通过依赖注入的方式进行使用。
四.SpringBoot集成Redis使用Cache缓存
RedisConfig配置
在config包下新建RedisConfig配置类:
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public KeyGenerator keyGenerator(){
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params)
sb.append(obj.toString());
return sb.toString();
}
};
}
@Bean
public RedisTemplate<Object, Object> redisCacheManager(RedisConnectionFactory redisConnectionFactory){
RedisTemplate<Object,Object>redisTemplate= new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
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);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory){
RedisSerializer<String>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);
// 配置序列化(解决乱码的问题),jackson2JsonRedisSerializer支持泛型
RedisCacheConfiguration config=RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofDays(7)) // 设置缓存过期时间为1分钟
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
.disableCachingNullValues();
RedisCacheManager cacheManager=RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
return cacheManager;
}
}
Cache注解
Cache注解在Spring Boot中主要用于方法级别的缓存控制,通过注解可以方便地将方法的返回结果缓存起来,以提高应用程序的性能。Spring Boot提供了多个与缓存相关的注解,这些注解通常与缓存管理器一起使用,如Redis、Ehcache、Caffeine等。以下是几个常用的Cache注解及其详细解释:
1. @EnableCaching
- 作用:在Spring Boot的启动类上使用此注解,以开启缓存支持。它告诉Spring Boot应用程序将使用缓存。
@SpringBootApplication
@EnableCaching
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
2. @Cacheable
- 作用:用于标记一个方法,其返回值需要被缓存。当方法被调用时,Spring会先检查缓存中是否存在相应的数据,如果存在,则直接返回缓存中的数据,而不需要执行方法体。如果不存在,则执行方法体,并将结果缓存起来。
- 属性:
value
:指定缓存的名称。key
:指定缓存的键,用于唯一标识缓存中的数据。支持Spring EL表达式。condition
:指定缓存的条件,只有当条件满足时,才会进行缓存。
@Cacheable(value="users", key="#id")
public User getUserById(Long id) {
// 查询数据库等操作
return user;
}
3. @CachePut
- 作用:与@Cacheable类似,但@CachePut每次都会执行方法体,并将结果缓存起来。它通常用于更新操作,确保缓存中的数据始终是最新的。
- 属性:与@Cacheable类似,也有value、key和condition等属性。
@CachePut(value="users", key="#user.id")
public User updateUser(User user) {
// 更新数据库等操作
return user;
}
4. @CacheEvict
- 作用:用于标记一个方法,该方法执行时会触发缓存的清除操作。它通常用于删除操作,以确保缓存中的数据与数据库中的数据保持一致。
- 属性:
value
:指定要清除的缓存的名称。key
:指定要清除的缓存的键。allEntries
:是否清除指定缓存中的所有数据。当设置为true时,会忽略key属性。beforeInvocation
:是否在方法执行前清除缓存。默认为false,即在方法执行后清除缓存。
@CacheEvict(value="users", key="#id")
public void deleteUserById(Long id) {
// 删除数据库中的用户等操作
}
@CacheEvict(value="users", allEntries=true)
public void deleteAllUsers() {
// 删除数据库中的所有用户等操作
}
5. @CacheConfig
- 作用:用于配置该类中会用到的一些共用的缓存配置。当类中的多个方法需要相同的缓存配置时,可以使用@CacheConfig来避免重复配置。
- 属性:
cacheNames
:指定该类中方法默认使用的缓存名称。
@CacheConfig(cacheNames = "myCache")
public class MyService {
@Cacheable
public String findById(Long id) {
// 查询数据库等操作
}
// 其他方法...
}