一、引言

本篇博客以redis缓存为主。至于什么是redis缓存?还有没有其它的缓存?哪个缓存的性能会更好?这里就不一一做介绍了!(有兴趣的可以自己去百度一下)

在日常的开发中,我们或多或少(必须)的会用到缓存。为了提高系统性能、提升用户体验度,用户体验是多么的重要;这就要求在软件设计时,不但要注重可靠性、安全性、可扩展性以及可维护性等等的一些指标,更要注重用户的体验,用户体验分很多方面,但是有一点非常重要就是对用户操作的响应一定要快;怎样提高用户访问的响应速度,这就是摆在架构设计中必须要解决的问题;说到提高服务的响应速度就不得不说缓存了;

从系统的层面说,CPU的速度远远高于磁盘IO的速度;所以要想提高响应速度,必须减少磁盘IO的操作,但是有很多信息又是存在数据库当中的,每次查询数据库就是一次IO操作;请求响应时间等于网络响应时间和服务器响应时间;网络我们控制不了,服务器响应时间包括CPU计算时间和磁盘IO时间,其中CPU计算时间这个有硬件资源决定的,我们尽量减少算法的复杂度来减少它,磁盘IO时间,这个时间是非常慢的,应该尽量减少;

当客户端调用某个接口获取信息的时候,执行顺序1、2、3、4;由于信息存放在DB中,所以2、3就有一次磁盘IO操作;这个看似非常简单业务逻辑,但是当你做架构设计的时候往往要考虑最坏的场景,或者当成千上万的用户频繁的调用这个接口应该怎么处理?如果按照上图这样的架构处理,这个看似简单业务的接口会使整个系统变慢,这样用户的请求就会长时间得不到响应;这样的问题怎么解决那,这时候就该缓存登场了;

缓存有很多种、也有很多种缓存策略。这里就不一一就探讨了,毕竟这篇博客是讲关于的工具类!总之一句话,要想提高系统的性能,尽量减少IO的操作,特别是磁盘IO的操作;使用缓存可以有效的避免这种情况;所以在架构设计过程中,涉及到查询数据库的时候,应该考虑一下是不是使用缓存技术来提高系统的性能,并且降低数据库的压力。

二、无知的痛(用get / set方式使用Redis)

在根据某个需求设计业务的时候,比如说购物车:涉及到添加、查询、修改、删除。不说这四个具体实现时候的细节,这不就简单的对数据库增、删、改、查吗?但是,当成千上万的用户频繁访问的时候,简单的事情在高并发的情况下就会变的不简单!这个时候就需要有个东西来代替数据,而且还要比数据库更快,来应对可能出现的高并发!所以我们想到了(redis)缓存,作为一个key / value 存在,很多开发者自然的使用set/get 方式来使用 redis  ,实际上这并不是最优化的使用方法。尤其在未启用VM 情况下,Redis 全部数据需要放入内存,节约内存尤其重要。 假如一个key-value单元需要最小占用512字节,即使只存一个字节也占了512字节(比如set/get,一个key-value对应一条数据)。这时候就有一个设计模式,可以把key复用,几个key-value作为一个大的value,大的value再作为一个value,set存入一个key中。这样同样512字节就会存放10-100倍的容量。 这就是为了节约内存,建议使用hash类型而不是set/get的方式来使用Redis。

三、hash类型方式使用redis -- 指定返回类型

在日常开发中,我们会把业务中的所有特性封装成一个对象,再把这个对象存入到redis缓存中。在使用redis的时候,通常会把redis常用的方法封装成一个工具类。然后我们调用工具类中的方法,把存入的对象传到方法中。通常方法会把对象转换成string存入缓存,需要的时候再把string取出来,然后再转换成对象!大多数的情况就是如此,但是在我实际的开发中传入的是个和业务有关的对象,返给我的却是一个object对象(和业务没有半毛钱关系)。我想要让返回的对象和业务有关,还得强转一下!这返回的是单个对象,如果是个list呢?循环强转吗?那如果是map呢?当然肯定都是能转的,但是这样就增加了实际业务中的代码量!在我看来多一行于业务无关的代码都是罪恶的(纵然它是为了和业务产生关联),我想要的是 我给你存的是啥!返回的就是啥!别整那些没用的......

