前面节分别介绍了 ValueOperations、SetOperations、ZSetOperations、ListOperations、HyperLogLogOperations 等操作接口。这些操作接口都拥有一个共性,在进行某个具体操作时,都需要传递 key,例如:使用这些操作接口添加值时,如下:
SetOperations -> add(K key, V... values) ZSetOperations -> add(K key, Set<ZSetOperations.TypedTuple<V>> tuples) ValueOperations -> set(K key, V value) ListOperations -> leftPush(K key, V value) ListOperations -> rightPush(K key, V value) ...
其实我们整个操作过程中,可能并没有换 key,反复就对一个 key 进行设置、取值、删除操作。于是,Spring Data Redis 提供了一套 Bound 类型的便捷操作接口,这些接口提前将某个 key 和操作接口进行绑定,在使用 Bound 接口进行操作时,就不需要传递麻烦的 key 了。
在 Spring Data Redis 的 RedisTemplate 类中,通过如下方法获取不同类型的 Bound 操作接口,如下:
BoundGeoOperations<K,V> boundGeoOps(K key) 返回绑定到给定键的地理空间特定操作接口。
<HK,HV> BoundHashOperations<K,HK,HV> boundHashOps(K key) 返回对绑定到给定键的哈希值执行的操作。
BoundListOperations<K,V> boundListOps(K key) 返回对绑定到给定键的列表值执行的操作。
BoundSetOperations<K,V> boundSetOps(K key) 返回对绑定到给定键的集合值执行的操作。
BoundValueOperations<K,V> boundValueOps(K key) 返回对绑定到给定键的简单值(或 Redis 术语中的字符串)执行的操作。
BoundZSetOperations<K,V> boundZSetOps(K key) 返回对绑定到给定键的 zset 值(也称为排序集)执行的操作。

下面通过一些列的具体示例演示怎样快速利用 Bound 类型操作接口操作 GEO、Hash、List、Set、Value、ZSet 数据类型。
BoundValueOperations<String,String> ops = redisTemplate.boundValueOps("bound-value");
// 新增
ops.set("value1");
System.out.println(ops.get());
// 修改
ops.set("value2");
System.out.println(ops.get());
// 追加值
ops.append(" append");
System.out.println(ops.get());
// 设置过期时间
ops.set("value3", 5, TimeUnit.SECONDS);
System.out.println(ops.get());
try {
// 休眠6秒,再次获取值
Thread.sleep(6000);
System.out.println(ops.get());
} catch (Exception e) {}运行结果:
value1 value2 value2 append value3 null
BoundHashOperations<String,String,String> ops =
redisTemplate.boundHashOps("bound-hash");
// 新增
ops.put("k1", "v1");
ops.put("k2", "100");
ops.put("k3", "v3");
System.out.println(JSONObject.toJSONString(ops.entries()));
// 增加
ops.increment("k2", 10);
System.out.println("k2=" + ops.get("k2"));
// 删除
ops.delete("k1");
System.out.println(JSONObject.toJSONString(ops.entries()));
// 迭代
ScanOptions scanOptions = new ScanOptions.ScanOptionsBuilder()
.count(5).match("*").build();
Cursor<Map.Entry<String,String>> cursor = ops.scan(scanOptions);
while(cursor.hasNext()) {
Map.Entry<String,String> entry = cursor.next();
System.out.println(entry.getKey() + "=" + entry.getValue());
}运行结果:
{"k1":"v1","k2":"100","k3":"v3"}
k2=110
{"k2":"110","k3":"v3"}
k2=110
k3=v3BoundListOperations<String,String> ops = redisTemplate.boundListOps("bound-list");
// 新增
ops.leftPush("value1");
ops.rightPush("value2");
ops.rightPush("value1", "value3");
System.out.println(JSONObject.toJSONString(ops.range(0, -1)));
// 修改
ops.set(0, "new-" + ops.index(0));
System.out.println(JSONObject.toJSONString(ops.range(0, -1)));
// 删除
ops.remove(1, "value2");
System.out.println(JSONObject.toJSONString(ops.range(0, -1)));运行结果:
["value1","value3","value2"] ["new-value1","value3","value2"] ["new-value1","value3"]
BoundSetOperations<String,String> ops = redisTemplate.boundSetOps("bound-set");
// 新增
ops.add("value1", "value2", "value3", "kval1", "kval2", "kval3", "hval1", "hval2");
System.out.println(JSONObject.toJSONString(ops.members()));
// 删除
ops.remove("value2");
System.out.println(JSONObject.toJSONString(ops.members()));
// 迭代
ScanOptions scanOptions = new ScanOptions.ScanOptionsBuilder()
.count(2).match("kval*").build();
Cursor<String> cursor = ops.scan(scanOptions);
while(cursor.hasNext()) {
System.out.println(cursor.next());
}运行结果:
["value3","hval1","kval3","kval1","kval2","hval2","value1","value2"] ["value3","hval1","kval3","kval1","kval2","hval2","value1"] kval3 kval2 kval1
BoundZSetOperations<String,String> ops = redisTemplate.boundZSetOps("bound-zset");
// 新增
ops.add("value1", 1);
ops.add("value2", 2);
ops.add("value3", 1);
ops.add("value4", 3);
System.out.println(JSONObject.toJSONString(ops.range(0, -1)));
// 删除
ops.remove("value3");
System.out.println(JSONObject.toJSONString(ops.range(0, -1)));
// 迭代
ScanOptions scanOptions = new ScanOptions.ScanOptionsBuilder().build();
Cursor<ZSetOperations.TypedTuple<String>> cursor = ops.scan(scanOptions);
while(cursor.hasNext()) {
ZSetOperations.TypedTuple<String> item = cursor.next();
System.out.println(item.getValue() + " --- " + item.getScore());
}运行结果:
["value1","value3","value2","value4"] ["value1","value2","value4"] value1 --- 1.0 value2 --- 2.0 value4 --- 3.0
BoundGeoOperations<String,String> ops = redisTemplate.boundGeoOps("bound-geo");
// 成都天府广场坐标
Point point = new Point(104.072206,30.663486);
ops.add(point, "chengdu");
// 北京天安门广场坐标
point = new Point(116.403039,39.91513);
ops.add(point, "beijing");
// 计算成都到北京的距离
Distance distance = ops.distance("chengdu", "beijing");
System.out.println("相距:" + distance.getValue() + distance.getUnit());
// Metrics.KILOMETERS 公里
// Metrics.MILES 英里
// Metrics.NEUTRAL 米
distance = ops.distance("chengdu", "beijing", Metrics.MILES);
System.out.println("相距:" + distance.getValue() + distance.getUnit());运行结果:
相距:1517797.1972m 相距:943.1178mi