Redis知识点总结(2)

Redis知识点总结

 

阿里巴巴面试题:你在项目中为什么选用mysql数据库,而不是NoSQL数据库呢?

答:面试官好,我们的项目中既使用了关系型数据库mysql,也使用了NoSQL数据库(非关系型数据库)Redis,这是根据不同的业务场景决定的。

  关系型数据库的优点:

  mysql数据库是关系型数据库,数据是以关系表的方式存储在硬盘中的,对于一些复杂的查询操作,关系型数据库比较方便。比方说商品,商品一般会对应三张表,分别是商品表、商品详表、商品规格参数表,这三张表通过主外键关联在一起,如果我想查询到一条同时包含三张表中的某些字段的数据信息,需要用到关联查询,关系型数据库是很方便的。而NoSQL数据库是非关系型数据库,是基于键值对的,而且键值对与键值对之间是彼此独立,没有关联的。假如键对应着商品的主键ID,值对应着商品信息,所有的商品信息存储在一个字符串中,当你需要对商品信息中的某部分进行增、删、改、查操作的时候,都非常麻烦。

  mysql数据库安全性比NoSql(非关系型数据库)安全性要高mysql支持事务,支持事务的四大特性ACID,即原子性、一致性、隔离性、持久性,安全性能非常好,而NoSQL数据库对事务支持的不完整,安全性能较低。

  非关系型数据库的优点:

  在一些涉及到频繁查询操作的节点上,以及一些临时存储的数据,我们需要利用NoSQL数据库进行缓存处理,以提高查询的效率,比如网站首页的访问,比如单点登录系统,比如临时购物车数据的存储。NoSQL数据库有如下优点:   

  易扩展NoSQL数据库没有关系型数据库的关系型特性,数据之间没关系,容易扩展。

  读写性能高。一般情况下,NoSQL数据库的数据存储在内存中,读写性能高。

  丰富的数据类型NoSQL数据库无需事先为要存储的数据建立字段,随时可以存储自定义的数据类型,比如Redis,支持6中数据类型。

  高可用NoSQL很容易实现高可用的架构。

 

什么是关系型数据库?

答:通过关系表来存数据的数据库。

 

什么是NoSQL数据库?

答:NoSQL全称Not only SQL,不仅仅是SQL,泛指非关系型数据库,数据一般存在内存中。

 

为什么要学NoSQL数据库?

答:随着互联网的发展,传统的关系型数据库在应对高并发、高负载和高可用的网站时已经显得力不从心,暴露出了很多难以克服的难题。NoSQL的出现就是用来解决这些难题的。

 

主流的NoSQL数据库有哪些?

答:redishbasemongoDB等。

NoSQL数据库的特点?

答:易扩展NoSQL数据库没有关系型数据库的关系型特性,数据之间没关系,容易扩展。

读写性能高。一般情况下,NoSQL数据库的数据存储在内存中,读写性能高。

丰富的数据类型NoSQL数据库无需事先为要存储的数据建立字段,随时可以存储自定义的数据类型。

高可用NoSQL很容易实现高可用的架构。

 

Redis以什么方式存储数据?

答:键值对。

 

Redis中的键(key)都是什么类型的呢?

答:String

 

Redis中的值(value)支持哪几种数据类型?

答:string(字符串)

hash(哈希)

list(列表)

set(集合)

zset(sorted set:有序集合)

 

Redis数据库有哪些优点?

答:

(1) 速度快。数据存储在内存中,读写特别快。

(2) 支持丰富数据类型。键值对中的值支持5种数据类型:stringhashlistsetsorted set

(3) 支持事务,操作都是原子性的。所谓的原子性就是对数据的更改要么全部执行,要么全部不执行。

(4) 易扩展NoSQL数据库没有关系型数据库的关系型特性,数据之间没关系,容易扩展。

(5) 高可用。容易实现高可用的架构。

 

Redis支持的数据类型

 

