当我们项目需要使用缓存并且高并发的时候,可以使用redis连接池,让我们直奔主题。本文项目环境win 10,springboot 2.1.5.RELEASE,redis Java客户端jedis 2.9.3,fastjson 1.2.47(用于序列化)。本项目使用了lombok插件,所以set,get方法用注解代替。
1.引入redis客户端依赖
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency>
2.在application.properties文件中添加配置
#redis redis.host=127.0.0.1 redis.port=6379 redis.timeout=10 redis.poolMaxTotal=1000 redis.poolMaxIdle=500 redis.poolMaxWait=500
3.编写实体类RedisConfig接收配置
/** * 读取配置文件的redis信息 */ @Data @Component @ConfigurationProperties(prefix = "redis")//会读取前缀为redis的配置 public class RedisConfig { private String host; private int port; private int timeout; private String password; private int poolMaxTotal; private int poolMaxIdle; private int poolMaxWait; }
4.编写RedisPoolFactory类,该类返回一个redis连接池。
@Service public class RedisPoolFactory { @Autowired RedisConfig redisConfig; /** * 将redis连接池注入spring容器 * @return */ @Bean public JedisPool JedisPoolFactory(){ JedisPoolConfig config = new JedisPoolConfig(); config.setMaxIdle(redisConfig.getPoolMaxIdle()); config.setMaxTotal(redisConfig.getPoolMaxTotal()); config.setMaxWaitMillis(redisConfig.getPoolMaxWait() * 1000); JedisPool jp = new JedisPool(config, redisConfig.getHost(), redisConfig.getPort(), redisConfig.getTimeout()*1000, redisConfig.getPassword(), 0); return jp; } }
5.自己编写redis方法类
重写的方法会给key加上前缀,好处就是可以分类,避免重复和批量删除
@Service public class RedisService { @Autowired JedisPool jedisPool; /** * 从redis连接池获取redis实例 */ public <T> T get(KeyPrefix prefix, String key, Class<T> clazz) { Jedis jedis = null; try { jedis = jedisPool.getResource(); //对key增加前缀,即可用于分类,也避免key重复 String realKey = prefix.getPrefix() + key; String str = jedis.get(realKey); T t = stringToBean(str, clazz); return t; } finally { returnToPool(jedis); } } /** * 存储对象 */ public <T> Boolean set(KeyPrefix prefix, String key, T value) { Jedis jedis = null; try { jedis = jedisPool.getResource(); String str = beanToString(value); if (str == null || str.length() <= 0) { return false; } String realKey = prefix.getPrefix() + key; int seconds = prefix.expireSeconds();//获取过期时间 if (seconds <= 0) { jedis.set(realKey, str); } else { jedis.setex(realKey, seconds, str); } return true; } finally { returnToPool(jedis); } } /** * 删除 */ public boolean delete(KeyPrefix prefix, String key) { Jedis jedis = null; try { jedis = jedisPool.getResource(); //生成真正的key String realKey = prefix.getPrefix() + key; long ret = jedis.del(realKey); return ret > 0; } finally { returnToPool(jedis); } } /** * 判断key是否存在 */ public <T> boolean exists(KeyPrefix prefix, String key) { Jedis jedis = null; try { jedis = jedisPool.getResource(); //生成真正的key String realKey = prefix.getPrefix() + key; return jedis.exists(realKey); } finally { returnToPool(jedis); } } /** * 增加值 * Redis Incr 命令将 key 中储存的数字值增一。 如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作 */ public <T> Long incr(KeyPrefix prefix, String key) { Jedis jedis = null; try { jedis = jedisPool.getResource(); //生成真正的key String realKey = prefix.getPrefix() + key; return jedis.incr(realKey); } finally { returnToPool(jedis); } } /** * 减少值 */ public <T> Long decr(KeyPrefix prefix, String key) { Jedis jedis = null; try { jedis = jedisPool.getResource(); //生成真正的key String realKey = prefix.getPrefix() + key; return jedis.decr(realKey); } finally { returnToPool(jedis); } } public static <T> String beanToString(T value) { if (value == null) { return null; } Class<?> clazz = value.getClass(); if (clazz == int.class || clazz == Integer.class) { return String.valueOf(value); } else if (clazz == long.class || clazz == Long.class) { return String.valueOf(value); } else if (clazz == String.class) { return (String) value; } else { return JSON.toJSONString(value); } } public static <T> T stringToBean(String str, Class<T> clazz) { if (str == null || str.length() <= 0 || clazz == null) { return null; } if (clazz == int.class || clazz == Integer.class) { return (T) Integer.valueOf(str); } else if (clazz == long.class || clazz == Long.class) { return (T) Long.valueOf(str); } else if (clazz == String.class) { return (T) str; } else { return JSON.toJavaObject(JSON.parseObject(str), clazz); } } private void returnToPool(Jedis jedis) { if (jedis != null) { jedis.close();//不是关闭,只是返回连接池 } } }
6.测试
@Test public void RedisServiceTest() { Boolean aBoolean = redisService.set(GoodsKey.getGoodsStock, "huawei", "500"); System.out.println(aBoolean);//aBoolean=true }
本文使用了redis连接池,并且给redis的键加上了前缀,好处是便于分类和避免重复。当需要储存对象时,可以将对象序列化后然后储存。