侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

redis学习笔记——不仅仅是存取数据

Redis  /  管理员 发布于 3年前   309

最近项目中用到比较多redis,感觉之前对它一直局限于get/set数据的层面。其实作为一个强大的NoSql数据库产品,如果好好利用它,会带来很多意想不到的效果。(因为我搞java,所以就从jedis的角度来补充一点东西吧。PS:不一定全,只是个人理解,不喜勿喷)

 

1、关于JedisPool.returnSource(Jedis jeids)

 

这个方法是从redis的池中释放一个redis连接的,类似线程池对线程的回收管理的。看下面的demo代码:

 

public static void main(String[] args) {Jedis jedis = JedisFactory.get();//这个方法是用来得到redis实例的,这里省略Jedis jedis2 = JedisFactory.get();jedis.set("key1", "good job");jedis.set("key2", "holy crap");System.out.println(jedis.get("key1") + ", " + jedis2.get("key2"));JedisFactory.close(jedis);//这个方法是用来回收redis实例的,这里省略System.out.println("redis池回收jedis1之后:");System.out.println(jedis.get("key1") + ", " + jedis2.get("key2"));}

 在打开redis服务器后,打印结果如下:

 

good job, holy crap

redis池回收jedis1之后:

good job, holy crap

 

上述demo代码说明了两点:

1)redis池中不同redis实例存储的数据可以共享——jedis和jeids2都是通过JedisPool.getResource()方法得到的,即它们都是从池中得到的不同实例,但是jeids set的数据可以被jeids2 get到

2)调用池的JedisPool.returnResource(Jedis jedis)之后,并不会把jedis set的数据删掉。

于是,引出我们常见的一个异常:

 java.util.NoSuchElementException: Timeout waiting for idle object

这个异常表明没有得到空闲的redis实例,从而引起超时。

老生常谈的问题是,在try{ ... } catch(Exception e){ ... } finally{ ... }代码结构中,必须把JedisPool.returnResource(Jedis jedis)放在finally中,这样无论是否发生异常,jedis都能很好的被归还到池中,以便下次被其他线程使用。而经过上述demo的测试表明——return给池后,并不需要担心数据会被删除!这也是我之前一直困惑的地方!

 

2、redis的key的管理——当key越来越多了咋办?

redis是可以存放很多数据,并且都是以k-v形式存放的。它也常常被使用在高并发的环境下,数据肯定也会越来越多。这时候问题来了——如何避免key越来越多,而其实大多时候数据只是暂时缓存一下而已,并不需要我们长久保存在内存中。这时候管理key就显得很重要了。看下面的demo代码:

