SpringBoot应该不用介绍!它是Spring当前最火的一个框架,整合Spring Boot 3和Redis可以显著提升应用程序的性能,特别是在处理大量数据和需要快速访问的场景下。
在Spring Boot中,从1.x版本到2.x版本的Redis连接方式发生了变化,从使用Jedis切换到了使用Lettuce。这两者在连接Redis时的实现方式和特性有所不同,主要区别如下:
Jedis
连接方式:
- Jedis是一个基于直连的连接池技术,每个Jedis实例都是线程不安全的。如果多个线程要使用Jedis实例,需要通过Jedis Pool来获取线程安全的连接。
- Jedis基于阻塞I/O(BIO),每个操作都是同步的,即一个线程处理一个连接。
实现特性:
- Jedis在单线程环境中表现良好,但在多线程环境下需要使用连接池来确保线程安全。
- 对于高并发场景,每个操作都会阻塞当前线程,可能导致性能瓶颈。
Lettuce
连接方式:
- Lettuce基于Netty框架实现了异步、非阻塞的连接操作。
- Lettuce的连接是线程安全的,一个连接可以被多个线程共享,不需要使用连接池来管理连接。
实现特性:
- Lettuce支持异步操作,每个操作都可以在单独的线程中执行,不会阻塞其他线程。
- 在高并发和大规模连接的情况下,Lettuce的性能通常优于Jedis,因为它能更有效地利用系统资源,如多核处理器和内存。
总结
- Jedis更像传统的BIO模式,适合于较简单的单线程或有限多线程的场景,但在高并发情况下需要注意线程安全性和连接管理。
- Lettuce则更像现代NIO模式,通过异步和非阻塞的方式提升了性能和资源利用率,特别是在需要处理大量并发连接或异步操作的场景下表现优异。
因此,Spring Boot从2.x版本开始推荐使用Lettuce作为连接Redis的客户端,以提升系统的并发能力和性能表现。
1、添加POM依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Data Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--lombok,自动生成set、get等方法-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
2、配置连接的application.yml文件:
spring:
data:
redis:
host: localhost
port: 6379
database: 0
password: # 密码(默认为空)
3、写个简单的Dome来测试连接
创建一个配置类来配置Redis的连接工厂和Redis模板。
package com.example.demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* Redis配置类
* 该类用于配置Redis连接和模板,以便在应用程序中使用Redis。
*/
@Configuration
public class RedisConfig {
/**
* Redis服务器主机地址
*/
@Value("${spring.data.redis.host}")
private String redisHost;
/**
* Redis服务器端口
*/
@Value("${spring.data.redis.port}")
private int redisPort;
/**
* Redis服务器密码
*/
@Value("${spring.data.redis.password}")
private String redisPassword;
/**
* 配置并返回RedisConnectionFactory
* 使用LettuceConnectionFactory创建Redis连接工厂,并配置主机、端口和密码。
*
* @return RedisConnectionFactory
*/
@Bean
public RedisConnectionFactory redisConnectionFactory() {
// 创建LettuceConnectionFactory实例
LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(redisHost, redisPort);
// 设置Redis密码
lettuceConnectionFactory.setPassword(redisPassword);
// 返回配置好的Redis连接工厂
return lettuceConnectionFactory;
}
/**
* 配置并返回RedisTemplate
* 创建Redis模板实例,配置键值序列化方式,并关联到RedisConnectionFactory。
*
* @param redisConnectionFactory Redis连接工厂
* @return RedisTemplate
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
// 创建Redis模板实例
RedisTemplate<String, Object> template = new RedisTemplate<>();
// 设置Redis连接工厂
template.setConnectionFactory(redisConnectionFactory);
// 设置键的序列化方式为StringRedisSerializer
template.setKeySerializer(new StringRedisSerializer());
// 设置值的序列化方式为GenericJackson2JsonRedisSerializer
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
// 返回配置好的Redis模板实例
return template;
}
}
创建一个实体类
package com.example.demo.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 用户类,用于表示应用程序中的用户信息。
*
* @Data Lombok注解,用于自动生成getter和setter方法,以及构造函数等。
* @NoArgsConstructor Lombok注解,生成一个无参的构造方法。
* @AllArgsConstructor Lombok注解,生成一个全参的构造方法。
* @Serializable 实现此接口的类的对象可以被序列化。
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {
private String id;
private String name;
private int age;
}
然后在服务类中注入RedisTemplate并进行CRUD操作。
package com.example.demo.service;
import com.example.demo.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
/**
* RedisService类提供了对Redis数据库的基本操作,包括存储、查询和删除数据。
* 该类使用Spring的RedisTemplate来简化对Redis的操作。
*/
@Service
public class RedisService {
/**
* 自动注入RedisTemplate,用于操作Redis数据库。
*/
@Autowired
private RedisTemplate<String, Object> redisTemplate;
/**
* 将给定的value保存到Redis中,使用指定的key进行标识。
*
* @param key 数据在Redis中的唯一标识符。
* @param value 要保存到Redis中的数据。
*/
public void save(String key, Object value) {
redisTemplate.opsForValue().set(key, value);
}
/**
* 根据指定的key从Redis中查询数据。
*
* @param key 数据在Redis中的唯一标识符。
* @return 与key对应的数据。
*/
public Object find(String key) {
return redisTemplate.opsForValue().get(key);
}
/**
* 根据指定的key从Redis中删除数据。
*
* @param key 要删除的数据在Redis中的标识符。
*/
public void delete(String key) {
redisTemplate.delete(key);
}
/**
* 将User对象保存到Redis中,使用指定的key进行标识。
*
* @param key 数据在Redis中的唯一标识符。
* @param user 要保存到Redis中的User对象。
*/
public void saveUser(String key, User user) {
redisTemplate.opsForValue().set(key, user);
}
/**
* 根据指定的key从Redis中查询User对象。
*
* @param key 数据在Redis中的唯一标识符。
* @return 与key对应的数据,这里是一个User对象。
*/
public User findUser(String key) {
return (User) redisTemplate.opsForValue().get(key);
}
/**
* 根据指定的key从Redis中删除User对象。
*
* @param key 要删除的User对象在Redis中的标识符。
*/
public void deleteUser(String key) {
redisTemplate.delete(key);
}
}
最后创建一个简单的控制器来测试Redis的CRUD操作。
package com.example.demo.controller;
import com.example.demo.model.User;
import com.example.demo.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* Redis控制器,负责处理与Redis缓存相关的HTTP请求。
*/
@RestController
@RequestMapping("/redis")
public class RedisController {
@Autowired
private RedisService redisService;
/**
* 保存键值对到Redis缓存。
* 如果键不存在,则保存键值对;否则返回提示信息。
*
* @param key 键
* @param value 值
* @return 保存结果的提示信息
*/
@PostMapping("/save")
public String save(@RequestParam String key, @RequestParam String value) {
if (redisService.find(key) == null) {
redisService.save(key, value);
return "保存的!";
}
return "键已存在!";
}
/**
* 通过键查询Redis缓存中的值。
* 如果键存在,则返回对应的值;否则返回提示信息。
*
* @param key 键
* @return 查询结果或提示信息
*/
@GetMapping("/find")
public Object find(@RequestParam String key) {
if (redisService.find(key) != null) {
return redisService.find(key);
}
return "没有找到!";
}
/**
* 通过键从Redis缓存中删除值。
* 如果键存在,则删除对应的值并返回提示信息;否则返回提示信息。
*
* @param key 键
* @return 删除结果的提示信息
*/
@DeleteMapping("/delete")
public String delete(@RequestParam String key) {
if (redisService.find(key) != null) {
redisService.delete(key);
return "删除的!";
}
return "没有找到!";
}
/**
* 保存用户信息到Redis缓存。
* 如果用户ID不存在,则保存用户信息并返回提示信息;否则返回提示信息。
*
* @param user 用户信息
* @return 保存结果的提示信息
*/
@PostMapping("/saveUser")
public String saveUser(@RequestBody User user) {
if (redisService.findUser(user.getId()) == null) {
redisService.saveUser(user.getId(), user);
return "用户已保存!";
}
return "用户已存在!";
}
/**
* 通过用户ID查询Redis缓存中的用户信息。
* 如果用户ID存在,则返回对应的用户信息;否则返回提示信息。
*
* @param id 用户ID
* @return 查询结果或提示信息
*/
@GetMapping("/findUser")
public Object findUser(@RequestParam String id) {
User user = redisService.findUser(id);
if (user != null) {
return user;
}
return "找不到用户!";
}
/**
* 通过用户ID从Redis缓存中删除用户信息。
* 如果用户ID存在,则删除用户信息并返回提示信息;否则返回提示信息。
*
* @param id 用户ID
* @return 删除结果的提示信息
*/
@DeleteMapping("/deleteUser")
public String deleteUser(@RequestParam String id) {
if (redisService.findUser(id) != null) {
redisService.deleteUser(id);
return "用户已删除!";
}
return "找不到用户!";
}
}
测试效果图