·Redis中的值(value)支持哪几种数据类型?

答:string(字符串)

hash(哈希)

list(列表)

set(集合)

zset(sorted set:有序集合)

 

·而关于key的定义呢,需要大家注意的几点:

1、key不要太长,最好不要操作1024个字节,这不仅会消耗内存还会降低查找效率

2、Key不要太短,如果太短会降低key的可读性

3、在项目中,key最好有一个统一的命名规范

 

String类型

 

 

 


Hash类型

 

 

 

 

 

此外,还有listsetzset等数据类型,用到的时候再整理!

 

Redis过期时间如何实现?

答:redis通过expire命令来设置key的过期时间。

 

Redis的持久化

Redis的高性能是由于其将所有数据都存储在了内存中,为了使Redis在重启之后仍能保证数据不丢失,需要将数据从内存中同步到硬盘中,这一过程是持久化。

Redis支持两种方式的持久化,一种是RDB方式,一种是AOF方式。可以单独使用其中一种或将二者结合使用。

1、RDB持久化(快照方式,默认开启,无需配置)

该机制是指在指定的时间间隔内将内存中的数据集快照写入磁盘。

2、AOF持久化

该机制将以日志的形式记录服务器所处理的每一个写操作,在Redis服务器启动之初会读取该文件来重新构建数据库,以保证启动后数据库中的数据是完整的。

3、无持久化(若Redis只做缓存用,不需要持久化)

我们可以通过配置的方式禁用Redis服务器的持久化功能,这样我们就可以将Redis视为一个功能加强版的memcached了。

4redis可以同时使用RDBAOF

 

RDB(快照)的优势?

答:

1)一旦采用该方式,那么你的整个Redis数据库将只包含一个文件,这对于文件备份而言是非常完美的。比如,你可能打算每个小时归档一次最近24小时的数据,同时还要每天归档一次最近30天的数据。通过这样的备份策略,一旦系统出现灾难性故障,我们可以非常容易的进行恢复。

2)对于灾难恢复而言,RDB是非常不错的选择。因为我们可以非常轻松的将一个单独的文件压缩后再转移到其它存储介质上。

3)性能最大化。对于Redis的服务进程而言,在开始持久化时,它唯一需要做的只是fork(分叉)出子进程,之后再由子进程完成这些持久化的工作,这样就可以极大的避免服务进程执行IO操作了。

4)相比于AOF机制,如果数据集很大,RDB的启动效率会更高。

 

RDB(快照)的劣势?

答:

1)如果你想保证数据的高可用性,即最大限度的避免数据丢失,那么RDB将不是一个很好的选择。因为系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。

2)由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至1秒钟。

AOF的优势?

答:

(1)该机制可以带来更高的数据安全性,即数据持久性。

(2)由于该机制对日志文件的写入操作采用的是append模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容。

(3)如果日志过大,Redis可以自动启用rewrite机制。

(4)AOF包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。

 

AOF的劣势?

答:

(1)对于相同数量的数据集而言,AOF文件通常要大于RDB文件

(2)根据同步策略的不同,AOF在运行效率上往往会慢于RDB。总之,每秒同步策略的效率是比较高的,同步禁用策略的效率和RDB一样高效。

 

【总结】

Redis的持久化方案有两种,分别是RDBAOF

RDB形式,即快照形式,定期把内存中当前时刻的数据保存到磁盘中,具体保存在磁盘中的快照文件,RDB文件中。当你重启Redis服务器之后,只需要把数据从磁盘中取出来再恢复到内存中就可以了。RDB形式是可能会丢数据的。如果对数据完整性较高,可以用关系型数据库,比如mysql。如果你想用Redis,就必须承受可能丢数据的情况,这个情况仅限于突然断电,内存中的数据还没来得及向磁盘中保存。如果仅有Redis做缓存,数据丢点也无所谓。