public static void main(String[] args) {Jedis jedis = JedisFactory.get();Jedis jedis2 = JedisFactory.get();jedis.set("test1", "well done");jedis.set("test2", "pain ends");System.out.println(jedis.get("test1") + " " + jedis2.get("test2"));jedis2.del("test1");jedis2.expire("test2", 12);System.out.println(jedis.get("test1") + " " + jedis2.get("test2"));try {Thread.sleep(10000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("10s后:" + jedis.get("test1") + " " + jedis2.get("test2"));try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("再过3s后:" + jedis.get("test1") + " " + jedis2.get("test2"));}

 代码跑完后,打印结果为:

well done pain ends

null pain ends

10s后:null pain ends

 

再过3s后:null null

 

打印结果表明:对key的删除操作和设置key的过期时间效果等同——都会在某段时间后删除数据,包括对应的key。在项目中,删除数据的时间点往往不好控制,所以最好是设置key的过期时间,该key会在指定过期时间后自动被内存删除。从而不会一直占用redis的内存。

 

3、redis库的“分区”

redis默认会有16个"库"——我们可以把它理解成16个内存分区。而我们默认是使用第一个库即:select(0),下面的demo:

Jedis jedis = JedisFactory.get();//这个方法是用来得到redis实例的,这里省略Jedis jedis2 = JedisFactory.get();System.out.println(jedis == jedis2);jedis.set("key1", "good job");//jedis.set("key2", "holy crap");jedis2.select(1);System.out.println(jedis.get("key1") + ", " + jedis2.get("key1"));

 跑出来的结果为:

false

good job, null

 

说明jedis2没有get到jedis1 set的东西,这是因为jedis2.select(1);它选择了第二个库,自然获取不到第一个库里set的数据了。如果要获取到对应库设置的值,必须先select(int index)再获取。——因为我们平常都是默认使用第一个库,所以不需要该操作;

但为了对key按不同功能来分区,达到解耦和易于管理的目的,最好选择不同的库空间。需要get不同的数据时,先要注意它之前是在哪个库set的。

——是否get set只与所在库有关?而与redis实例无关?——只要在同一个库,不同redis实例set的数据,另一个redis实例便可得到。

 

4、用redis统计过去某段时间的总数据、平均数据等

这个我之前一直是“事后统计”的想法,即把该段时间的东西先存到redis,再去遍历集合,然后再做统计。这样循环效率很低,尤其是在高并发数据的情形下。所以我们可以边按不同统计指标来边入redis。比如使用jedis.incr(key)累加,或jedis.incrBy(key, num)按num累加,统计时就可以直接拿key对应的value,因为它不断进行了incr操作了,就已经是我们要的总数据了,而非事后拿到所有的数据累加;lpush(key, data)可以缓存出一个集合,便于做统计时使用边入jeids.sort(key)来排序,得出最大、最小之类的指标,而非通过排序算法来不断比较。

 

5、关于hmset hgetAll

这个是value为map类型的,要慎用!因为一旦map里面某个Entry的value为null的话,会报jedisdataexception异常的,提示set的value不能为null(即:一旦map里面有一对k-v的value为null,即使整个map不为null,也会报错!)

所以一般尽量避免使用hmset,不仅容易出错,而且你取的时候,先得到map,再从map里用对应的key去取value,效率极低。

 

——对于redis的强大可以从很多简单的demo来测试了解。


  • 上一条:
    Redis
    下一条:
    NoSQL数据库之Redis数据库管理(String类型和hash类型)
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • Redis集群之主从复制错误:NOAUTH Authentication required解决方式(0个评论)
    • redis数据同步工具redis-shake之两服务器之间数据实时同步案例(0个评论)
    • redis中INCR、SETNX、SET三种加锁方式详解(0个评论)
    • redis安全配置之修改端口、添加密码流程步骤及启动使用(0个评论)
    • redis实现分页(0个评论)
    • 近期文章
    • 在laravel框架中的5个HTTP客户端技巧分享(0个评论)
    • 在go语言中使用FFmpeg库实现PCM音频文件编码为mp3格式文件流程步骤(0个评论)
    • gopacket免安装Pcap实现驱动层流量抓包流程步骤(0个评论)
    • 在laravel项目中实现密码强度验证功能推荐扩展包:password-strength(0个评论)
    • 在go语言中用filepath.Match()函数以通配符模式匹配字符串示例(0个评论)
    • Laravel Response Classes 响应类使用优化浅析(0个评论)
    • mysql中sql_mode的各模式浅析(0个评论)
    • 百度文心一言今天发布,个人第一批内测体验记录,不好别打我(0个评论)
    • 嘿加密世界让我们谈谈在共识中将中本聪主流化(0个评论)
    • 在go语言中寻找两个切片或数组中的相同元素/共同点/交集并集示例代码(0个评论)
    • 近期评论
    • 博主 在

      2023年国务院办公厅春节放假通知:1月21日起休7天中评论 @ xiaoB 你只管努力,剩下的叫给天意;天若有情天亦老,..
    • xiaoB 在

      2023年国务院办公厅春节放假通知:1月21日起休7天中评论 会不会春节放假后又阳一次?..
    • BUG4 在

      你翻墙过吗?国内使用vpn翻墙可能会被网警抓,你需了解的事中评论 不是吧?..
    • 博主 在

      go语言+beego框架中获取get,post请求的所有参数中评论 @ t1  直接在router.go文件中配就ok..
    • Jade 在

      如何在MySQL查询中获得当月记录中评论 Dear zongscan.com team, We can skyroc..
    • 2017-12
    • 2020-03
    • 2020-05
    • 2021-04
    • 2022-03
    • 2022-05
    • 2022-08
    • 2023-02
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客