对Redis数据类型的操作
对数据类型的操作才是 Redis 需要关心的部分,下面正式介绍 Redis 数据类型的操作部分。主要有三个部分:StringRedisTemplate 的使用、模板 template 以及其他数据类型的操作。
StringRedisTemplate的使用
在上文,添加与获取都需要使用 byte 数组进行操作,这样显得比较烦琐。其实,Spring Boot 有可以使用模板,可简化代码书写。
package com.springBoot.redis.config;
@Configuration
public class RedisConfig {
@Bean
public JedisConnectionFactory getFactory(){
RedisStandaloneConfiguration redisStandaloneConfiguration=new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setDatabase(0);
redisStandaloneConfiguration.setHostName("127.0.0.1");
redisStandaloneConfiguration.setPort(6379);redisStandaloneConfiguration.setPassword(RedisPassword.of("123456"));
JedisConnectionFactory factory = new JedisConnectionFactory (redisStandaloneConfiguration);
return factory;
}
@Bean
public StringRedisTemplate redisTemplate(JedisConnectionFactory
jedisConnectionFactory) {
return new StringRedisTemplate(jedisConnectionFactory);
}
}
RedisConfig 类在8.1节中有不使用连接池返回工厂类和使用连接池返回工厂类两种方式。在这个实例中,我们只使用其中一种进行演示,效果相同。我们讲解了工厂类,那么如何使用?
在 Spring 中有模板,在建立模板的时候则需要传入工厂类。因此,我们把刚生成的工厂类带入模板,并返回。在 Spring Boot 中有多个模板,先使用 StringRedisTemplate,至于其他的模板将会在后面进行介绍。然后,我们写测试类程序,进行测试,代码如下所示。
package com.springBoot.redis;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
public class RedisApplicationTest {
@Autowired
StringRedisTemplate stringRedisTemplate;
@Test
public void testRedis(){
stringRedisTemplate.opsForValue().set("myKey2","myValue2");
String myVal=stringRedisTemplate.opsForValue().get("myKey2");
System.out.println("myVal: "+myVal);
}
}
上面程序中,将 StringRedisTemplate 模板注入,然后使用模板的方法。首先,使用 SET 方法把数据存放进 Redis。为了验证方法正确性,可以从 Redis 的命令行上观察,不过这里还是使用取出的方式进行验证,执行结果如图8.4所示。

Spring Data Redis 提供了两个模板,一个为 RedisTemplate,另一个为 StringRedisTemplate。RedisTemplate 使用的序列化类是 JdkSerializationRedisSerializer,StringRedisTemplate 使用的序列化类是 StringRedisSerializer。
首先,来看 StringRedisTemplate 的类关系,如图8.5所示。

