一.什么是Redis
Redis是一个非关系型数据库,具有很高的存取性能,一般用作缓存数据库,减少正常存储数据库的压力。
Redis可以存储键与5种不同数据结构类型之间的映射,这5种数据结构类型分别为String(字符串)、List(列表)、Set(集合)、Hash(散列)和 Zset(有序集合)。
二.RedisTemplate及其相关方法
Spring封装了RedisTemplate对象来进行对Redis的各种操作,它支持所有的Redis原生的api。RedisTemplate位于spring-data-redis包下。RedisTemplate提供了redis各种操作、异常处理及序列化,支持发布订阅,并对spring 3.1 cache进行了实现。
注意 RedisTemplate是一个key和value都是泛型的模板类,一般情况下key为String类型,如:RedisTemplate<String,Object>。
此外,如果没特殊情况,切勿定义成RedisTemplate<Object, Object>,否则根据里氏替换原则,使用的时候会造成类型错误 。
// 在maven中添加依赖(下面只是主要的部分依赖)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
spring-data-redis针对jedis提供了如下功能:
1.连接池自动管理,提供了一个高度封装的“RedisTemplate”类
2.针对jedis客户端中大量api进行了归类封装,将同一类型操作封装为operation接口
ValueOperations:简单K-V操作
SetOperations:set类型数据操作
ZSetOperations:zset类型数据操作
HashOperations:针对map类型的数据操作
ListOperations:针对list类型的数据操作
RedisTemplate中定义了对5种数据结构操作
redisTemplate.opsForValue();//操作字符串
redisTemplate.opsForHash();//操作hash
redisTemplate.opsForList();//操作list
redisTemplate.opsForSet();//操作set
redisTemplate.opsForZSet();//操作有序set
其实这里的ops相当于options, 是RedisTemplate对各种不同的Redis数据类型进行操作。其实还有另外的方法:
redistempalate.boundValueOps
redistempalate.boundSetOps
redistempalate.boundListOps
redistempalate.boundHashOps
redistempalate.boundZSetOps
opsForXXX和boundXXXOps的区别?
前者获取一个operator,但是没有指定操作的对象(key),可以在一个连接(事务)内操作多个key以及对应的value;后者获取了一个指定操作对象(key)的operator,在一个连接(事务)内只能操作这个key对应的value。
关于计数的API(increment)有一个bug,需要各位使用中注意,通过increment计数以后,通过get方式获取计数值的时候可能会抛出EOF异常(和本地的jdk以及redis的编译版本有关),可以考虑使用boundValueOps(key).get(0,-1)获取计数值。
三.RedisTemplate操作Redis数据库的具体例子
1、Value(值)类型
public class RedisTest {
@Autowired
private RedisTemplate redisTemplate;
@Test
public void testValue(){
redisTemplate.boundValueOps("testValue1").set("value1",60,TimeUnit.SECONDS); //设置过期时间为60秒,60秒后自动删除
redisTemplate.boundValueOps("testValue2").set("value2");
// redisTemplate.boundValueOps("testValue2").set("22222",3); //把testValue2的前三位置换为22222
}
@Test
public void getValue(){
Object o1 = redisTemplate.boundValueOps("testValue1").get();
Object o2 = redisTemplate.boundValueOps("testValue2").get();
System.out.println(o1 + " " + o2);
}
}
2、list类型
@Test
public void listTest(){
redisTemplate.boundListOps("list").leftPush("aaa");
redisTemplate.boundListOps("list").leftPush("aaa");
redisTemplate.boundListOps("list").leftPush("aaa");
redisTemplate.boundListOps("list").leftPush("bbb");
redisTemplate.boundListOps("list").rightPush("ccc");
redisTemplate.boundListOps("list").rightPush("ddd");
}
@Test
public void getList(){
List list = redisTemplate.boundListOps("list").range(0,10); //查询,range(0,10)会查询出0-10的元素
System.out.println(list);
System.out.println(redisTemplate.boundValueOps("list").getKey()); //获取key值
redisTemplate.boundListOps("list").remove(2,"aaa"); //删除两个个aaa
List list1 = redisTemplate.boundListOps("list").range(0,10); //查询,range(0,10)会查询出0-10的元素
System.out.println(list1);
redisTemplate.boundListOps("list").expire(60,TimeUnit.SECONDS); //设置60秒后过期
System.out.println(redisTemplate.boundListOps("list").index(1)); //根据索引获取值
System.out.println(redisTemplate.boundListOps("list").leftPop()); //bbb,打印左边起第一个元素值
}
/**
* 右压栈:后添加的对象排在后边,相当于队列,相当于先进先出
*/
@Test
public void testSetValue1(){
redisTemplate.boundListOps("namelist1").rightPush("刘备");
redisTemplate.boundListOps("namelist1").rightPush("关羽");
redisTemplate.boundListOps("namelist1").rightPush("张飞");
}
/**
* 显示右压栈集合,range 表示查询的索引,从第几个查到第几个,如果想查询所有的数的话只能将第二个数写得大一点。
*/
@Test
public void testGetValue1(){
List list = redisTemplate.boundListOps("namelist1").range(0, 10);
System.out.println(list);
}
//运行结果:[刘备, 关羽, 张飞],元素可以重复
/**
* 左压栈:后添加的对象排在前边,相当于栈,先进后出
*/
@Test
public void testSetValue2(){
redisTemplate.boundListOps("namelist2").leftPush("刘备");
redisTemplate.boundListOps("namelist2").leftPush("关羽");
redisTemplate.boundListOps("namelist2").leftPush("张飞");
}
/**
* 显示左压栈集合
*/
@Test
public void testGetValue2(){
List list = redisTemplate.boundListOps("namelist2").range(0, 10);
System.out.println(list);
}
//运行结果:[张飞, 关羽, 刘备]
3、set类型:无序、不可重复
@Test
public void setTest(){
redisTemplate.boundSetOps("set").add("aaa");
redisTemplate.boundSetOps("set").add("bbb");
redisTemplate.boundSetOps("set").add("ccc");
redisTemplate.boundSetOps("set").add("ddd");
}
@Test
public void getTest(){
Set set = redisTemplate.boundSetOps("set").members();
System.out.println(set); //[bbb, ccc, aaa, ddd]
redisTemplate.boundSetOps("set").remove("aaa");//删除aaa这个元素
redisTemplate.delete("set"); //删除整个集合
}
4、ZSet
@Test
public void zsetTest(){
redisTemplate.boundZSetOps("zset").add("aaa",1);
redisTemplate.boundZSetOps("zset").add("bbb",2);
redisTemplate.boundZSetOps("zset").add("ccc",3);
redisTemplate.boundZSetOps("zset").add("ddd",4);
}
@Test
public void getTest(){
Set zset = redisTemplate.boundZSetOps("zset").range(0,10);
System.out.println(zset); //[aaa, bbb, ccc, ddd]
redisTemplate.boundZSetOps("zset").removeRange(0,2); //删除0-2的元素,共三个
Set zset1 = redisTemplate.boundZSetOps("zset").range(0,10);
System.out.println(zset1); //[ddd]
}
5、hash类型
@Test
public void hashTest(){
redisTemplate.boundHashOps("hash").put("1", "a");
redisTemplate.boundHashOps("hash").put("2", "b");
redisTemplate.boundHashOps("hash").put("3", "c");
redisTemplate.boundHashOps("hash").put("4", "d");
}
@Test
public void getHashTest(){
List hash = redisTemplate.boundHashOps("hash").values();
System.out.println(hash);
Set set = redisTemplate.boundHashOps("hash").keys();
System.out.println(set);
Object o = redisTemplate.boundHashOps("hash").get("1");
System.out.println(o);
/**
* [a, b, c, d]
* [1, 2, 3, 4]
* a
*/
}
注意:上面五种类型都可以使用redisTemeplate的expire(long l,TimeUnit timeUnit)函数设置过期时间。
四.RedisTemplate和StringRedisTemplate的区别
1、StringRedisTemplate继承RedisTemplate;
2、两者的数据是不共通的;也就是说StringRedisTemplate只能管理StringRedisTemplate里面的数据,RedisTemplate只能管理RedisTemplate中的数据
3、序列化方式不同
StringRedisTemplate默认采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的;
RedisTemplate默认采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。
RedisTemplate使用的序列类在在操作数据的时候,比如说存入数据会将数据先序列化成字节数组然后在存入Redis数据库,这个时候打开Redis查看的时候,你会看到你的数据不是以可读的形式展现的,而是以字节数组显示。
当然从Redis获取数据的时候也会默认将数据当做字节数组转化,这样就会导致一个问题,当需要获取的数据不是以字节数组存在redis当中而是正常的可读的字符串的时候。
RedisTemplate就无法获取导数据,这个时候获取到的值就是NULL。这个时候StringRedisTempate就派上了用场。
当Redis当中的数据值是以可读的形式显示出来的时候,只能使用StringRedisTemplate才能获取到里面的数据。
所以当你使用RedisTemplate获取不到数据的时候请检查一下是不是Redis里面的数据是可读形式而非字节数组。
参考网址:
https://blog.csdn.net/qq_43060759/article/details/90707626
https://www.cnblogs.com/EasonJim/p/7803067.html
https://blog.csdn.net/striveb/article/details/83745680