每次学习到新的知识,最期待的一步就是整合SpringBoot,这真的很令人兴奋!废话少说,我们赶快开始进行SpringBoot整合Redis的学习!
SpringBoot整合Redis
Spring整合Redis要借助SpringData,之前使用的是jedis,现在被替换成了lettuce
替换原因:
jedis采用直连方式,多个线程操作的话是不安全的,如果想要避免这个问题,就需要使用连接池技术,可能会发生阻塞(BIO)。
lettuce底层使用netty(异步事件驱动的 NIO 框架),实例可以在多个线程中共享,不存在线程不安全的情况,可以减少线程,发生阻塞的情况相比于jedis少,性能也就更加优秀。
1.导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- spring boot 2.x以后 redis客户端默认使用lettuce, lettuce连接池需显示依赖commons-pool2 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
2.在配置文件中配置Redis连接(两种配置文件选其一,看自己配置文件的尾缀)
在application.properties文件中配置Redis连接
spirng.redis.host=127.0.0.1
spring.redis.port=6379
在application.yml文件中配置
spring:
# redis配置
redis:
# 连接主机IP
host: 127.0.0.1
# 端口号
port: 6800
# 超时时间
timeout: 3000ms
# 默认数据库
database: 0
# 密码
password: 123456
# lettuce连接池
lettuce:
pool:
max-active: 8
min-idle: 0
max-idle: 8
max-wait: -1ms
3.测试连接
package com.test;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisTemplate;
@SpringBootTest
class RedisSpringBootApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void contextLoads() {
// redisTemplate 用来操作不同数据类型,操作方法及释义↓
// opsForValue 操作字符串
// opsForList 操作list集合
// opsForSet 操作set集合
// opsForHash 操作hash集合
// opsForZset 操作Zset集合
// opsForGeo 操作地理位置
// opsForHyperloglog 操作hyperloglog
// opsForStream 操作Bitmap
// opsForCluster 操作集群
//获取Redis数据库连接
RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
// 测试数据库连接
connection.ping();
// 清空当前数据库
connection.flushDb();
// 清空全部数据库
connection.flushAll();
}
}
我们连接上了Redis后会有一个问题,就是当前我们连接的Redis是没有序列化的,也就是说我们在Java代码中输入的中文,在Redis服务器上打开会显示乱码,我们需要自己自定义一个配置类来解决这个问题。
并且一般情况下我们不会传Java对象作为value,我们都会先将Java对象转换成JSON字符串后进行传输。
自定义配置类进行序列化
package com.test.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.net.UnknownHostException;
/**
* @author ME
* @date 2022/3/13 14:10
*/
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
// Json序列化配置
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// String序列化配置
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key 与 hash类型的key使用String类型的序列化
template.setKeySerializer(stringRedisSerializer);
template.setHashKeySerializer(stringRedisSerializer);
// value 与 hash类型的value使用json类型的序列化
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
// 保存修改
template.afterPropertiesSet();
return template;
}
}
最后友情附送一下Redis工具类,对底层常用方法进行封装,手打了一个多小时QAQ
package com.test.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* @author ME
* @date 2022/3/13 14:39
*/
@Component
public final class RedisUtil {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// =============================公共============================
/**
* 指定key失效时间
* @param key key的名称
* @param time 时间(秒)
* @return true成功 false 失败
*/
public boolean expire(String key, long time) {
try{
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
}catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据key获取过期时间
* @param key key的名称 不能为null
* @return 时间(秒) 返回0代表永久有效
*/
public long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
/**
* 判断key是否存在
* @param key key的名称
* @return true成功 false 失败
*/
public boolean hasKey(String key) {
try{
return redisTemplate.hasKey(key);
}catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除key
* @param key key的名称
*/
public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
}else {
redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key));
}
}
}
// ==============================String====================================================
/**
* 获取String类型的值
* @param key
* @return
*/
public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}
/**
* 保存String类型的键值对
* @param key key的名称
* @param value 值的内容
* @return true成功 false 失败
*/
public boolean set(String key, Object value) {
try{
redisTemplate.opsForValue().set(key, value);
return true;
}catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 保存String类型的键值对并设置过期时间
* @param key key的名称
* @param value 值的内容
* @param time 时间(秒) time要大于0,如果小于等于0则为永久有效
* @return true成功 false失败
*/
public boolean set(String key, Object value, long time) {
try{
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
}else {
set(key, value);
}
return true;
}catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 递增
* @param key key的名称
* @param delta 增加的数量-步长
*/
public long incr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递增因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, delta);
}
/**
* 递减
* @param key key的名称
* @param delta 减少的数量-步长
*/
public long decr(String key, long delta) {
if (delta > 0) {
throw new RuntimeException("递减因子必须小于0");
}
return redisTemplate.opsForValue().increment(key, -delta);
}
// ============================Hash==========================================
/**
* 获取hash列表中的单个map集合
* @param key mapName的名称
* @param item key的名称
*/
public Object hget(String key, String item) {
return redisTemplate.opsForHash().get(key, item);
}
/**
* 获取hash集合的所有键值对
* @param key mapName的名称
* @return 多个键值对
*/
public Map<Object, Object> hmget(String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* 将元素批量放入hash集合
* @param key mapName的名称
* @param map map集合
* @return true成功 false失败
*/
public boolean hmset(String key, Map<String, Object> map) {
try{
redisTemplate.opsForHash().putAll(key, map);
return true;
}catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将元素批量放入hash集合并设置过期时间
* @param key mapName的名称
* @param map map集合
* @param time 设置的过期时间(秒)
* @return true成功 false失败
*/
public boolean hmset(String key, Map<String, Object> map, long time) {
try{
redisTemplate.opsForHash().putAll(key, map);
if (time > 0) {
expire(key, time);
}
return true;
}catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向hash集合中添加数据,如果不存在则创建
* @param key mapName的名称
* @param item key的名称
* @param value 值的内容
* @return true成功 false失败
*/
public boolean hset(String key, String item, Object value) {
try {
redisTemplate.opsForHash().put(key, item, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向hash集合中添加数据,如果不存在则创建
* @param key mapName的名称
* @param item key的名称
* @param value 值的内容
* @param time 设置的过期时间(秒)
* @return true成功 false失败
*/
public boolean hset(String key, String item, Object value, long time) {
try {
redisTemplate.opsForHash().put(key, item, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除hash集合中的值
* @param key mapName的名称
* @param item key的名称
*/
public void hdel(String key, Object... item) {
redisTemplate.opsForHash().delete(key, item);
}
/**
* 判断hash集合中是否有该值
* @param key mapName的名称
* @param item key的名称
* @return true成功 false失败
*/
public boolean hHaskey(String key, Object item) {
return redisTemplate.opsForHash().hasKey(key, item);
}
/**
* hash递增,如果不存在则创建一个,并将创建并新增以后的值返回
* @param key mapName的名称
* @param item key的名称
* @param by 增加的步长
*/
public double hincr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, by);
}
/**
* hash递减,如果不存在则创建一个,并将创建并新增以后的值返回
* @param key mapName的名称
* @param item key的名称
* @param by 减少的步长
*/
public double hdecr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, -by);
}
// ===============================Set=============================================
/**
* 根据key获取set集合中的值
* @param key key的名称
* @return
*/
public Set<Object> sGet(String key) {
try{
return redisTemplate.opsForSet().members(key);
}catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 查询此值在set集合中是否存在
* @param key key的名称
* @param value value的内容
* @return
*/
public boolean sHasKey(String key, Object value) {
try {
return redisTemplate.opsForSet().isMember(key, value);
}catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将元素保存到set集合中
* @param key key的名称
* @param values 多个value内容
* @return 成功个数
*/
public long sSet(String key, Object... values) {
try{
return redisTemplate.opsForSet().add(key, values);
}catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 将元素保存到set集合中并设置过期时间
* @param key key的名称
* @param time 过期时间(秒)
* @param values 多个value内容
* @return 成功个数
*/
public long sSetAndTime(String key, long time, Object... values) {
try{
Long count = redisTemplate.opsForSet().add(key, values);
if (time > 0) {
expire(key, time);
}
return count;
}catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 获取Set集合的长度
* @param key key的名称
*/
public long sGetSetSize(String key) {
try{
return redisTemplate.opsForSet().size(key);
}catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 移除Set集合中值为value的元素
* @param key key的名称
* @param values 多个值的内容
* @return 移除的个数
*/
public long setRemove(String key, Object... values) {
try {
Long count = redisTemplate.opsForSet().remove(key, values);
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
// ================================List===================================
/**
* 获取list集合的长度
* @param key key的名称
* @return
*/
public long lGetListSize(String key) {
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 通过索引获取list集合中的值
* @param key key的名称
* @param index 索引下标
*/
public Object lGetIndex(String key, long index) {
try {
return redisTemplate.opsForList().index(key, index);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 将键值对放入list集合
* @param key key的名称
* @param value 值的内容
* @return
*/
public boolean lSet(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将键值对放入list集合并设置过期时间
* @param key key的名称
* @param value 值的内容
* @param time 过期时间(秒)
* @return
*/
public boolean lSet(String key, Object value, long time) {
try {
redisTemplate.opsForList().rightPush(key, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将键值对放入list集合
* @param key key的名称
* @param values 多个值的内容
* @return
*/
public boolean lSet(String key, List<Object> values) {
try {
redisTemplate.opsForList().rightPushAll(key, values);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将键值对放入list集合
* @param key key的名称
* @param values 多个值的内容
* @param time 过期时间(秒)
* @return
*/
public boolean lSet(String key, List<Object> values, long time) {
try {
redisTemplate.opsForList().rightPushAll(key, values);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据索引修改list集合中的某条数据
* @param key key的名称
* @param index 索引下标
* @param value 值的内容
* @return
*/
public boolean lUpdateIndex(String key, long index, Object value) {
try {
redisTemplate.opsForList().set(key, index, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 移除集合中指定value的所有值
* @param key key的名称
* @param count 自定义需要移除的个数
* @param value 值的内容
* @return 移除的个数
*/
public long lRemove(String key, long count, Object value) {
try {
Long removeCount = redisTemplate.opsForList().remove(key, count, value);
return removeCount;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
}
下一篇请戳↓