1.根据key和fieid返回hash中指定存储位置的值,指定返回类型

  1. /**
  2. * 返回hash中指定存储位置的值
  3. * @param key
  4. * @param fieid
  5. * @param obj
  6. * @param <T>
  7. * @return
  8. */
  9. public<T> T hget(String key,String fieid,T obj) {
  10. Jedis jedis = null;
  11. try {
  12. logger.info("hget >> key+fieid:{}",key +"+"+ fieid);
  13. jedis = jedisPool.getResource();
  14. String hget = jedis.hget(key, fieid);
  15. ObjectMapper om = new ObjectMapper();
  16. T t =(T) om.readValue(hget, obj.getClass());
  17. return t;
  18. } catch (Exception e) {
  19. logger.error("Jedis hget 异常: " + e.getMessage());
  20. return null;
  21. } finally {
  22. closeRedis(jedis);
  23. }
  24. }

调用:

  1. //调用hget方法
  2. DemoDTO demoDTO = jedis.hget("key", "fieid", new DemoDTO());

2.hvals()方法,获取hash中value的集合,指定返回的集合类型

  1. /**
  2. * 获取hash中value的集合,指定返回的集合类型
  3. * @param key
  4. * @param obj
  5. * @param <T>
  6. * @return
  7. */
  8. public<T> List<T> hvals(String key,T obj) {
  9. Jedis jedis = null;
  10. try {
  11. logger.info("hvals >> key:{}",key);
  12. jedis = jedisPool.getResource();
  13. List<String> hvals = jedis.hvals(key);
  14. Iterator<String> iterator = hvals.iterator();
  15. List<T> returnList = new ArrayList<>();
  16. ObjectMapper om = new ObjectMapper();
  17. while (iterator.hasNext()) {
  18. String next = iterator.next();
  19. T t =(T) om.readValue(next, obj.getClass());
  20. returnList.add(t);
  21. }
  22. return returnList;
  23. } catch (Exception e) {
  24. logger.error("Jedis hvals fail >> e:{}",e.getMessage());
  25. return null;
  26. } finally {
  27. closeRedis(jedis);
  28. }
  29. }

调用:

  1. //调用hvals方法
  2. List<DemoDTO> demoListDTOS = jedis.hvals("key", new DemoDTO());

3.以Map的形式返回hash中的存储和值,指定map中的value类型

  1. /**
  2. * 以Map的形式返回hash中的存储和值
  3. * @param key
  4. * @param obj
  5. * @param <T>
  6. * @return
  7. */
  8. public<T> Map<String,T> hgetAll(String key,T obj) {
  9. Jedis jedis = null;
  10. try {
  11. logger.info("hget >> key+obj:{}",key+"+"+obj);
  12. jedis = jedisPool.getResource();
  13. Map<String, String> map = jedis.hgetAll(key);
  14. Map<String, T> returnMap = new HashMap<>();
  15. ObjectMapper om = new ObjectMapper();
  16. for (Map.Entry<String, String> e : map.entrySet()) {
  17. T t =(T) om.readValue(e.getValue(), obj.getClass());
  18. returnMap.put(e.getKey(),t);
  19. }
  20. return returnMap;
  21. } catch (Exception e) {
  22. logger.error("Jedis hget fail >> e:{}" + e.getMessage());
  23. return null;
  24. } finally {
  25. closeRedis(jedis);
  26. }
  27. }

调用:

  1. //调用hgetAll方法
  2. Map<String,DemoDTO> stringDemoDTOMap = jedis.hgetAll("key", new DemoDTO());

4.关闭jedis连接,将jedis连接归还redis连接池

  1. /**
  2. * 关闭jedis连接池
  3. * @param jedis
  4. */
  5. private void closeRedis(Jedis jedis) {
  6. if (jedis != null){
  7. try{
  8. jedis.close();
  9. }catch (Exception e){
  10. logger.error("Jedis关闭异常" + e.getMessage());
  11. }
  12. }
  13. }

closeRedis 释放资源 防止达到最大连接数出现异常 如 :maxTotal=300

如果每次获取完redis连接,不归还redis连接池的话,当超过redis的最大连接数。然后redis就雪崩了!注意!注意!!!

四、结尾

其实指定redis返回类型,没什么高大上的!就是用了ObjectMapper类,这个类是Jackson库的主要类。但是,我百度查过网上很多关于redis的连接工具类,发现却没有一个做过这方面的处理!其实这个也不难,在写业务的时候随手就能写出来。我也就是在用redis的时候偶尔蹦出来了这个想法,每都要多那么两三行于业务无关的代码让人非常的抓狂