AOFappend only file)形式,默认不开启。把对数据库操作的命令保存在一个文件里面,如果想恢复数据库,只需要把这些命令从头到尾执行一遍就可以了。为什么AOF默认不开启呢?因为它会频繁的操作磁盘,默认是每秒钟同步一次,性能会下降,使用Redis的目的就是因为它的高性能,若因为使用AOF将性能拖慢了,就得不偿失了!当然,你如果对数据库完整性要求较高的话,可以开启。话又说回来了,如果对数据完成性要求特别高,那就直接用关系型数据库了。

 

Redis事务

Redis中的事务和我们在关系型数据库中讲的事务不是一回事,它不能算是真正的事务。就是一个p处理。

 

Redis集群的搭建

什么是分布式系统?

答:将一个完整的系统按照功能点拆成若干个相互独立的子系统,每一个子系统可称之为一个节点,每一个节点都可以单独配置多台服务器(集群),各个子系统之间相互进行通信,进行协调合作,共同完成整个系统的业务流程,这就是分布式。

分布式和集群是不得不联系在一起的两个概念,如果多台服务器共同处理一件事情,叫集群;如果多台服务器各自处理不同的事情,彼此之间协调合作,共同完成整个系统的工作,就叫做分布式系统。

 

Redis-Cluster是集群,还是分布式缓存系统?

答:既是集群,也是分布式系统。这要看从哪个角度来考虑。

假如从存储数据是否相同来看,Redis-Cluster中每个结点存储的数据是不一样的,它共有16384个槽(0~16383),假如Redis-Cluster中有3个结点,那么这16384个槽是根据各个节点的性能分布在不同节点上的。第一个节点负责0~5000个槽,第二个节点负责5001~10000个槽,第三个节点负责10001~16383个槽,三个节点分别负责不同范围的数据存储,最终完成对整个数据范围的存储。很显然,这是一个分布式系统。

但如果从Redis-Cluster中所提供的缓存功能来看,每个结点都是用来做缓存的,各个节点提供的功能都是一样的,当内存不够用时,还可以不断横向添加结点来扩大内存容量,很显然,这是一个集群。

  所以,我们会说,Redis集群是一个分布式集群系统。

 

(面试题)你知道哪些分布式缓存,如果要你设计一个分布式缓存,你会怎么去设计?

答:主要有MemcachedRedis。我使用Redis来做分布式缓存。

刚开始对Redis的操作都是单机版,虽然Redis的速度很快,但是在特别高的并发下,Redis也有性能瓶颈。Redis中的数据都放在内存里面,内存能有多大呢?64G,已经很大了,64G都放满了呢?还能放吗?可以,内存放满了会放在硬盘中的虚拟内存中,一旦用到虚拟内存了,性能就很低了,所以我们尽可能的不要超出内存的容量。如果存不下了,但是数据还是很多,还需要往缓存中放,那怎么办呢?通过搭Redis集群来扩展内存空间。官方给出的Redis集群名称为Redis-Cluster

Redis-Cluster架构图如下:

 

集群一般都会有一个入口,有一个集群管理工具,但Redis集群没有入口,即没有代理层,集群中的节点都是相互连接的,通过PING-PONG机制来实现各个节点之间的通信,以及判断各个节点的状态,客户端想要连接集群,只需要连接到集群中的任意一个节点即可。

集群中有那么多个结点,结点中保存的数据一样吗?不一样。如果是一样的,那叫主备。既然是集群,就应该是可以扩容的,如果存储空间不足了,可以加结点,加一个服务器进,存储空间就会变大。所有结点的内存容量加起来才是整个集群内存的总容量,如果每个结点存储的数据都一样,那总容量就只是一个Redis的内存容量了。

Redis集群中,每个结点保存的数据是不一样的。如果不一样,那么当一个结点挂了,那整个集群就不完整了,不完整了就不能用了,所以,要想保证Redis集群的高可用(长时间可使用,而不会宕机),每一个节点都需要加一个备份机,如果这个结点挂了,必须要有备份结点顶上来,来保证集群可以继续提供服务。

