[关闭]
@MRsunhuimin 2019-10-16T14:10:30.000000Z 字数 13002 阅读 953

SpringBoot Redis 基础使用(10.16)

SpringBoot

作者:孙慧敏

1. redis介绍

redis是一个key-value。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets)与范围查询, bitmaps, hyperloglogs和 地理空间(geospatial)索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions)和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)

1.1 redis特点

  • Redis将其数据库完全保存在内存中,仅使用磁盘进行持久化。
  • 与其它键值数据存储相比,Redis有一组相对丰富的数据类型
  • Redis可以将数据复制到任意数量的从机中。

1.2 redis优点

  • 异常快
    Redis非常快,每秒可执行大约110000次的设置(SET)操作,每秒大约可执行81000次的读取/获取(GET)操作。
  • 支持丰富的数据类型
    Redis支持开发人员常用的大多数数据类型,例如列表,集合,排序集和散列等等。这使得Redis很容易被用来解决各种问题,因为我们知道哪些问题可以更好使用地哪些数据类型来处理解决。
  • 操作具有原子性
    所有Redis操作都是原子操作,这确保如果两个客户端并发访问,Redis服务器能接收更新的值。
  • 多实用工具
    Redis是一个多实用工具,可用于多种用例,如:缓存,消息队列(Redis本地支持发布/订阅),应用程序中的任何短期数据,例如,web应用程序中的会话,网页命中计数等。

1.3 redis安装(Windows系统)

下载包
https://github.com/MicrosoftArchive/redis/releases
解压到D盘目录下

1.4 启动redis

在这个目录下cmd,然后直接redis-server.exe redis.windows.conf,即可启动redis
或新建记事本文件startup.bat,输入redis-server.exe redis.windows.conf

1.5 修改密码

解压目录下找到redis.windows.conf
大概在387行左右requirepass 下添加requirepass 密码,保存,重新运行即可

1.6 下载安装RedisDesktopManager,并连接redis(关闭防火墙并设置允许远程连接此电脑)

2. SpringBoot中Redis相关配置

2.1 引入相关JAR(pom.xml文件中)

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-redis</artifactId>
  4. <version>1.3.8.RELEASE</version>
  5. </dependency>

2.2 配置写到.propertier文件中

  1. # Redis数据库索引(默认为0)
  2. spring.redis.database=0
  3. # Redis服务器地址
  4. spring.redis.host=127.0.0.1
  5. # Redis服务器连接端口
  6. spring.redis.port=6379
  7. # Redis服务器连接密码(默认为空)
  8. spring.redis.password=123456
  9. # 连接池最大连接数(使用负值表示没有限制)
  10. spring.redis.pool.max-active=8
  11. # 连接池最大阻塞等待时间(使用负值表示没有限制)
  12. spring.redis.pool.max-wait=-1
  13. # 连接池中的最大空闲连接
  14. spring.redis.pool.max-idle=8
  15. # 连接池中的最小空闲连接
  16. spring.redis.pool.min-idle=0
  17. # 连接超时时间(毫秒)
  18. spring.redis.timeout=0

2.3 上述两个步骤完成后,SpringBoot自动在Spring容器中配置一个redisTemplate的Bean,所以可以直接使用redisTemplate

2.4 使用Spring封装的RedisTemplate操作redis

常用方法

  • redisTemplate.opsForValue();//操作字符串
  • redisTemplate.opsForHash();//操作hash
  • redisTemplate.opsForList();//操作list
  • redisTemplate.opsForSet();//操作set
  • redisTemplate.opsForZSet();//操作有序set