通过图8.5可以看到 StringRedisTemplate 继承了 RedisTemplate。当要存入、读取 Redis 数据库中的数据是字符串或者数据库中的数据是字符串,那么进行操作时使用 StringRedisTemplate 模板非常方便,从上面的实例中也可以发现的确方便很多。
只有对数据的复杂类型进行操作,才会使用 RedisTemplate,所以这里先来看 StringRedisTemplate 常用的操作,代码如下所示。
stringRedisTemplate.opsForValue().set("test", "100",60*10,TimeUnit. SECONDS);//向redis里存入数据和设置缓存时间
stringRedisTemplate.boundValueOps("key").increment(-1); //val做-1操作
stringRedisTemplate.opsForValue().get("key") //根据key获取缓存中的val
stringRedisTemplate.boundValueOps("key").increment(1); //val +1
stringRedisTemplate.getExpire("key") //根据key获取超时时间
stringRedisTemplate.getExpire("key",TimeUnit.SECONDS) //获取超时时间并换算成指定单位
stringRedisTemplate.delete("key "); //根据key删除缓存
stringRedisTemplate.hasKey("aaaaa"); //检查key是否存在,返回boolean值
stringRedisTemplate.opsForSet().add("red_123","2","3"); //向指定key中存放Set集合
stringRedisTemplate.expire("red_123",1000 , TimeUnit.MILLISECONDS);//设置超时时间
stringRedisTemplate.opsForSet().members("rrr"); //根据key获取Set集合
模板template
Redis 支持五种数据类型,分别是字符串(String)、列表(List)、散列(Hash)、集合(Set)、有序集合(Zset)。对于字符串,我们建议使用 StringRedisTemplate 模板进行操作,那么对其他几种数据类型如何操作?本节将会介绍。
Redis的数据类型
首先,把这五种数据类型做一个归纳总结,让不熟悉 Redis 的读者有一个了解,方便后续的学习。
-
String:在 Redis 中存取的是字符串,也可以是整数与浮点数,需要注意的是学习过 Java 编程的读者,不要把整数与浮点数当成字符串。其实 StringRedisTemplate 的用法有 “val+1” 的操作。
-
List:Redis 中的链表。可以在链表的开头与结尾,或者说链表左侧与链表右侧进行添加与删除数据的操作,同样可以对其中的指定位置进行操作,即在每一个节点上都是一个字符串。
-
Hash:包含键值的无序散列表。
-
Set:集合的意思。与 Java 中的语法不同,在集合中是字符串,其特点是无序,而且唯一,即不允许重复。
-
Zset:是字符串成员与数值的有序映射,然后根据数值的大小进行排序。
RedisTemplate的使用
在8.2.1小节中,讲到了 StringRedisTemplate 与 RedisTemplate 的关系,也说明了对于字符串的操作,使用 StringRedisTemplate 即可,但操作其他的数据类型,就需要 RedisTemplate 的配合。
很多时候,我们不仅要知道操作字符串需要与该模板打交道,也要知道该模板是 Redis 的核心,是 Redis 交互的高级抽象,有着更丰富的功能。
在最开始时,我们使用 RedisConnect 进行操作,这种方式存取都需要 byte 数组,而 RedisTemplate 则不需要这么费事,因为在模板中就可以处理序列化与连接,使得开发人员只需要关注业务开发,而不需要太关注 Redis 的细节。
首先,Spring 对数据类型的操作都提供了接口,在具体操作前,我们先看有哪些接口,这也被称为 Key 类型操作,接口清单如下所示。
ValueOperations //字符串类型的操作
ListOperations //列表类型的操作
SetOperations //集合类型的操作
ZsetOperations //有序集合类型的操作
HashOperations //散列类型的操作
GeoOperations //地理位置的操作
HyperLogLogOperations //基数类型的操作
上面定义了几种接口,这些定义的接口如何使用?RedisTemplate 定义了对数据类型的操作,我们可以通过如下的几种方式获取接口,接口清单如下。
redisTemplate.opsForValue(); //操作字符串
redisTemplate.opsForHash(); //操作Hash
redisTemplate.opsForList(); //操作List
redisTemplate.opsForSet(); //操作Set
redisTemplate.opsForZSet(); //操作有序Set
redisTemplate.opsForGeo(); //操作地理位置
redisTemplate.opsForHyperLogLog(); //操作基数
然后,除了在前面提过的 Key 类型操作,其实还有一种 Key 绑定操作。例如有这样的场景,如果想对某一个键值对做一系列操作,这时 Spring Data Redis 也存在相应接口,接口的清单如下所示。
BoundValueOperations //绑定一个字符串键操作
BoundListOperations //列表键绑定
BoundSetOperations //集合键绑定
BoundZSetOperations //有序集合键绑定
BoundHashOperations //散列键绑定
BoundGeoOperations //地理位置绑定
同理,定义了接口,就可以使用 RedisTemplate 获取接口,接口清单如下所示。
redisTemplate.boundValueOps("string");
redisTemplate.boundSetOps("set");
redisTemplate. boundZSetOps ("zset");
redisTemplate.boundHashOps("hash");
redisTemplate.boundListOps("list");
redisTemplate.boundGeoOps("geo");
数据类型的操作
在 Redis 中存在多种数据类型,现在对 String、List、Set、Hash 数据类型进行操作。下面是测试类程序,以及运行的结果。
String操作
首先,进行 String 数据类型的操作,代码继续写在测试类 RedisApplicationTest中。
package com.springBoot.redis;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
public class RedisApplicationTest {
@Autowired
RedisTemplate redisTemplate;
@Test
public void testString(){
ValueOperations<String,String> valueOperations=redisTemplate. opsForValue();
//不设置超时时间
valueOperations.set("testString1","testStringValue1");
//设置超时时间,设置的时间单位为秒,切位30秒
valueOperations.set("testString2","testStringValue2",30, TimeUnit.SECONDS);
//判断key是否存在,不存在则存取
valueOperations.setIfAbsent("testString3","testStringValue3");
//获取数据类型
String val1=valueOperations.get("testString1");
String val2=valueOperations.get("testString2");
String val3=valueOperations.get("testString3");
System.out.println("val1: "+val1);
System.out.println("val2: "+val2);
System.out.println("val3: "+val3);
}
}
运行测试类程序,观察执行结果如图8.6所示。

List操作
在这里,放入一个对象。首先在 redis 的包下新建 entity 包,在 entity 包下新建 Employ 类,代码如下所示。
package com.springBoot.redis.entity;
public class Employ implements Serializable {
private static final long serialVersionUID = 366444554774130L;
private String id;
private String name;
//GET和SET方法
@Override
public String toString() {
return "Employ{" +
"id='" + id + '\" +
", name='" + name + '\" +
'}';
}
}
在这段代码中,需要注意的是要让这个类可以序列化,因为我们在测试时没有特别指定序列器,则会使用 JDK 序列化,所以需要实现 Serializable 接口。然后,写测试类程序,测试代码如下所示。
package com.springBoot.redis;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
public class RedisApplicationTest {
@Autowired
RedisTemplate redisTemplate;
@Test
public void testList(){
ListOperations<String,Object> listOperations=redisTemplate. opsForList();
for (int i=0;i<3;i++){
Employ employ=new Employ();
employ.setId("\""+i+"\"");
employ.setName("name"+i);
listOperations.rightPush("list1",employ);
listOperations.rightPush("list2",employ);
}
Employ employ=(Employ)listOperations.rightPop("list1");
System.out.println(employ.toString());
}
}
在这段代码中,通过 RedisTemplate 获取操作 List 的接口,然后模拟数据在链表的右侧插入数据,最后通过在右侧弹出的方式验证程序的执行结果,如图8.7所示。

分析一下结果,我们在右侧执行弹出是后放入的,所以 id 为 2。
Set操作
继续在测试类程序中添加测试方法,代码如下所示。
@Test
public void testSet(){
SetOperations<String,Object> setOperations=redisTemplate. opsForSet();
Employ employ=new Employ();
employ.setId("1");
employ.setName("a");
setOperations.add("set",employ);
Employ employ1=(Employ)setOperations.pop("set");
System.out.println(employ1.toString());
}
执行结果如图8.8所示。

Hash操作
继续在测试类中程序添加测试方法,代码如下所示。
@Test
public void testHash() {
HashOperations<String,Object,Object> hashOperations=redisTemplate. opsForHash();
Map<String,String> newMap=new HashMap<>();
newMap.put("testMap1","test1");
newMap.put("testMap2","test2");
hashOperations.putAll("hash",newMap);
System.out.println(hashOperations.entries("hash"));
}
执行结果如图8.9所示。
