目前,Java 连接 Redis 分为两种客户端 一种是 Jedis,另一种则是 Lettuce
注:Spring Boot 2.0+ 使用 spring-boot-starter-data-redis 依赖,默认的客户端使用的是 Lettuce
1、Jedis 和 Lettuce 的区别
Jedis 在实现上,是直接连接的 Redis 服务器,在多个线程间共享一个 Jedis 实例是线程不安全的。如果是需要在多线程的场景下使用 Jedis ,需要使用连接池,让每个线程都使用自己的 Jedis 实例,当线程数量增多时,会消耗比较多的物理资源~
与 Jedis 相比的话,Lettuce 完全克服了前者线程不安全的缺点,多个线程可以共享一个实例,而不用担心多线程的并发问题~
2、Spring Boot 集成 Redis
1、添加相关依赖
<!-- 集成redis依赖(默认使用lettuce) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <!--通过排除 lettuce 依赖来实现 跳过它去用 Jedis,如果需要使用 Jedis,请解除注释下方配置 --> <!-- <exclusions>--> <!-- <exclusion>--> <!-- <groupId>io.lettuce</groupId>--> <!-- <artifactId>lettuce-core</artifactId>--> <!-- </exclusion>--> <!-- </exclusions>--> </dependency> <!-- 连接池所需的依赖 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency> <!--引入Jedis 依赖--> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency>
2、添加数据源配置
我新建了一个 application-redis-test.yml 不清楚如何引用外部配置的,请移步 【Spring Boot学习笔记】配置文件的理解
#这个是Redis的配置文件 spring: data: redis: #Redis服务器地址 host: 127.0.0.1 #Redis服务端口 port: 6379 #Redis链接密码 password: 114514 #使用第几个数据库 database: 0 #链接超时时间 timeout: 1000 #这个是针对 lettuce客户端的配置 lettuce: pool: #最大活跃连接 max-active: 8 #最大空闲连接(连接空闲时会保留在连接池中,后续可以直接复用) max-idle: 8 #最小空闲连接 min-idle: 0 max-wait: 1000 # 连接等待时间,单位毫秒 #这个是针对 jedis客户端的配置 jedis: pool: #最大活跃连接 max-active: 8 #最大空闲连接(连接空闲时会保留在连接池中,后续可以直接复用) max-idle: 8 #最小空闲连接 min-idle: 0 max-wait: 1000 # 连接等待时间,单位毫秒
3、定义Redis Config
这个是设定序列化与反序列化格式的~
/**
* 这个类是设定key-value的序列化与反序列化
* 告诉 Redis,我要把key序列化为String ,value序列化为Json
*/
@Configuration
public class RedisConfig {
@Bean(name="redisTemplate")
@SuppressWarnings("all")//暂时解决版本问题,导致报错 无法自动装配。找不到 'RedisConnectionFactory' 类型的 Bean。
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 设置key序列化方式string,RedisSerializer.string() 等价于 new StringRedisSerializer()
redisTemplate.setKeySerializer(RedisSerializer.string());
// 设置value的序列化方式json,使用GenericJackson2JsonRedisSerializer替换默认序列化,RedisSerializer.json() 等价于 new GenericJackson2JsonRedisSerializer()
redisTemplate.setValueSerializer(RedisSerializer.json());
// 设置hash的key的序列化方式
redisTemplate.setHashKeySerializer(RedisSerializer.string());
// 设置hash的value的序列化方式
redisTemplate.setHashValueSerializer(RedisSerializer.json());
// 使配置生效
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}4、创建 RedisUtil
这个根据自己需要,创建一个Redis统一的操作类,方便后续开发,这边我直接就用构造方法把Template注入了~
不到万不得已,别去用手动获取Bean!!!
@Component//非常重要,不然无法使用构造方法注入!,这个是告诉 Spring ,要以它管理的Bean加载到容器中~
public class RedisUtil {
//private static RedisTemplate<String, Object> redisTemplate = SpringContextUtils.getBean("redisTemplate", RedisTemplate.class);
private final RedisTemplate<String, Object> _redisTemplate;
public RedisUtil(RedisTemplate<String, Object> redisTemplate) {
_redisTemplate = redisTemplate;
}
/**
* 指定缓存失效时间
*
* @param key 键
* @param time 时间(秒)
* @return
*/
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 键 不能为null
* @return 时间(秒) 返回-1代表为永久有效 失效时间为0,说明该主键未设置失效时间(失效时间默认为-1)
*/
public Long getExpire(String key) {
return _redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
/**
* 判断key是否存在
*
* @param key 键
* @return true 存在 false 不存在
*/
public Boolean hasKey(String key) {
try {
return _redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除缓存
*
* @param key 可以传一个值 或多个
*/
@SuppressWarnings("unchecked")
public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
_redisTemplate.delete(key[0]);
} else {
var keys = (List<String>) CollectionUtils.arrayToList(key);
_redisTemplate.delete(keys);
}
}
}
/**
* 普通缓存获取
*
* @param key 键
* @return 值
*/
@SuppressWarnings("unchecked")
public <T> T get(String key) {
T res=key==null?null:(T)(_redisTemplate.opsForValue().get(key));
//return key == null ? null : (T) _redisTemplate.opsForValue().get(key);
return res;
}
/**
* 普通缓存放入并设置时间
*
* @param key 键
* @param value 值
* @param time 时间(秒) time要大于0 如果time小于等于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 {
_redisTemplate.opsForValue().set(key, value);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}目前,前期的部署操作已经完成,下面创建测试方法~
5、初步体验
在Service里面创建一个方法,可以根据自己的需求进行编写,我这边是如果在Redis中查到了这个用户的话,我把这个人的uid改为20000,如果没有查到的话,正常从数据库获取一遍,然后写入Redis,Key就是 KEY_USERINFO_xxx,这个 xxx 就是查询的用户名,大概像这样 (仅仅一个测试案例,别杠!)
private final RedisUtil _redisUtil;
public UserService(RedisUtil redisUtil) {
_redisUtil=redisUtil;
}
//缓存实验
public UserInfo redisTest(String name){
UserInfo ui=null;
ui=_redisUtil.get("KEY_USERINFO_"+name);//获取数据
if(ui==null) {
QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().like(UserInfo::getName, name).last("LIMIT 1");
ui = userInfoMapper.selectOne(queryWrapper);
if (ui != null) {
_redisUtil.set("KEY_USERINFO_" + name, ui, (60 * 60 * 24));//缓存一天
}
}else{
ui.setUid(20000);
}
return ui;
}Controller那边我就不写了,删除就是 _redisUtil.del(key),当然多个key一起传也行~
测试效果:

刷新一下就变成了

完事~

微信扫码查看本文
发表评论