2.4+ IndexTestController

  1. package com.hz.controller;
  2. import com.hz.pojo.SfUser;
  3. import org.springframework.data.redis.core.RedisTemplate;
  4. import org.springframework.data.redis.serializer.RedisSerializer;
  5. import org.springframework.data.redis.serializer.StringRedisSerializer;
  6. import org.springframework.web.bind.annotation.RequestMapping;
  7. import org.springframework.web.bind.annotation.RestController;
  8. import javax.annotation.Resource;
  9. import java.util.ArrayList;
  10. import java.util.List;
  11. import java.util.concurrent.TimeUnit;
  12. @RestController
  13. public class IndexTestController {
  14. @Resource
  15. private RedisTemplate redisTemplate;
  16. @RequestMapping("getTestRedis")
  17. public String getTestRedis(){
  18. // 存储字符串,并设置失效时间
  19. // redisTemplate.opsForValue().set("name","张三",10,TimeUnit.SECONDS);
  20. // Object obj = redisTemplate.opsForValue().get("name");
  21. // System.out.println(obj);
  22. // 支持整型与浮点型(increment)
  23. // increment插入的内容不能通过get获得
  24. // Object age = redisTemplate.opsForValue().increment("age",15);
  25. // System.out.println(age);
  26. double age = redisTemplate.opsForValue().increment("age",+1);
  27. System.out.println(age);
  28. // set 设定该Key持有指定的字符串Value,如果该Key已经存在,则覆盖其原有值
  29. // append 如果该Key已经存在,APPEND命令将参数Value的数据追加到已存在Value的末尾。
  30. // 如果该Key不存在,APPEND命令将会创建一个新的Key/Value,它被创建并设置为空字符串,此种情况下类似于set。
  31. // redisTemplate.opsForValue().set("name","张三");
  32. // redisTemplate.opsForValue().set("name","李四");
  33. // redisTemplate.opsForValue().append("name","王五");
  34. // System.out.println(redisTemplate.opsForValue().get("name"));
  35. // 取出结果为最左边内容
  36. // 截取key所对应的value字符串
  37. // System.out.println("截取姓名为:"+redisTemplate.opsForValue().get("name",0,2));
  38. // 存入单个对象,并获取对象属性下的值
  39. // SfUser sfUser = new SfUser();
  40. // sfUser.setUser_name("小明");
  41. // sfUser.setUser_password("123456");
  42. // RedisSerializer redisSerializer = new StringRedisSerializer();
  43. // redisTemplate.opsForValue().set("sfuser",sfUser);
  44. // SfUser sfUser1 = (SfUser) redisTemplate.opsForValue().get("sfuser");
  45. // System.out.println("setUser_name=="+sfUser1.getUser_name());
  46. // System.out.println("setUser_password=="+sfUser1.getUser_password());
  47. // 存入多个对象,类似于Push栈,先进后出
  48. // redisTemplate.opsForList().leftPush("names","萧红");
  49. // redisTemplate.opsForList().leftPush("names","小皇");
  50. // redisTemplate.opsForList().leftPush("names","小兰");
  51. // redisTemplate.opsForList().leftPush("names","小路");
  52. // redisTemplate.opsForList().leftPush("names","小紫");
  53. // 移除指定对象
  54. // count> 0:删除等于从头到尾移动的值的元素。
  55. // count <0:删除等于从尾到头移动的值的元素。
  56. // count = 0:删除等于value的所有元素
  57. // redisTemplate.opsForList().remove("names",0,"萧红");
  58. // 0,-1:输出全部
  59. // List list = redisTemplate.opsForList().range("names",0,-1);
  60. // for (Object objnames :list){
  61. // System.out.println(objnames);
  62. // }
  63. // 返回key所对应的value值得长度
  64. // System.out.println("names的长度为:"+redisTemplate.opsForValue().size(""));
  65. // 存入对象数组
  66. // List<SfUser> sfUserList = new ArrayList<SfUser>();
  67. //
  68. // SfUser sfUser1 = new SfUser();
  69. // sfUser1.setUser_name("张三");
  70. //
  71. // SfUser sfUser2 = new SfUser();
  72. // sfUser2.setUser_name("张三");
  73. //
  74. // sfUserList.add(sfUser1);
  75. // sfUserList.add(sfUser2);
  76. // RedisSerializer redisSerializer = new StringRedisSerializer();
  77. // redisTemplate.setStringSerializer(redisSerializer);
  78. //
  79. // redisTemplate.opsForValue().set("sfUserList",sfUserList);
  80. // List<SfUser> sfUserList1 = (List<SfUser>) redisTemplate.opsForValue().get("sfUserList");
  81. //
  82. // System.out.println(sfUserList1.size());
  83. return "Redis存入成功!";
  84. }
  85. }