Redis集群中有一个投票:容错机制,我们前面说集群中一般都会有一个集群管理工具,但在Redis集群中并没有,那么,我们怎么才能知道集群中哪一个结点挂了呢?Redis集群中有一个投票机制。大家都知道,在选举的时候,是少数服从多数的原则,要判断Redis集群中的某个结点是否挂掉了,需要我们集群中超过半数的节点进行投票,半数以上的节点认为它挂了,它就挂了。假如集群中有5个结点,有三个认为某个结点已经挂了,那么集群就认为这个结点真挂了。这个时候就要看有没有备份结点,如果没有备份结点顶上来,那么集群就会宕机。如果有备份结点,备份结点顶上来,继续维持整个集群的工作,然后管理人员就需要赶快把那个挂掉的节点修理好。那么,集群中最少有几个结点呢?3个!3个结点就可以搭建起一个Redis集群。而在实际开发中,为了保证集群的高可用,还要保证每个结点都有一个备份机,所以,实际中,最小的集群会搭建6个结点。那如果面试官问你:

 

一个Redis集群至少有几个结点?为什么?

答:3个结点。这是由Redis集群中的投票:容错机制决定的。Redis集群中,要判断一个结点是否挂掉了,是通过集群中的其他结点投票决定的。当集群中有一半以上的节点都投票认为该节点挂掉了,Redis集群才会认为该节点挂掉了,这就导致一个Redis集群中最少要有3个结点。

 

当我们使用单机版的Redis做缓存时,操作很简单,当单机版的Redis变成Redis集群后,操作是不是就会变得异常复杂?

答:并不会变多复杂。只需要连接上Redis集群中的任意一个结点,就能连接上整个Redis集群。只是在使用Jedis连接单机版Redis和连接Redis集群时,会有所不同,但对Redis的操作都是一样的。

Redis集群中,每个结点保存的数据是不一样的,那就会有一个问题,如何把数据分散到不同的节点进行存储呢?为解决这个问题,Redis集群中引入了一个概念,叫slot(槽,哈希槽)。Redis集群中一共有16384个槽(0~16383),这是固定的。这些槽有什么作用呢?

当要在Redis集群中放置一个key-value对时,先要对key使用crc16算法得出一个数,然后再用这个数对16384求余数,肯定会得到一个0~16383之间的数,这样每一个key值都会对应一个0~16383之间的哈希槽,然后将key-value键值对放在这个槽对应的Redis结点上就可以了。

 

槽如何进行分配呢?

答:这是可以由为设置的。一般情况下会平均分配。为了保证Redis集群的性能,要看Redis集群中有几个结点,还要看每个结点的性能怎么样。假如有3个结点,每个结点的性能都是完全一样的,那么我们就可以把这16384个槽平均分到3个结点上。

0~5000个槽分到第一个结点上

5001~10000个槽分到第二个结点上

10001~16383个槽分到第三个结点上(为了好计算,这样划分)

 

Redis集群中最多有多少个结点?为什么?

答:最多有16384个结点(这里不考虑备份机的问题)。这是由Redis集群中哈希槽的数量决定的,极限情况下,每个结点有一个哈希槽。

 

架构细节:

(1)所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.

(2)节点的fail是通过集群中超过半数的节点检测失效时才生效.

(3)客户端与redis节点直连,不需要中间proxy.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可

(4)redis-cluster把所有的物理节点映射到[0-16383]slot,cluster负责维护node<->slot<->value

Redis集群中内置了16384个哈希槽,当需要在Redis集群中放置一个key-value时,redis先对key使用crc16算法算出一个结果,然后把结果对16384求余数,这样每个key都会对应一个编号在0-16383之间的哈希槽,redis会根据节点数量大致均等的将哈希槽映射到不同的节点。

 

单击版Redis的安装与启动

