RedisTemplate
此笔记是学习之初做的,很多是从别人的博客中学习来的,献丑了,抛砖引玉
近两年的开发中我很少使用 RedisTemplate 了,使用自己整合 Jedis ,自行整合 Redis 请查看: https://www.cnblogs.com/Alay/p/15092531.html
配置系列化:
@Configuration @EnableCaching public class CacheConfig extends CachingConfigurerSupport { @Bean public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) { StringRedisTemplate template = new StringRedisTemplate(factory); //定义key序列化方式 //RedisSerializer<String> redisSerializer = new StringRedisSerializer();//Long类型会出现异常信息;需要我们上面的自定义key生成策略,一般没必要 //定义value的序列化方式 Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); // template.setKeySerializer(redisSerializer); template.setValueSerializer(jackson2JsonRedisSerializer); template.setHashValueSerializer(jackson2JsonRedisSerializer); template.afterPropertiesSet(); return template; } }
或
@Configuration public class RedisConfig { @Bean public <T> RedisTemplate<String, T> redisTemplateKeyString(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<String, T> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); jackson2JsonRedisSerializer.setObjectMapper(objectMapper); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); redisTemplate.afterPropertiesSet(); return redisTemplate; } /**配置其他类型的redisTemplate***/ @Bean public RedisTemplate<Object, Object> redisTemplateKeyObject(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); jackson2JsonRedisSerializer.setObjectMapper(objectMapper); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); redisTemplate.afterPropertiesSet(); return 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 键 * @return 时间(秒),返回0代表永久有效 */ public long getExpireTime(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; } }
String类型:
/** * String类型获取值 * * @param key 键 * @return 值 */ public Object get(String key) { return key == null ? null : redisTemplate.opsForValue().get(key); } /** * 添加缓存并设置过期时间 * * @param key 键 * @param value 值 * @param time 时间(秒) * @return true成功 false失败 */ public boolean set(String key, Object value, long time) { try { redisTemplate.opsForValue().set(key, value, time); return true; } catch (Exception e) { e.printStackTrace(); return false; } }
递增递减
/** * 递增 * * @param key 键 * @return */ public long incr(String key, long delta) { if (delta < 0) { throw new RuntimeException("递增因子必须大于0"); } return redisTemplate.opsForValue().increment(key, delta); } /** * 递减 * * @param key 键 * @return */ public long decr(String key, long delta) { if (delta < 0) { throw new RuntimeException("递减因子必须大于0"); } return redisTemplate.opsForValue().increment(key, -delta); }
Hash类型
/** * HashGet * * @param key 键 不能为null * @param item 项 不能为null * @return 值 */ public Object hget(String key, String item) { return redisTemplate.opsForHash().get(key, item); } /** * 获取hashKey对应的所有键值 * * @param key 键 * @return 对应的多个键值 */ public Map<Object, Object> hmget(String key) { return redisTemplate.opsForHash().entries(key); } /** * HashSet * * @param key 键 * @param 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; } } /** * HashSet 并设置时间 * * @param key 键 * @param 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 键 * @param item 项 * @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 键 * @param item 项 * @param value 值 * @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间 * @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 键 不能为null * @param item 项 可以使多个 不能为null */ public void hdel(String key, Object... item) { redisTemplate.opsForHash().delete(key, item); } /** * 判断hash表中是否有该项的值 * * @param key 键 不能为null * @param item 项 不能为null * @return true 存在 false不存在 */ public boolean hHasKey(String key, String item) { return redisTemplate.opsForHash().hasKey(key, item); } /** * hash递增 如果不存在,就会创建一个 并把新增后的值返回 * * @param key 键 * @param item 项 * @param by 要增加几(大于0) * @return */ public double hincr(String key, String item, double by) { return redisTemplate.opsForHash().increment(key, item, by); } /** * hash递减 * * @param key 键 * @param item 项 * @param by 要减少记(小于0) * @return */ public double hdecr(String key, String item, double by) { return redisTemplate.opsForHash().increment(key, item, -by); }
Set类型
/** * 根据key获取Set中的所有值 * * @param key 键 * @return */ public Set<Object> sGet(String key) { try { return redisTemplate.opsForSet().members(key); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 根据value从一个set中查询,是否存在 * * @param key 键 * @param value 值 * @return true 存在 false不存在 */ public boolean sHasKey(String key, Object value) { try { return redisTemplate.opsForSet().isMember(key, value); } catch (Exception e) { e.printStackTrace(); return false; } } /** * 将数据放入set缓存 * * @param key 键 * @param values 值 可以是多个 * @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 键 * @param time 时间(秒) * @param values 值 可以是多个 * @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 键 * @return */ public long sGetSetSize(String key) { try { return redisTemplate.opsForSet().size(key); } catch (Exception e) { e.printStackTrace(); return 0; } } /** * 移除值为value的 * * @param 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; } }
@Test public void demo1 () { //集合中添加元素,返回添加个数 redisTemplate.opsForSet().add("games", "鬼泣", "古墓丽影", "仙剑奇侠传", "LOL", "DOTA自走棋"); printSet("games"); } @Test public void demo2 () { //从集合中删除指定元素 redisTemplate.opsForSet().remove("games", "鬼泣"); printSet("games"); } @Test public void demo3 () { //从集合中随机删除一个元素,并返回该元素 String item = redisTemplate.opsForSet().pop("games"); System.out.println(item); printSet("games"); } @Test public void demo4 () { //将集合1中的指定元素移到集合2 redisTemplate.opsForSet().move("games", "仙剑奇侠传", "chinese-games"); //打印集合1 printSet("games"); //打印集合2 printSet("chinese-games"); } @Test public void demo5 () { //获得集合大小 Long size = redisTemplate.opsForSet().size("games"); printSet("games"); System.out.println(size); } @Test public void demo6 () { //判断集合中是否存在某元素 Boolean ifExist = redisTemplate.opsForSet().isMember("games", "LOL"); System.out.println(ifExist); } @Test public void demo7 () { //添加集合a redisTemplate.opsForSet().add("set-a", "a", "b", "c", "d"); //添加集合b redisTemplate.opsForSet().add("set-b", "a", "b"); //求交集 Set<String> intersection = redisTemplate.opsForSet().intersect("set-a", "set-b"); //也可以和多个key对应的集合求交集 Set<V> intersect(K key, K otherKey); System.out.println(intersection); } @Test public void demo8 () { //添加集合a redisTemplate.opsForSet().add("set-a", "a", "b", "c", "d"); //添加集合b redisTemplate.opsForSet().add("set-b", "a", "b"); //求交集并放入集合c redisTemplate.opsForSet().intersectAndStore("set-a", "set-b", "set-c"); //也可以和多个key对应的集合求交集 Long intersectAndStore(K key, Collection<K> otherKeys, K destKey); //打印集合c printSet("set-c"); } @Test public void demo9 () { //添加集合m redisTemplate.opsForSet().add("set-m", "a", "b", "c", "d"); //添加集合n redisTemplate.opsForSet().add("set-n", "c", "d", "e", "f"); //求并集 Set<String> union = redisTemplate.opsForSet().union("set-m", "set-n"); System.out.println(union); //其他操作与intersect类似 如和多个key求并集,求并集并放入集合等 } @Test public void demo10 () { //添加集合d redisTemplate.opsForSet().add("set-d", "a", "b", "c", "d"); //添加集合e redisTemplate.opsForSet().add("set-e", "c", "d", "e", "f"); //添加集合f redisTemplate.opsForSet().add("set-f", "e", "f", "g", "h"); //求差集(属于d不属于e和f) Set<String> difference = redisTemplate.opsForSet().difference("set-d", Arrays.asList("set-e", "set-f")); System.out.println(difference); //其他操作与交集并集类似 } @Test public void demo11 () { //随机获取集合中的一个元素 System.out.println(redisTemplate.opsForSet().randomMember("games")); //随机获取集合中指定个数的元素(有可能重复) System.out.println(redisTemplate.opsForSet().randomMembers("games", 10)); //随机获取集合中指定个数的元素(不重复) System.out.println(redisTemplate.opsForSet().distinctRandomMembers("games", 10)); } /** * 打印集合 * @date 2019年2月12日 * @author baipengfei * @param key */ private void printSet (String key){ //获取所有成员 Set<String> members = redisTemplate.opsForSet().members(key); System.out.println(members); }
List类型
/** * 获取list缓存的内容 * * @param key 键 * @param start 开始 * @param end 结束 0 到 -1代表所有值 * @return */ public List<Object> lGet(String key, long start, long end) { try { return redisTemplate.opsForList().range(key, start, end); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 获取list缓存的长度 * * @param key 键 * @return */ public long lGetListSize(String key) { try { return redisTemplate.opsForList().size(key); } catch (Exception e) { e.printStackTrace(); return 0; } } /** * 通过索引 获取list中的值 * * @param key 键 * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推 * @return */ public Object lGetIndex(String key, long index) { try { return redisTemplate.opsForList().index(key, index); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 将list放入缓存 * * @param 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 键 * @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 键 * @param value 值 * @return */ public boolean lSet(String key, List<Object> value) { try { redisTemplate.opsForList().rightPushAll(key, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 将list放入缓存 * * @param key 键 * @param value 值 * @param time 时间(秒) * @return */ public boolean lSet(String key, List<Object> value, long time) { try { redisTemplate.opsForList().rightPushAll(key, value); if (time > 0) expire(key, time); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 根据索引修改list中的某条数据 * * @param 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; } } /** * 移除N个值为value * * @param key 键 * @param count 移除多少个 * @param value 值 * @return 移除的个数 */ public long lRemove(String key, long count, Object value) { try { Long remove = redisTemplate.opsForList().remove(key, count, value); return remove; } catch (Exception e) { e.printStackTrace(); return 0; } } }
redisTemplate.opsForValue().set("test", "100", 60 * 10, TimeUnit.SECONDS);//向redis里存入数据和设置缓存时间 redisTemplate.boundValueOps("test").increment(-1);//val做-1操作 redisTemplate.opsForValue().get("test")//根据key获取缓存中的val redisTemplate.boundValueOps("test").increment(1);//val +1 redisTemplate.getExpire("test")//根据key获取过期时间 redisTemplate.getExpire("test", TimeUnit.SECONDS)//根据key获取过期时间并换算成指定单位 redisTemplate.delete("test");//根据key删除缓存 redisTemplate.hasKey("546545");//检查key是否存在,返回boolean值,若返回值总是 true ,解决方案:注入对象 RedisTemplate 改为 StringRedisTemplate redisTemplate.opsForSet().add("red_123", "1", "2", "3");//向指定key中存放set集合 redisTemplate.expire("red_123", 1000, TimeUnit.MILLISECONDS);//设置过期时间 redisTemplate.opsForSet().isMember("red_123", "1")//根据key查看集合中是否存在指定数据
Redis实现附近的人示例(不要用,推荐使用 Searche 或其他NoSQL)
@Component public class RedisGeoUtils { @Autowired RedisTemplate redisTemplate; /** * 添加经纬度信息,时间复杂度为O(log(N)) * redis 命令:geoadd cityGeo 116.405285 39.904989 "北京" * * @param k * @param point * @param m */ public Long addGeoPoin(Object k, Point point, Object m) { Long addedNum = redisTemplate.opsForGeo().geoAdd(k, point, m); return addedNum; } /** * 查找指定key的经纬度信息,可以指定多个key,批量返回 * redis命令:geopos cityGeo 北京 * * @param k * @param m */ public List<Point> geoGet(Object k, Object... m) { List<Point> points = redisTemplate.opsForGeo().geoPos(k, m); return points; } /** * 返回两个地方的距离,可以指定单位,比如米m,千米km,英里mi,英尺ft * redis命令:geodist cityGeo 北京 上海 * * @param k * @param mk1 * @param mk2 * @param metric * @return */ public Distance geoDist(Object k, Object mk1, Object mk2, Metric metric) { Distance distance = redisTemplate.opsForGeo().geoDist(k, mk1, mk2, metric); return distance; } /** * 根据给定的经纬度,返回半径不超过指定距离的元素,时间复杂度为O(N+log(M)),N为指定半径范围内的元素个数,M为要返回的个数 * redis命令:georadius cityGeo 116.405285 39.904989 100 km WITHDIST WITHCOORD ASC COUNT 5 * * @param k * @param circle * @param args */ public void nearByXY(Object k, Circle circle, RedisGeoCommands.GeoRadiusCommandArgs args) { //longitude,latitude //Circle circle = new Circle(116.405285, 39.904989, Metrics.KILOMETERS.getMultiplier()); //RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands .GeoRadiusCommandArgs .newGeoRadiusArgs() .includeDistance() .includeCoordinates() .sortAscending() .limit(5); GeoResults<RedisGeoCommands.GeoLocation<String>> results = redisTemplate.opsForGeo().geoRadius(k, circle, args); System.out.println(results); } /** * 根据指定的地点查询半径在指定范围内的位置,时间复杂度为O(log(N)+M),N为指定半径范围内的元素个数,M为要返回的个数 * redis命令:georadiusbymember cityGeo 北京 100 km WITHDIST WITHCOORD ASC COUNT 5 * * @param k * @param mk * @param distance * @param args * @return */ public GeoResults nearByPlace(Object k, Object mk, Distance distance, RedisGeoCommands.GeoRadiusCommandArgs args) { //Distance distance = new Distance(5, Metrics.KILOMETERS); //RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands .GeoRadiusCommandArgs .newGeoRadiusArgs() .includeDistance() 返回值包含距离 .includeCoordinates() 返回值包含坐标 .sortAscending() 排序升序 .limit(5); 取多少个数据 GeoResults<RedisGeoCommands.GeoLocation<String>> results = redisTemplate.opsForGeo().geoRadiusByMember(k, mk, distance, args); return results; } /** * 返回的是geohash值,查找一个位置的时间复杂度为O(log(N)) * redis命令:geohash cityGeo 北京 * * @param k * @param mks * @return */ public List geoHash(Object k, Object... mks) { List<String> results = redisTemplate.opsForGeo().geoHash(k, mks); return results; } } //==================================================== // 搜索范围 @Value("${3}") private Double lbsDistance; private String LbsKey = "key"; Point center = new Point(lon, lat); Distance radius = new Distance(lbsDistance, Metrics.KILOMETERS); Circle within = new Circle(center, radius); // order by 距离 limit 20 ,同时返回距离中心点的距离 GeoRadiusCommandArgs args = GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().limit(limit).sortAscending(); GeoResults<GeoLocation<String>> result = ops.radius(LbsKey, within, args);
使用示例
@RestController @Api(value = "nearbyMember", tags = "nearbyMember附近的人") @RequestMapping("/nearbyMember") public class NearbyMemberController { @Autowired private RedisTemplate redisTemplate; @Autowired private PersonInformationService informationService; @ApiOperation(value = "添加用户定位", notes = "添加用户定位") @SysLog("添加用户定位") @PostMapping("/addPoint") public R addPoint(@RequestBody NearbyVO nearbyVO) { String userId = nearbyVO.getUserId(); String key = nearbyVO.getKey(); double x = nearbyVO.getX(); double y = nearbyVO.getY(); Point point = new Point(x, y); JSONObject peopleJson = informationService.getGeoInfo(userId); Long add = redisTemplate.opsForGeo().add(key, point, peopleJson); return R.ok(add); } @ApiOperation(value = "查找附近的人", notes = "查找附近的人") @SysLog("查找附近的人") @PostMapping("/getPeople") public R getPeople(@RequestBody NearbyVO nearbyVO) { double radius = nearbyVO.getRadius(); String key = nearbyVO.getKey(); //设定查找范围的中心 Point center = new Point(nearbyVO.getX(), nearbyVO.getY()); //设定查找范围距离(半径) Distance distance = new Distance(radius, Metrics.KILOMETERS); //得到一个圆形面积的范围 Circle circle = new Circle(center, distance); //设定返回的数据类型 RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands .GeoRadiusCommandArgs .newGeoRadiusArgs() .includeDistance() .includeCoordinates() .sortAscending(); GeoResults geoResults = redisTemplate.opsForGeo().radius(key, circle, args); return R.ok(geoResults); } }
@ApiOperation(value = "删除地图用户位置信息", notes = "删除地图用户位置信息") @SysLog("以userId为对象测试") @DeleteMapping("/delGEO") public R delGEO(@RequestBody NearbyVO nearbyVO) { String userId = nearbyVO.getUserId(); String key = nearbyVO.getKey(); JSONObject peopleJson = informationService.getGeoInfo(userId); Long remove = redisTemplate.opsForGeo().remove(key, peopleJson); return R.ok(remove); }
VO数据模型
public class NearbyVO { private double x; private double y; private String key; private String userId; private double radius; }
发布订阅
// 发布一个 话题 redisTemplate.convertAndSend("REDIS_PUBLISH_TOPIC_NAME", "重新加载支付参数");
/** * redis 监听配置,监听 REDIS_PUBLISH_TOPIC_NAME,并处理逻辑 * * @param redisConnectionFactory redis 配置 * @return */ @Bean public RedisMessageListenerContainer redisContainer(RedisConnectionFactory redisConnectionFactory) { RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.setConnectionFactory(redisConnectionFactory); container.addMessageListener((message, bytes) -> { log.warn("接收到Redis 事件 重新加载支付参数事件"); // 执行代码逻辑 initPayChannel(); // Name 和发布的一致 }, new ChannelTopic("REDIS_PUBLISH_TOPIC_NAME")); return container; }
本文来自博客园,作者:Vermeer,转载请注明原文链接:https://www.cnblogs.com/chxlay/p/15092452.html