2.5 使用opsForValue操作字符串

  1. 存储字符串
  2. 使用:redisTemplate.opsForValue().set("name","tom");
  3. 结果:redisTemplate.opsForValue().get("name") 输出结果为tom
  4. ------------------------------------------------------------------
  5. 设置失效时间
  6. 使用:redisTemplate.opsForValue().set("name","tom",10, TimeUnit.SECONDS);
  7. TimeUnit.DAYS //天
  8. TimeUnit.HOURS //小时
  9. TimeUnit.MINUTES //分钟
  10. TimeUnit.SECONDS //秒
  11. TimeUnit.MILLISECONDS //毫秒
  12. 结果:redisTemplate.opsForValue().get("name")由于设置的是10秒失效,十秒之内查询有结果,十秒之后返回为null
  13. -------------------------------------------------------------------
  14. 支持整型与浮点型(increment
  15. 使用:template.opsForValue().increment("sex",1);
  16. //System.out.println(template.opsForValue().get("sex"));
  17. //increment存不能用get取,set和get配对使用
  18. 结果:1
  19. --------------------------------------------------------------------
  20. 如果key已经存在并且是一个字符串,则该命令将该值追加到字符串的末尾。如果键不存在,则它被创建并设置为空字符串,因此APPEND在这种特殊情况下将类似于SET
  21. 使用:template.opsForValue().append("name"," hello");
  22. System.out.println(template.opsForValue().get("name"));
  23. 结果:tom Hello
  24. --------------------------------------------------------------------
  25. 截取key所对应的value字符串
  26. System.out.println("*********"+template.opsForValue().get("name",0,3));
  27. 结果:tom
  28. --------------------------------------------------------------------
  29. 返回key所对应的value值得长度
  30. System.out.println("***************"+template.opsForValue().size("key"));
  31. --------------------------------------------------------------------
  32. 存储一个对象(此类必须先序列化实现接口Serializable
  33. RedisSerializer rs = new StringRedisSerializer();
  34. redisTemplate.setStringSerializer(rs);
  35. ValueOperations ops = redisTemplate.opsForValue();
  36. ops.set("user",user);//放入redis
  37. //取出对象
  38. User setuser = (User) redisTemplate.opsForValue().get("user");

2.6 使用opsForList操作list

  1. 将所有指定的值插入存储在键的列表的头部。如果键不存在,则在执行推送操作之前将其创建为空列表。(从左边插入)
  2. redisTemplate.opsForList().leftPush("names","张三");
  3. redisTemplate.opsForList().leftPush("names","李四");
  4. --------------------------------------------------------------------
  5. 将所有指定的值插入存储在键的列表的头部。如果键不存在,则在执行推送操作之前将其创建为空列表。(从右边插入)
  6. redisTemplate.opsForList().rightPush("names","王五");
  7. redisTemplate.opsForList().rightPush("names","马六");
  8. --------------------------------------------------------------------
  9. 获取集合长度
  10. redisTemplate.opsForList().size("names");
  11. --------------------------------------------------------------------
  12. 返回存储在键中的列表的指定元素
  13. 使用:System.out.println(redisTemplate.opsForList().range("list",0,-1));
  14. 结果:[c#, c++, python, java, c#, c#]
  15. --------------------------------------------------------------------
  16. 在列表中index的位置设置value值(如果index不存在则报错)
  17. redisTemplate.opsForList().set("names",1,"岳不群");
  18. --------------------------------------------------------------------
  19. 批量把一个数组插入到列表中
  20. String[] stringarrays = new String[]{"1","2","3"};
  21. redisTemplate.opsForList().leftPushAll("listarray",stringarrays);
  22. --------------------------------------------------------------------
  23. 从存储在键中的列表中删除等于值的元素的第一个计数事件
  24. count> 0:删除等于从头到尾移动的值的元素。
  25. count <0:删除等于从尾到头移动的值的元素。
  26. count = 0:删除等于value的所有元素
  27. redisTemplate.opsForList().remove("names",1,"王五");
  28. --------------------------------------------------------------------
  29. 根据下表获取列表中的值,下标是从0开始的
  30. redisTemplate.opsForList().index("names",2);

2.6 使用opsForSet操作set

  1. 无序集合中添加元素,返回添加个数
  2. 使用:String[] strarrays = new String[]{"strarr1","sgtarr2"};
  3. System.out.println(redisTemplate.opsForSet().add("setTest", strarrays));
  4. 结果:2
  5. --------------------------------------------------------------------
  6. 返回集合中的所有成员
  7. 使用:System.out.println(redisTemplate.opsForSet().members("setTest"));
  8. 结果:[ddd, bbb, aaa, ccc]
  9. --------------------------------------------------------------------
  10. 移除集合中一个或多个成员
  11. 使用:String[] strarrays = new String[]{"strarr1","sgtarr2"};
  12. System.out.println(redisTemplate.opsForSet().remove("setTest",strarrays));
  13. 结果:2
  14. --------------------------------------------------------------------
  15. 无序集合的大小长度
  16. 使用:System.out.println(redisTemplate.opsForSet().size("setTest"));
  17. 结果:1
  18. --------------------------------------------------------------------
  19. 判断 ccc 元素是否是集合 key 的成员
  20. 使用:System.out.println(redisTemplate.opsForSet().isMember("setTest","ccc"));
  21. 结果:true
  22. --------------------------------------------------------------------
  23. 随机获取key无序集合中的一个元素
  24. redisTemplate.opsForSet().randomMember("setTest");

2.7 使用opsForZSet操作有序set

  1. 新增一个有序集合,存在的话为false,不存在的话为true
  2. 使用:System.out.println(template.opsForZSet().add("zset1","zset-1",1.0));
  3. 结果:true
  4. --------------------------------------------------------------------
  5. 从有序集合中移除一个或者多个元素
  6. 使用:System.out.println(template.opsForZSet().range("zset1",0,-1));
  7. System.out.println(template.opsForZSet().remove("zset1","zset-6"));
  8. System.out.println(template.opsForZSet().range("zset1",0,-1));
  9. 结果:[zset-1, zset-2, zset-3, zset-4, zset-5, zset-6]
  10. 1
  11. [zset-1, zset-2, zset-3, zset-4, zset-5]
  12. --------------------------------------------------------------------
  13. 增加元素的score值,并返回增加后的值
  14. 使用://原为1.1
  15. System.out.println(template.opsForZSet().incrementScore("zset1","zset-1",1.1));
  16. 结果:2.2
  17. --------------------------------------------------------------------
  18. 通过分数返回有序集合指定区间内的成员,其中有序集成员按分数值递增(从小到大)顺序排列
  19. 使用:
  20. System.out.println(redisTemplate.opsForZSet().add("zset1","zset-1",1.0));
  21. System.out.println(redisTemplate.opsForZSet().add("zset1","zset-2",6.0));
  22. System.out.println(redisTemplate.opsForZSet().add("zset1","zset-3",8.0));
  23. System.out.println(redisTemplate.opsForZSet().add("zset1","zset-4",4.0));
  24. System.out.println(redisTemplate.opsForZSet().add("zset1","zset-5",10.0));
  25. System.out.println(redisTemplate.opsForZSet().add("zset1","zset-6",2.0));
  26. System.out.println(redisTemplate.opsForZSet().rangeByScore("zset1",0,5));
  27. 结果:[zset-1, zset-6, zset-4]
  28. --------------------------------------------------------------------
  29. 通过分数返回有序集合指定区间内的成员个数
  30. 使用:System.out.println(template.opsForZSet().rangeByScore("zset1",0,5));
  31. System.out.println(template.opsForZSet().count("zset1",0,5));
  32. 结果:[zset-1, zset-6, zset-4]
  33. 3
  34. --------------------------------------------------------------------
  35. 获取有序集合的成员数(zCardsize一样)
  36. 使用:System.out.println(template.opsForZSet().size("zset1"));
  37. 结果:6
  38. --------------------------------------------------------------------
  39. 获取指定成员的score
  40. 使用:System.out.println(template.opsForZSet().score("zset1","zset-1"));
  41. 结果:1.0

3. StringRedisTemplate与RedisTemplate区别点

  • 两者的关系是StringRedisTemplate继承RedisTemplate
  • 两者的数据是不共通的;也就是说StringRedisTemplate只能管理StringRedisTemplate里面的数据,RedisTemplate只能管理RedisTemplate中的数据。
  • (序列化类)RedisTemplate使用的是JdkSerializationRedisSerializer 存入数据会将数据先序列化成字节数组然后在存入Redis数据库。 StringRedisTemplate使用的是StringRedisSerializer

3.1 使用时注意事项:

当你的redis数据库里面本来存的是字符串数据或者你要存取的数据就是字符串类型数据的时候,那么你就使用StringRedisTemplate即可。
但是如果你的数据是复杂的对象类型,而取出的时候又不想做任何的数据转换,直接从Redis里面取出一个对象,那么使用RedisTemplate是更好的选择。

3.2 RedisTemplate使用时常见问题

redisTemplate 中存取数据都是字节数组。当redis中存入的数据是可读形式而非字节数组时,使用redisTemplate取值的时候会无法获取导出数据,获得的值为null

4. StringRedisTemplate常用操作

  1. //向redis里存入数据和设置缓存时间
  2. stringRedisTemplate.opsForValue().set("test", "100",60*10,TimeUnit.SECONDS);
  3. //val做-1操作
  4. stringRedisTemplate.boundValueOps("test").increment(-1);
  5. //根据key获取缓存中的val
  6. stringRedisTemplate.opsForValue().get("test")
  7. //val +1
  8. stringRedisTemplate.boundValueOps("test").increment(1);
  9. //根据key获取过期时间
  10. stringRedisTemplate.getExpire("test")
  11. //根据key获取过期时间并换算成指定单位
  12. stringRedisTemplate.getExpire("test",TimeUnit.SECONDS)
  13. //根据key删除缓存
  14. stringRedisTemplate.delete("test");
  15. //检查key是否存在,返回boolean值
  16. stringRedisTemplate.hasKey("546545");
  17. //向指定key中存放set集合
  18. stringRedisTemplate.opsForSet().add("red_123", "1","2","3");
  19. //设置过期时间
  20. stringRedisTemplate.expire("red_123",1000 , TimeUnit.MILLISECONDS);
  21. //根据key查看集合中是否存在指定数据
  22. stringRedisTemplate.opsForSet().isMember("red_123", "1")
  23. //根据key获取set集合
  24. stringRedisTemplate.opsForSet().members("red_123");
  25. **使用**
  26. @RestController
  27. @RequestMapping("/user")
  28. public class UserResource {
  29. @Autowired
  30. public StringRedisTemplate stringRedisTemplate;
  31. @RequestMapping("/num")
  32. public String countNum() {
  33. String userNum = stringRedisTemplate.opsForValue().get("userNum");
  34. if(StringUtils.isNull(userNum)){
  35. stringRedisTemplate.opsForValue().set("userNum", userService.countNum().toString());
  36. }
  37. return userNum;
  38. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注