(1)redisC语言开发,安装redis需要先将官网下载的源码进行编译,编译依赖gcc环境。如果没有gcc环境,需要安装gcc

(2)Windows下下载的压缩文件上传到Linux下。通过SSH进行上传。

(3)解压文件。

(4)编译redis。进入解压文件夹,cd redis-3.0.0,执行make

(5)安装。make PREFIX=/usr/local/redis install

(6)copy文件。Redis启动需要一个配置文件(redis.conf),可以修改端口号等信息。

(7)Redis启动。分为前端模式启动和后端模式。

前端启动模式:

直接运行bin/redis-server将以前端模式启动,前端模式启动的缺点是启动完成后,不能再进行其他操作,如果要操作必须使用ctrl+c,同时redis-server程序结束,不推荐使用此方法。

后端模式:

·修改redis.conf配置文件,daemonize yes以后端模式启动

·启动时,指定配置文件  cd redis-server ./redis.conf

·Redis默认端口6379,通过当前服务进行查看

 

Redis集群的搭建

Redis集群中至少应该有三个节点。要保证集群的高可用,需要每个节点有一个备份机。

Redis集群至少需要6台服务器。

搭建伪分布式。可以使用一台虚拟机运行6redis实例。需要修改redis的端口号7001-7006

集群搭建环境

1、使用ruby脚本搭建集群。需要ruby的运行环境。

安装ruby

yum install ruby

yum install rubygems

 

2、安装ruby脚本运行使用的包。

[root@localhost ~]# gem install redis-3.0.0.gem

Successfully installed redis-3.0.0

1 gem installed

Installing ri documentation for redis-3.0.0...

Installing RDoc documentation for redis-3.0.0...

[root@localhost ~]#

----------------------------------------------------------------------

[root@localhost ~]# cd redis-3.0.0/src

[root@localhost src]# ll *.rb

-rwxrwxr-x. 1 root root 48141 Apr  1  2015 redis-trib.rb

 

搭建步骤

需要6redis服务器。搭建伪分布式。

需要6redis实例。

需要运行在不同的端口7001-7006

 

第一步:创建6redis实例,每个实例运行在不同的端口。需要修改redis.conf配置文件。配置文件中还需要把cluster-enabled yes前的注释去掉。

 

