背景介绍
最近在做一个硬件项目需要硬件上传数据,然后解析保存到redis里然后由后台去读取redis里的数据.第一选择采用方便的redis官方首选的java客户端jedis.后来发现很多同行在使用中发现jedis连接增多后会报连接超时的异常,而且springboot在2.0版本以后,底层连接池已经换成了lettuce.但是依然要做个记录
使用场景spring boot2.2+
pom应用
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.1.0</version>
</dependency>
yml配置
spring:
#redis单机版
redis:
host: ${parm.redis.host-name}
port: ${parm.redis.port}
# 密码 没有则可以不填
password: ${parm.redis.pwd}
database: ${parm.redis.db1}
timeout: 2000
jedis:
pool:
max-total: 12
# 最大活跃链接数 默认8(使用负值表示没有限制)
max-active: 12
# 最大空闲连接数 默认8
max-idle: 12
# 最小空闲连接数 默认0
min-idle: 0
# 连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1
jedis启动时配置
启动时配置全局的jedispool,这样能保证每一次获取的jedis连接都是去连接池里面获取,不然每次如果配置jedispool那么就是每次获取了一个jedis连接池.因此在启动时将jedispool的配置交给spring来管理.配置一次全局的
@Configuration
public class RedisConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.password}")
private String password;
@Value("${spring.redis.timeout}")
private int timeout;
@Value("${spring.redis.jedis.pool.max-active}")
private int maxActive;
@Value("${spring.redis.jedis.pool.max-idle}")
private int maxIdle;
@Value("${spring.redis.jedis.pool.min-idle}")
private int minIdle;
@Value("${spring.redis.jedis.pool.max-wait}")
private long maxWaitMillis;
@Bean
public JedisPool generateJedisPoolFactory() {
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(maxActive);
poolConfig.setMaxIdle(maxIdle);
poolConfig.setMinIdle(minIdle);
poolConfig.setMaxWaitMillis(maxWaitMillis);
JedisPool jedisPool = new JedisPool(poolConfig, host, port, timeout, password);
return jedisPool;
}
}
jedis工具类
为什么要封装工具类,
首先如果需要操作redis的业务接口比较多,那么就需要多个连接,需要用到jedis连接池,
其次在使用中发现,如果每次new一个jedis实例,产生一个链接,如果使用完不释放回jedis链接池的话,那么当链接多了的话,就会发生链接被占用,产生链接阻塞.无法访问redis,
这样就需要把每一次的链接调用,封装到工具类里面.使用完了就释放资源
这里特别记录一点:在封装工具类的时候本来在类中添加@component,就可以在其它地方通过@Autowried的方式来注入了,但是不要忘记,我需要在jedis工具类中引用jedispool,而这个jedispool是在启动的时候交给spring托管,返回的一个实体,并不是自定义了一个类,所以在本工具类中,通过注入的方式识别不了,具体原因有待详细的去调查…不过无所谓了…计划换redisTemplte了…在这里坐下记录这是用的@Service接口服务方式实现
@Service
public class RedisServiceImpl implements IRedisService {
@Autowired
public JedisPool jedisPool;
//region 哈希方法
@Override
public Long hset(int dbNum, String key, String field, String value) {
Jedis jedisSet = null;
Long susNum = 0L;
try {
jedisSet = jedisPool.getResource();
jedisSet.select(dbNum);
jedisSet.hset(key, field, value);
} catch (Exception e) {
if (null != jedisSet) {
// 释放jedis对象
jedisSet.close();
}
return null;
} finally {
jedisSet.close();
}
return susNum;
}
/**
* hset
*
* @param key
* @param map
* @param dbNum
*/
@Override
public void hset(String key, Map<String, String> map, int dbNum) {
Jedis jedisSet = jedisPool.getResource();
jedisSet.select(dbNum);
try {
jedisSet.hset(key, map);
} catch (Exception e) {
if (null != jedisSet) {
// 释放jedis对象
jedisSet.close();
}
} finally {
jedisSet.close();
}
}
/**
* hget
*
* @param key
* @param field
* @return
*/
@Override
public String hget(String key, String field, int dbNum) {
Jedis jedisSet = jedisPool.getResource();
jedisSet.select(dbNum);
String object = "";
try {
object = jedisSet.hget(key, field);
} catch (Exception e) {
if (null != jedisSet) {
// 释放jedis对象
jedisSet.close();
}
return null;
} finally {
jedisSet.close();
}
return object;
}
//endregion
//region bit
/**
* 设置bit,使用场景签到等
*
* @param key
* @param offset
* @param value
* @param dbNum
*/
@Override
public void setbit(String key, long offset, boolean value, int dbNum) {
Jedis jedis = jedisPool.getResource();
jedis.select(dbNum);
try {
jedis.setbit(key, offset, value);
} catch (Exception e) {
if (null != jedis) {
// 释放jedis对象
jedis.close();
}
} finally {
jedis.close();
}
}
/**
* 获取bit
*
* @param key
* @param offset
* @param dbNum
* @return
*/
@Override
public Boolean getbit(String key, long offset, int dbNum) {
Jedis jedis = jedisPool.getResource();
jedis.select(dbNum);
boolean transpotStatus = false;
try {
transpotStatus = jedis.getbit(key, offset);
} catch (Exception e) {
if (null != jedis) {
// 释放jedis对象 返回连接池
jedis.close();
}
} finally {
jedis.close();
}
return transpotStatus;
}
/**
* 获取某库中的所有key
*
* @param dbNum
* @return
*/
@Override
public List<String> getAllKeys(int dbNum) {
Jedis jedis = jedisPool.getResource();
jedis.select(dbNum);
List<String> resultList = new ArrayList<>();
try {
String cursor = "0";
do {
ScanParams scanParams = new ScanParams();
//要查询的key,*代表所有的
scanParams.match("*");
//每次查询的数量
scanParams.count(10);
ScanResult<String> sr = jedis.scan(cursor, scanParams);
resultList.addAll(sr.getResult());
cursor = sr.getCursor();
//没有下一页则退出
} while (!cursor.equals("0"));
} catch (Exception e) {
if (null != jedis) {
// 释放jedis对象
jedis.close();
}
} finally {
jedis.close();
}
return resultList;
}
//endregion
//region List--queue 队列
/**
* 右进队
*
* @param dbNum
* @param key
* @param strings
* @return
*/
@Override
public Long rpush(int dbNum, String key, String... strings) {
Jedis jedisSet = jedisPool.getResource();
jedisSet.select(dbNum);
Long susNum = 0L;
try {
susNum = jedisSet.rpush(key, strings);
} catch (Exception e) {
if (null != jedisSet) {
// 释放jedis对象
jedisSet.close();
}
return null;
} finally {
jedisSet.close();
}
return susNum;
}
/**
* 左出队
*
* @param dbNum
* @param key
* @return
*/
@Override
public String lpop(int dbNum, String key) {
Jedis jedisSet = jedisPool.getResource();
jedisSet.select(dbNum);
String data = "";
try {
data = jedisSet.lpop(key);
} catch (Exception e) {
if (null != jedisSet) {
// 释放jedis对象
jedisSet.close();
}
return null;
} finally {
jedisSet.close();
}
return data;
}
//endregion
}
调用
在需要的地方直接注入这个service调用就行