前提:使用redis保存经纬度坐标,判断redis中是否存在该坐标时,发现一直判断存在,导致无法存储坐标。
问题代码
//存储redis:查询redis中是否存在该坐标
//member存储经纬度,格式:[经度,纬度]
String member = "["+geoLocation.getLongitude()+","+geoLocation.getLatitude()+"]";
//geoKey可以看作整个经纬度集合的key
List<Point> points = redisGeoUtils.geoGet(geoKey,member);
if (points.size()<=0){
//不存在,添加至redis
Point point = new Point(geoLocation.getLongitude(),geoLocation.getLatitude());
redisGeoUtils.geoAdd(geoKey,point,member);
}
经过debug检查,points.size()一直等于1,导致不能进入添加redis判断。但debug中也发现,points虽然存在元素,但显示的是All elements are null,意思是当前集合所有元素都为null。
原因
List集合允许存入空值,导致出现判断失误。
解决
在原代码中多加一层判断,判断集合中的元素不为null即可。
本处代码redisGeoUtils.geoGet(geoKey,member),是通过总经纬度key与单个经纬度member值获取redis中存储经纬度元素,获取值最多一个,所以只用判断第一个元素不为null即可。
if (points.size()<=0||null==points.get[0]){
...
}
ps:member可以传多个,多个的话就会可能返回多个值,然后再遍历points一个一个判断即可。
public List<Point> geoGet(String key, String... members) {
return redisTemplate.opsForGeo().position(key, members);
}
为何redis不存在,points的size还是返回1,而不是0?
进入geoGet(String key, String… members)方法内部
public List<Point> geoGet(String key, String... members) {
return redisTemplate.opsForGeo().position(key, members);
}
进入position(key, members)
@Override
public List<Point> position(K key, M... members) {
byte[] rawKey = rawKey(key);
byte[][] rawMembers = rawValues(members);
return execute(connection -> connection.geoPos(rawKey, rawMembers), true);
}
进入connection.geoPos(rawKey, rawMembers),选择lettuceGeoCommands.java的实现
@Override
public List<Point> geoPos(byte[] key, byte[]... members) {
Assert.notNull(key, "Key must not be null!");
Assert.notNull(members, "Members must not be null!");
Assert.noNullElements(members, "Members must not contain null!");
ListConverter<GeoCoordinates, Point> converter = LettuceConverters.geoCoordinatesToPointConverter();
try {
if (isPipelined()) {
pipeline(connection.newLettuceResult(getAsyncConnection().geopos(key, members), converter));
return null;
}
if (isQueueing()) {
transaction(connection.newLettuceResult(getAsyncConnection().geopos(key, members), converter));
return null;
}
return converter.convert(getConnection().geopos(key, members));
} catch (Exception ex) {
throw convertLettuceAccessException(ex);
}
}
进入converter.convert(getConnection().geopos(key, members))
@Override
public List<T> convert(List<S> source) {
List<T> results = new ArrayList<>(source.size());
for (S result : source) {
results.add(itemConverter.convert(result));
}
return results;
}
debug发现convert方法中,source .size=1于是返回的results.size=1,导致最终points.size=1。
返回上一步,进入getConnection().geopos(key, members),这里是导致source .size=1的原因
/**
* Get geo coordinates for the {@code members}.
*
* @param key the key of the geo set
* @param members the members
*
* @return a list of {@link GeoCoordinates}s representing the x,y position of each element specified in the arguments. For
* missing elements {@literal null} is returned.
*/
List<GeoCoordinates> geopos(K key, V... members);
该方法没有进一步的实现类,但与直接在redis客户端中使用的方法一样,应该是操作客户端的方法
GEOPOS key member [member …]
根据方法注释解释到:对于缺失元素,返回null。
而在redis官网命令中的解释:
个人理解:List geopos(K key, V… members)方法在查询到null值后,将null值直接添加至List中,以至于返回size=1。