第二步:启动每个redis实例。(使用p处理统一启动

第三步:使用ruby脚本搭建集群。

./redis-trib.rb create --replicas 1 192.168.25.153:7001 192.168.25.153:7002 192.168.25.153:7003 192.168.25.153:7004 192.168.25.153:7005 192.168.25.153:7006

 

创建关闭集群的脚本:

[root@localhost redis-cluster]# vim shutdow-all.sh

redis01/redis-cli -p 7001 shutdown

redis01/redis-cli -p 7002 shutdown

redis01/redis-cli -p 7003 shutdown

redis01/redis-cli -p 7004 shutdown

redis01/redis-cli -p 7005 shutdown

redis01/redis-cli -p 7006 shutdown

[root@localhost redis-cluster]# chmod u+x shutdow-all.sh

 

[root@localhost redis-cluster]# ./redis-trib.rb create --replicas 1 192.168.25.153:7001 192.168.25.153:7002 192.168.25.153:7003 192.168.25.153:7004 192.168.25.153:7005  192.168.25.153:7006

>>> Creating cluster

Connecting to node 192.168.25.153:7001: OK

Connecting to node 192.168.25.153:7002: OK

Connecting to node 192.168.25.153:7003: OK

Connecting to node 192.168.25.153:7004: OK

Connecting to node 192.168.25.153:7005: OK

Connecting to node 192.168.25.153:7006: OK

>>> Performing hash slots allocation on 6 nodes...

Using 3 masters:

192.168.25.153:7001

192.168.25.153:7002

192.168.25.153:7003

Adding replica 192.168.25.153:7004 to 192.168.25.153:7001

Adding replica 192.168.25.153:7005 to 192.168.25.153:7002

Adding replica 192.168.25.153:7006 to 192.168.25.153:7003

M: 2e48ae301e9c32b04a7d4d92e15e98e78de8c1f3 192.168.25.153:7001

   slots:0-5460 (5461 slots) master

M: 8cd93a9a943b4ef851af6a03edd699a6061ace01 192.168.25.153:7002

   slots:5461-10922 (5462 slots) master

M: 2935007902d83f20b1253d7f43dae32aab9744e6 192.168.25.153:7003

   slots:10923-16383 (5461 slots) master

S: 74f9d9706f848471583929fc8bbde3c8e99e211b 192.168.25.153:7004

   replicates 2e48ae301e9c32b04a7d4d92e15e98e78de8c1f3

S: 42cc9e25ebb19dda92591364c1df4b3a518b795b 192.168.25.153:7005

   replicates 8cd93a9a943b4ef851af6a03edd699a6061ace01

S: 8b1b11d509d29659c2831e7a9f6469c060dfcd39 192.168.25.153:7006

   replicates 2935007902d83f20b1253d7f43dae32aab9744e6

Can I set the above configuration? (type 'yes' to accept): yes

>>> Nodes configuration updated

>>> Assign a different config epoch to each node

>>> Sending CLUSTER MEET messages to join the cluster

Waiting for the cluster to join.....

>>> Performing Cluster Check (using node 192.168.25.153:7001)

M: 2e48ae301e9c32b04a7d4d92e15e98e78de8c1f3 192.168.25.153:7001

   slots:0-5460 (5461 slots) master

M: 8cd93a9a943b4ef851af6a03edd699a6061ace01 192.168.25.153:7002

   slots:5461-10922 (5462 slots) master

M: 2935007902d83f20b1253d7f43dae32aab9744e6 192.168.25.153:7003

   slots:10923-16383 (5461 slots) master

M: 74f9d9706f848471583929fc8bbde3c8e99e211b 192.168.25.153:7004

   slots: (0 slots) master

   replicates 2e48ae301e9c32b04a7d4d92e15e98e78de8c1f3

M: 42cc9e25ebb19dda92591364c1df4b3a518b795b 192.168.25.153:7005

   slots: (0 slots) master

   replicates 8cd93a9a943b4ef851af6a03edd699a6061ace01

M: 8b1b11d509d29659c2831e7a9f6469c060dfcd39 192.168.25.153:7006

   slots: (0 slots) master

   replicates 2935007902d83f20b1253d7f43dae32aab9744e6

[OK] All nodes agree about slots configuration.

>>> Check for open slots...

>>> Check slots coverage...

[OK] All 16384 slots covered.

[root@localhost redis-cluster]#

集群的使用方法

Redis-cli连接集群。

[root@localhost redis-cluster]# redis01/redis-cli -p 7002 -c

-c:代表连接的是redis集群

 

Jedis

需要把jedis依赖的jar包添加到工程中。Maven工程中需要把jedis的坐标添加到依赖。

推荐添加到服务层。E3-content-Service工程中。

连接单机版

第一步:创建一个Jedis对象。需要指定服务端的ip及端口。

第二步:使用Jedis对象操作数据库,每个redis命令对应一个方法。

第三步:打印结果。

第四步:关闭Jedis

@Test

public void testJedis() throws Exception {

// 第一步:创建一个Jedis对象。需要指定服务端的ip及端口。

Jedis jedis = new Jedis("192.168.25.153", 6379);

// 第二步:使用Jedis对象操作数据库,每个redis命令对应一个方法。

String result = jedis.get("hello");

// 第三步:打印结果。

System.out.println(result);

// 第四步:关闭Jedis

jedis.close();

}

连接单机版使用连接池

第一步:创建一个JedisPool对象。需要指定服务端的ip及端口。

第二步:从JedisPool中获得Jedis对象。

第三步:使用Jedis操作redis服务器。

第四步:操作完毕后关闭jedis对象,连接池回收资源。

第五步:关闭JedisPool对象。

@Test

public void testJedisPool() throws Exception {

// 第一步:创建一个JedisPool对象。需要指定服务端的ip及端口。

JedisPool jedisPool = new JedisPool("192.168.25.153", 6379);

// 第二步:从JedisPool中获得Jedis对象。

Jedis jedis = jedisPool.getResource();

// 第三步:使用Jedis操作redis服务器。

jedis.set("jedis", "test");

String result = jedis.get("jedis");

System.out.println(result);

// 第四步:操作完毕后关闭jedis对象,连接池回收资源。

jedis.close();

// 第五步:关闭JedisPool对象。

jedisPool.close();

}

连接集群版

第一步:使用JedisCluster对象。需要一个Set<HostAndPort>参数。Redis节点的列表。

第二步:直接使用JedisCluster对象操作redis。在系统中单例存在。

第三步:打印结果

第四步:系统关闭前,关闭JedisCluster对象。

 

@Test

public void testJedisCluster() throws Exception {

// 第一步:使用JedisCluster对象。需要一个Set<HostAndPort>参数。Redis节点的列表。

Set<HostAndPort> nodes = new HashSet<>();

nodes.add(new HostAndPort("192.168.25.153", 7001));

nodes.add(new HostAndPort("192.168.25.153", 7002));

nodes.add(new HostAndPort("192.168.25.153", 7003));

nodes.add(new HostAndPort("192.168.25.153", 7004));

nodes.add(new HostAndPort("192.168.25.153", 7005));

nodes.add(new HostAndPort("192.168.25.153", 7006));

JedisCluster jedisCluster = new JedisCluster(nodes);

// 第二步:直接使用JedisCluster对象操作redis。在系统中单例存在。

jedisCluster.set("hello", "100");

String result = jedisCluster.get("hello");

// 第三步:打印结果

System.out.println(result);

// 第四步:系统关闭前,关闭JedisCluster对象。

jedisCluster.close();

}

 

向业务逻辑中添加缓存

接口封装

常用的操作redis的方法提取出一个接口,分别对应单机版和集群版创建两个实现类。

接口定义

public interface JedisClient {

 

String set(String key, String value);

String get(String key);

Boolean exists(String key);

Long expire(String key, int seconds);

Long ttl(String key);

Long incr(String key);

Long hset(String key, String field, String value);

String hget(String key, String field);

Long hdel(String key, String... field);

}

单机版实现类

public class JedisClientPool implements JedisClient {

@Autowired

private JedisPool jedisPool;

 

@Override

public String set(String key, String value) {

Jedis jedis = jedisPool.getResource();

String result = jedis.set(key, value);

jedis.close();

return result;

}

 

@Override

public String get(String key) {

Jedis jedis = jedisPool.getResource();

String result = jedis.get(key);

jedis.close();

return result;

}

 

@Override

public Boolean exists(String key) {

Jedis jedis = jedisPool.getResource();

Boolean result = jedis.exists(key);

jedis.close();

return result;

}

 

@Override

public Long expire(String key, int seconds) {

Jedis jedis = jedisPool.getResource();

Long result = jedis.expire(key, seconds);

jedis.close();

return result;

}

 

@Override

public Long ttl(String key) {

Jedis jedis = jedisPool.getResource();

Long result = jedis.ttl(key);

jedis.close();

return result;

}

 

@Override

public Long incr(String key) {

Jedis jedis = jedisPool.getResource();

Long result = jedis.incr(key);

jedis.close();

return result;

}

 

@Override

public Long hset(String key, String field, String value) {

Jedis jedis = jedisPool.getResource();

Long result = jedis.hset(key, field, value);

jedis.close();

return result;

}

 

@Override

public String hget(String key, String field) {

Jedis jedis = jedisPool.getResource();

String result = jedis.hget(key, field);

jedis.close();

return result;

}

 

@Override

public Long hdel(String key, String... field) {

Jedis jedis = jedisPool.getResource();

Long result = jedis.hdel(key, field);

jedis.close();

return result;

}

}

 

配置:applicationContext-redis.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"

xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans4.2.xsd

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context4.2.xsd

http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx4.2.xsd

http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util4.2.xsd">

 

<!-- 配置单机版的连接 -->

<bean id="jedisPool" class="redis.clients.jedis.JedisPool">

<constructor-arg name="host" value="192.168.25.153"></constructor-arg>

<constructor-arg name="port" value="6379"></constructor-arg>

</bean>

<bean id="jedisClientPool" class="cn.e3mall.jedis.JedisClientPool"/>

</beans>

 

集群版实现类

package cn.e3mall.jedis;

 

import org.springframework.beans.factory.annotation.Autowired;

 

import redis.clients.jedis.JedisCluster;

 

public class JedisClientCluster implements JedisClient {

@Autowired

private JedisCluster jedisCluster;

 

@Override

public String set(String key, String value) {

return jedisCluster.set(key, value);

}

 

@Override

public String get(String key) {

return jedisCluster.get(key);

}

 

@Override

public Boolean exists(String key) {

return jedisCluster.exists(key);

}

 

@Override

public Long expire(String key, int seconds) {

return jedisCluster.expire(key, seconds);

}

 

@Override

public Long ttl(String key) {

return jedisCluster.ttl(key);

}

 

@Override

public Long incr(String key) {

return jedisCluster.incr(key);

}

 

@Override

public Long hset(String key, String field, String value) {

return jedisCluster.hset(key, field, value);

}

 

@Override

public String hget(String key, String field) {

return jedisCluster.hget(key, field);

}

 

@Override

public Long hdel(String key, String... field) {

return jedisCluster.hdel(key, field);

}

 

}

 

 

Spring的配置:

<!-- 集群版的配置 -->

<bean id="jedisCluster" class="redis.clients.jedis.JedisCluster">

<constructor-arg>

<set>

<bean class="redis.clients.jedis.HostAndPort">

<constructor-arg name="host" value="192.168.25.153"></constructor-arg>

<constructor-arg name="port" value="7001"></constructor-arg>

</bean>

<bean class="redis.clients.jedis.HostAndPort">

<constructor-arg name="host" value="192.168.25.153"></constructor-arg>

<constructor-arg name="port" value="7002"></constructor-arg>

</bean>

<bean class="redis.clients.jedis.HostAndPort">

<constructor-arg name="host" value="192.168.25.153"></constructor-arg>

<constructor-arg name="port" value="7003"></constructor-arg>

</bean>

<bean class="redis.clients.jedis.HostAndPort">

<constructor-arg name="host" value="192.168.25.153"></constructor-arg>

<constructor-arg name="port" value="7004"></constructor-arg>

</bean>

<bean class="redis.clients.jedis.HostAndPort">

<constructor-arg name="host" value="192.168.25.153"></constructor-arg>

<constructor-arg name="port" value="7005"></constructor-arg>

</bean>

<bean class="redis.clients.jedis.HostAndPort">

<constructor-arg name="host" value="192.168.25.153"></constructor-arg>

<constructor-arg name="port" value="7006"></constructor-arg>

</bean>

</set>

</constructor-arg>

</bean>

<bean id="jedisClientCluster" class="cn.e3mall.jedis.JedisClientCluster"/>

 

注意:单机版和集群版不能共存,使用单机版时注释集群版的配置。使用集群版,把单机版注释

封装代码测试

@Test

public void testJedisClient() throws Exception {

//初始化Spring容器

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring/applicationContext-redis.xml");

//从容器中获得JedisClient对象

JedisClient jedisClient = applicationContext.getBean(JedisClient.class);

jedisClient.set("first", "100");

String result = jedisClient.get("first");

System.out.println(result);

}

 

 


阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页