高效Redis工具类的更多相关文章

  1. 小D课堂 - 零基础入门SpringBoot2.X到实战_第9节 SpringBoot2.x整合Redis实战_40、Redis工具类封装讲解和实战

    笔记 4.Redis工具类封装讲解和实战     简介:高效开发方式 Redis工具类封装讲解和实战         1.常用客户端 https://redisdesktop.com/download ...

  2. Redis操作Hash工具类封装,Redis工具类封装

    Redis操作Hash工具类封装,Redis工具类封装 >>>>>>>>>>>>>>>>>> ...

  3. Redis操作字符串工具类封装,Redis工具类封装

    Redis操作字符串工具类封装,Redis工具类封装 >>>>>>>>>>>>>>>>>>& ...

  4. redis 工具类 单个redis、JedisPool 及多个redis、shardedJedisPool与spring的集成配置

    http://www.cnblogs.com/edisonfeng/p/3571870.html http://javacrazyer.iteye.com/blog/1840161 http://ww ...

  5. SpringBoot整合Redis及Redis工具类撰写

            SpringBoot整合Redis的博客很多,但是很多都不是我想要的结果.因为我只需要整合完成后,可以操作Redis就可以了,并不需要配合缓存相关的注解使用(如@Cacheable). ...

  6. redistemplate优雅地操作redis redis 工具类

    参考:https://www.cnblogs.com/superfj/p/9232482.html redis 工具类 package com.service; import org.springfr ...

  7. java的redis工具类

    package com.mracale.sell.utils; /** * @Auther: Mracale */ import org.springframework.beans.factory.a ...

  8. Redis 工具类

    项目里的Redis 工具类,写下来以备后用 public class RedisConnector { public class RedisParseResult<T> { public ...

  9. Redis 工具类 java 实现的redis 工具类

    最近了解了一下非关系型数据库 redis 会使用简单的命令 在自己本地电脑 使用时必须先启动服务器端 在启动客户端 redis 简介 Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内 ...

随机推荐

  1. 游戏引擎架构 (Jason Gregory 著)

    第一部分 基础 第1章 导论 (已看) 第2章 专业工具 (已看) 第3章 游戏软件工程基础 (已看) 第4章 游戏所需的三维数学 (已看) 第二部分 低阶引擎系统 第5章 游戏支持系统 (已看) 第 ...

  2. github上计算String相似度好的项目

    项目中包含了杰卡德NGram.cosin夹角.最长公共子序列.边际距离等常用的相似度算法. https://github.com/tdebatty/java-string-similarity

  3. python统计wav文件的时长

    import wave import os.path # 音频存放文件夹绝对路径 filedir = '/Users/111/PycharmProjects/TextClassify/wav' lis ...

  4. D3力布图绘制--在曲线路径上添加文本标记

    今天遇到一个在曲线路径上标识文本标记的问题,找到一个比较好的解决思路,在这里分享下: 使用d3建立的Force Layout,加上自定义的箭头形状,将多条连接线线改成弧线(https://www.cn ...

  5. Course: ISA 414

    Assignment #4Course: ISA 414Points:100Due date: November 18th, 2019, before 11:59 pmSubmission instr ...

  6. 明解C语言 中级篇 第二章答案

    练习2-1 /* 倒计时后显示程序运行时间 */ #include <time.h> #include <stdio.h> /*--- 等待x毫秒 ---*/ int slee ...

  7. Mac终端常用快捷键

    Ctrl + a 跳到行首Ctrl + e 跳到行尾Ctrl + d 删除一个字符,相当于通常的Delete键(命令行若无所有字符,则相当于exit:处理多行标准输入时也表示eof)Ctrl + h ...

  8. netcore sdk版本选择

    NetCore sdk并不是每个版本都支持VS2017工具,也不是每个版本的sdk版本号和Runtime版本号都一样,这就需要我们在创建某个版本的net core应用时注意: 使用不同版本的vs时需要 ...

  9. Python【day 13】内置函数01

    1.python3.6.2 一共有 68个内置函数2.分成6个大类 1.反射相关-4个 2.面向对象相关-9个 3.作用域相关--2个 1.globlas() #注意:最后是s,复数形式 查看全局作用 ...

  10. mask-rcnn的解读(三):batch_slice()

    我已用随机生产函数取模拟5张图片各有8个box的坐标值,而后验证batch_slice()函数的意义.由于inputs_slice = [x[i] for x in inputs] output_sl ...