Redis(二)

Redis的复制 

复制

Redis支持复制的功能,以实现当一台服务器的数据更新后,自动将新的数据同步到其它数据库。

 

Redis复制实现中,把数据库分为主数据库master和从数据库slave,主数据库可以进行读写操作,从数据库一般是只读的,当主数据库数据变化的时候,会自动同步给从数据库。

 

复制带来的好处

1:可以实现读写分离

2:利于在主数据库崩溃时的数据恢复

 

复制的配置

主数据库不做配置;从数据库需要在配置中设置“slaveof 主数据库ip 主数据库端口”。

 

复制的基本操作命令

1:info replication :可以查看复制节点的相关信息

2:slaveof:可在运行期间修改slave节点的信息,如果该数据库已经是某个主数据库的从数据库,那么会停止和原主数据库的同步关系,转而和新的主数据库同步

3:slaveof no one:使当前数据库停止与其他数据库的同步,转成主数据库

 

复制的基本原理

1:slave启动时,会向master发送sync命令,2.8版后发送psync,以实现增量复制

2:主数据库接到sync请求后,会在后台保存快照,也就是实现RDB持久化,并将保存快照期间接收到的命令缓存起来

3:快照完成后,主数据库会将快照文件和所有缓存的命令发送给从数据库

4:从数据库接收后,会载入快照文件并执行缓存的命令,从而完成复制的初始化

5:在数据库使用阶段,主数据库会自动把每次收到的写命令同步到从服务器

 

乐观复制策略

Redis采用乐观复制的策略,容忍在一定时间内主从数据库的内容不同,当然最终的数据会是一样的。这个策略保证了性能,在复制的时候,主数据库并不阻塞,照样处理客户端的请求。

Redis提供了配置来限制只有当数据库至少同步给指定数量的从数据库时, 主数据库才可写,否则返回错误。配置是:min-slaves-to-write、min-slaves- max-lag

 

无硬盘复制

当复制发生时,主数据库会在后台保存RDB快照,即使你关闭了RDB,它也会这么做,这样就会导致:

1:如果主数据库关闭了RDB,现在强行生成了RDB,那么下次主数据库启动的时候,可能会从RDB来恢复数据,这可能是旧的数据。

2:由于要生成RDB文件,如果硬盘性能不高的时候,会对性能造成一定影响。因此从2.8.18版本,引入了无硬盘复制选项:repl-diskless-sync n 哨兵(sentinel)

 

Redis提供了哨兵工具来实现监控Redis系统的运行情况,主要实现:

1:监控主从数据库运行是否正常

2:当主数据库出现故障时,自动将从数据库转换成为主数据库

3:使用Redis-sentinel,redis实例必须在非集群模式下运行

 

开启哨兵功能 建立一个sentinel.conf文件,里面设置要监控的主数据库的名字,形如: sentinel monitor 监控的主数据库的名字 127.0.0.1 6379 1

1 表示选举主数据库的最低票数

(1)这个文件的内容,在运行期间会被sentinel动态进行更改

(2)可以同时监控多个主数据库,一行一个配置即可

 

Redis的集群 

复制的问题

由于复制中,每个数据库都是拥有完整的数据,因此复制的总数据存储量,受限于内存最小的数据库节点,如果数据量过大,复制就无能为力了。

 

分片

分片(Partitioning)就是将你的数据拆分到多个Redis实例的过程,这样每个 Redis实例将只包含完整数据的一部分。常见的分片方式:

1:按照范围分片

2:哈希分片,比如一致性哈希

 

常见的分片实现:

1:在客户端进行分片

2:通过代理来进行分片,比如:Twemproxy

3:查询路由:就是发送查询到一个随机实例,这个实例会保证转发你的查询到正确的节点,Redis集群在客户端的帮助下,实现了查询路由的一种混合形式,请求不是直接从Redis实例转发到另一个,而是客户端收到重定向到正确的节点

4:在服务器端进行分片, Redis采用哈希槽(hash slot)的方式在服务器端进行分片: Redis集群有16384个哈希槽,使用键的CRC16编码对16384取模来计算一个键所属的哈希槽

 

Redis分片的缺点

1:不支持涉及多键的操作,如mget,如果所操作的键都在同一个节点,就正常执行,否则会提示错误

2:分片的粒度是键,因此每个键对应的值不要太大

3:数据备份会比较麻烦,备份数据时你需要聚合多个实例和主机的持久化文件

4:扩容的处理比较麻烦

5:故障恢复的处理会比较麻烦,可能需要重新梳理Master和Slave的关系,并调整每个复制集里面的数据

 

集群

由于数据量过大,单个复制集难以承担,因此需要对多个复制集进行集群,形成水平扩展,每个复制集只负责存储整个数据集的一部分,这就是Redis的集群。

1:在以前版本中,Redis的集群是依靠客户端分片来完成,但是这会有很多缺点,比如维护成本高,需要客户端编码解决;增加、移出节点都比较繁琐等

2:Redis3.0新增的一大特性就是支持集群,在不降低性能的情况下,还提供了网络分区后的可访问性和支持对主数据库故障的恢复。

3:使用集群后,都只能使用默认的0号数据库 4:每个Redis集群节点需要两个TCP连接打开,正常的TCP端口用来服务客户端,例如6379,加10000的端口用作数据端口,必须保证防火墙打开这两个端口

5:Redis集群不保证强一致性,这意味着在特定的条件下,Redis集群可能会丢掉一些被系统收到的写入请

求命令。

 

集群架构

 

1:所有的Redis节点彼此互联,内部使用二进制协议优化传输速度和带宽

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

3:客户端与Redis节点直连,不需要中间proxy层。客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可

4:集群把所有的物理节点映射到[0-16383]插槽上,集群负责维护:节点-插槽-值 的关系

 

集群操作基本命令

1:CLUSTER INFO:获取集群的信息

2:CLUSTER NODES:获取集群当前已知的所有节点,以及这些节点的相关信息

3:CLUSTER MEET <ip> <port>:将ip和port所指定的节点添加到集群当中

4:CLUSTER FORGET <node_id>:从集群中移除 node_id 指定的节点

5:CLUSTER REPLICATE <node_id>:将当前节点设置为 node_id 指定的节点的从节点

6:CLUSTER SAVECONFIG:将节点的配置文件保存到硬盘里面

7:CLUSTER ADDSLOTS <slot> [slot ...]:将一个或多个槽分配给当前节点

8:CLUSTER DELSLOTS <slot> [slot ...]:从当前节点移除一个或多个槽

9:CLUSTER FLUSHSLOTS:移除分配给当前节点的所有槽

10:CLUSTER SETSLOT <slot> NODE <node_id>:将槽分配给 node_id 指定的节点,如果槽已经分配给另一

个节点,那么先让另一个节点删除该槽>,然后再进行分配

11:CLUSTER SETSLOT <slot> MIGRATING <node_id>:将本节点的槽迁移到指定的节点中

12:CLUSTER SETSLOT <slot> IMPORTING <node_id>:从指定节点导入槽到本节点

13:CLUSTER SETSLOT <slot> STABLE:取消对槽的导入(import)或迁移(migrate)

14:CLUSTER KEYSLOT <key>:计算键 key 应该被放置在哪个槽

15:CLUSTER COUNTKEYSINSLOT <slot>:返回槽目前包含的键值对数量

16:CLUSTER GETKEYSINSLOT <slot> <count>:返回 count 个槽中的键

17:migrate 目的节点ip 目的节点port 键名 数据库号码 超时时间 [copy] [replace]:迁移某个键值对

 

手工创建集群

1:首先进行集群配置

只需要将每个数据库的cluster-enabled配置选项打开,然后再修改如下内 容:pidfile、port、logfile、dbfilename、cluster-config-file

2:分别启动这些Redis数据库,可以用info cluster查看信息

3:连接节点,使用cluster meet,把所有的数据库都放到一个集群中来

4:可以通过cluster info ,或者cluster nodes 查看信息

5:设置部分数据库为slave,使用cluster replicate

6:然后就该来分配插槽了,使用cluster addSlots,这个命令目前只能一个一个加,如果要加区间的话,就得客户端编写代码来循环添加。 有个实用的技巧:把所有的Redis停下来,然后直接修改node的配置文件,

只需要配置master的数据库就可以,然后再重启数据库。 分配完插槽,可以使用cluster slots查看信息。

7:通过cluster info查看集群信息,如果显示ok,那就可以使用了

 

什么是插槽

插槽是Redis对Key进行分片的单元。在Redis的集群实现中,内置了数据自动分片机制,集群内部会将所有的key映射到16384个插槽中,集群中的每个数据库实例负责其中部分的插槽的读写。

 

键与插槽的关系

Redis会将key的有效部分,使用CRC16算法计算出散列值,然后对16384取余数,从 而把key分配到插槽中。键名的有效部分规则是:

1:如果键名包含{},那么有效部分就是{}中的值

2:否则就是取整个键名

 

移动已分配的插槽

这个稍微麻烦点,尤其是有了数据过后,假设要迁移123号插槽从A到B,

大致步骤如下:

1:在B上执行cluster setslot 123 importing A

2:在A上执行cluster setslot 123 migrating B

3:在A上执行cluster getkeysinslot 123 要返回的数量

4:对上一步获取的每个键执行migrate命令,将其从A迁移到B

5:在集群中每个服务器上执行cluster setslot 123 node B

 

避免在移动已分配插槽过程中,键的临时丢失 上面迁移方案中的前两步就是用来避免在移动已分配插槽过程中,键的临时丢失问题的,

大致思路如下:

1:当前两步执行完成后,如果客户端向A请求插槽123中的键时,如果键还未被转移,A将处理请求

2:如果键已经转移,则返回,把新的地址告诉客户端,客户端将发起新的请求以获取数据

 

获取插槽对应的节点

当客户端向某个数据库发起请求时,如果键不在这个数据库里面,将会返回一个move重定向的请求,里面包含新的地址,客户端收到这个信息后,需要重新发起请求到新的地址去获取数据。

当然,大部分的Redis客户端都会自动去重定向,也就是这个过程对开发人 员是透明的。redis-cli也支持自动重定向,只需要在启动时加入 -c 的参数。

 

故障判定

1:集群中每个节点都会定期向其他节点发出ping命令,如果没有收到回复,就认为该节点为疑似下线,然后在集群中传播该信息

2:当集群中的某个节点,收到半数以上认为某节点已下线的信息,就会真的标记该节点为已下线,并在集群中传播该信息

3:如果已下线的节点是master节点,那就意味着一部分插槽无法写入了

4:如果集群任意master挂掉,且当前master没有slave,集群进入fail状态

5:如果集群超过半数以上master挂掉,无论是否有slave,集群进入fail状态

6:当集群不可用时,所有对集群的操作做都不可用,收到CLUSTERDOWN The cluster is down错误信息

 

故障恢复 发现某个master下线后,集群会进行故障恢复操作,来将一个slave变成master,基于Raft算法,大致步骤如下:

1:某个slave向集群中每个节点发送请求,要求选举自己为master

2:如果收到请求的节点没有选举过其他slave,会同意

3:当集群中有超过节点数一半的节点同意该slave的请求,则该Slave选举成功

4:如果有多个slave同时参选,可能会出现没有任何slave当选的情况,将会等待一个随机时间,再次发出选举请求

5:选举成功后,slave会通过 slaveof no one命令把自己变成master

如果故障后还想集群继续工作,可设置cluster-require-full-coverage为no,默认yes

 

对于集群故障恢复的说明

1:master挂掉了,重启还可以加入集群,但挂掉的slave重启,如果对应的master变化了,是不能加入集群的,除非修改它们的配置文件,将其master指向新master

2:只要主从关系建立,就会触发主和该从采用save方式持久化数据,不论你是否禁止save

3:在集群中,如果默认主从关系的主挂了并立即重启,如果主没有做持久化,数据会完全丢失,从而从的数据也被清空

使用redis-trib.rb来操作集群 redis-trib.rb是Redis源码中提供的一个辅助工具,可以非常方便的来操作集群,它是用 ruby写的,因此需要在服务器上安装相应环境

1:安装Ruby

(1)下载ruby安装包,地址https://www.ruby-lang.org/en/downloads/

(2)然后分别configure、make、make install

(3)安装后通过ruby -v 查看一下版本,看是否正常

 

2:还需要安装rubygems

(1)下载包,地址https://rubygems.org/pages/download

(2)解压后进入解压文件夹,运行 ruby setup.rb

(3)安装后通过gem –v查看一下版本,看是否正常 3:还需要安装redis的ruby library

(1)由于连接国外源不太稳定,请先删除,如gem sources --remove

https://rubygems.org/ ,然后添加gem sources -a https://ruby.taobao.org/

(2)可以通过gem sources -l 查看源

(3)运行gem install redis

 

4:使用redis-trib.rb来初始化集群,形如:

ruby redis-trib.rb create --replicas 1 127.0.0.1:6381

   127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384 127.0.0.1:6385
   127.0.0.1:6386

create表示要初始化集群,--replicas 1表示每个驻数据库拥有的从数据 库为1个

5:使用redis-trib.rb来迁移插槽,如下:

(1)执行ruby redis-trib.rb reshard ip:port ,这就告诉Redis要重新分片,ip:port可以是集群中任何一个节点

(2)然后按照提示去做就可以了

(3)这种方式不能指定要迁移的插槽号

 

Redis预分区 

介绍

为了实现在线动态扩容和数据分区,Redis的作者提出了预分区的方案,实际就是在同一台机器上部署多个Redis实例,当容量不够时将多个实例拆分到不同的机器上,这样就达到了扩容的效果。拆分过程如下:

1:在新机器上启动好对应端口的Redis实例

2:配置新端口为待迁移端口的从库

3:待复制完成,与主库完成同步后,切换所有客户端配置到新的从库的端口

4:配置从库为新的主库

5:移除老的端口实例

6:重复上述过程把要迁移的数据库转移到指定服务器上

以上拆分流程是Redis作者提出的一个平滑迁移的过程,不过该拆分方法还 是很依赖Redis本身的复制功能的,如果主库快照数据文件过大,这个复制的过 程也会很久,同时会给主库带来压力。

 

Redis的安全 

简述 Redis在安全部分并没有做太多的工作,毕竟Redis是按照“Redis是运行在可信环境”这个假定来设计的。

 

安全相关的配置

1:bind:可以绑定允许访问数据库的地址,只能绑定一个地址

2:requirepass:设置数据库密码,如果设置了,那么客户端每次连接Redis的时候,都需要传入密码,形如:auth 密码,然后才能执行命令。 如果是复制集,就需要配置masterauth参数为主数据库的密码

 

安全相关的命令

1:rename-command:命令重命名

 

Redis的管理 

常用的管理命令

1:slowlog get:获取慢日志,可以通过配置文件的slowlog-log-slower-than来设置时间限制,默认是10000微秒,slowlog-max-len来限制记录条数。

返回的记录包含四个部分:

(1)日志的id

(2)该命令执行的unix时间

(3)该命令消耗的时间,单位微秒

(4)命令和参数

2:monitor:监控Redis执行的所有命令,这个命令比较耗性能,建议仅用在开发调试阶段

常用的管理工具

1:phpRedisAdmin:地址https://github.com/ErikDubbelboer/phpRedisAdmin

2:rdbtools:地址https://github.com/sripathikrishnan/redis-rdb-tools ,这个是用 python写的,可以提供生成内存报告、 转储文件到JSON、使用标准的diff工具比较两个 dump文件等功能

3:Cacti:用来监控Redis服务的流量

 

适合使用Redis的场景 

缓存

取最新N个数据的操作,如:可以将最新的50条评论的ID放在List集合排行榜类的应用,取TOP N操作,前面操作以时间为权重,这个是以某个条件为权重,比如按顶的次数排序

 

计数器应用

存储关系:比如社交关系,比如Tag等

获取某段时间所有数据排重值,使用set,比如某段时间访问的用户ID,或者是

 

客户端IP

构建队列系统,List可以构建栈和队列,使用zset可以构建优先级队列 n 实时分析系统,比如:访问频率控制

模拟类似于HttpSession这种需要设定过期时间的功能Pub/Sub构建实时消息系统

记录日志

 

使用管道(Pipeline) Redis的底层通讯协议对管道提供了支持,通过管道,可以一次性发送多条命令给

Redis,在执行完后一次性将结果取回。 使用管道,可以减少客户端和Redis的通信次数,降低网络延时,从而提供性能。

Redis的管道功能在命令行中没有,但Redis是支持管道的,而且在各个语言版的client中

都有相应的实现。

 

精简键名和键值

合理设计存储的数据结构和数据关系,尽量减少数据冗余

尽量使用mset来赋值,比set效率高一个数量级;类似的还有lpush、zadd等都可以一次输

入多个指令

如果可能,尽量使用Lua脚本来辅助获取或操作数据 n 尽量使用hash结构来存储对象

将一个对象存储在hash类型中会占用更少的内存,并且可以更方便的存取整个对 象,省内存的原因是新建一个hash对象时开始是用zipmap来存储的。

 

使用hash结构时,应尽量保证每个key下面的<field, value>的数目不超过限制(默认值为 64),否则插入效率下降十分明显,同样,内存开销也会显著增加

 

配置使用ziplist以优化list 如果list的元素个数小于配置值list-max-ziplist-entries且元素值字符串的长度 小于配置值list-max-ziplist-value,则可以编码成ziplist类型存储,否则采用 Dict 来存储,Dict实际是Hash Table的一种实现。

 

配置使用intset以优化set

当set集合中的元素为整数且元素个数小于配置set-max-intset-entries值时,使用 intset数据结构存储,否则转化为Dict结构

 

配置使用ziplist以优化sorted set 当sorted set的元素个数及元素大小小于一定限制时,它是用ziplist来存储。这个限制的配置如下:zset-max-ziplist-entries、zset-max-ziplist-value n 配置使用zipmap以优化hash 当entry数量没有超过hash-max-ziplist-entries指定的限制,并且值的最大长度没 有超过hash-max-ziplist-value指定的限制时,会用zipmap来编码。 

 

注意:HashMap的优势就是查找和操作的时间复杂度都是O(1)的,而放弃Hash采用一 维存储则是O(n)的时间复杂度,如果成员数量很少,则影响不大,否则会严重影响性能, 所以要权衡好些个值的设置,在时间成本和空间成本上进行权衡。

 

一定要设置maxmemory 设置Redis使用的最大物理内存,也就是使用了这么多物理内存后就开始拒绝后续的写入请求,该参数能保护Redis不会因为使用了过多的物理内存而严重影响性能甚至崩溃。

 

对排序的优化

1:尽量让要排序的Key存放在一个Server上 如果采用客户端分片,那么具体决定哪个key存在哪个服务器上,是由 client端采用一定算法来决定的,因此可以通过只对key的部分进行hash。比 如:client如果发现key中包含{},那么只对key中{}包含的内容进行hash。

如果采用服务端分片,也可以通过控制key的有效部分,来让这些数据分配 到同一个插槽中。

2:尽量减少Sort的集合大小

如果要排序的集合非常大, 会消耗很长时间,Redis单线程的,长时间的排序操作会阻塞其它client的请求。解决办法是通过主从复制,将数据复制到多个 slave上,然后只在slave上做排序操作,并尽可能的对排序结果缓存。

 

考虑采用复制+RDB的方式 使用复制机制来实现高可用,数据采用RDB的方式进行持久化备份,建议只在Slave上持久化RDB文件,而且只要在一个相对较长的时间备份一次就够了,比 如只保留save 900 1这条规则,大致就是15分钟保存一次。 这样的方式避免了AOF带来的持续的IO,也避免AOF Rewrite最后将rewrite 过程中产生的新数据写到新文件所造成的阻塞。代价是如果Master/Slave同时倒 掉,可能会丢失15分钟的数据。

 

考虑在一台服务器启动多个Redis实例 由于Redis使用单线程,为了提高CPU利用率,可以在同一台服务器上启动多个Redis实例,但这可能会带来严重的IO争用,除非Redis不需要持久化,或者 有某种方式保证多个实例不会在同一个时间重写AOF。

 

Redis的Java客户端

Redis官方推荐的Java客户端是jedis 网址:https://github.com/xetorthio/jedis

构建开发环境,在Maven中添加

<dependency>

<groupId>redis.clients</groupId>

<artifactId>jedis</artifactId>

<version>2.7.2</version>

</dependency>

连接池

1:jedis的连接池基于apach的commons-pool,要确保添加了相应的包

2:配置连接池,一般使用JedisPoolConfig,常见的设置:

(1)maxTotal:最大实例数,-1表示不限制,默认8

(2)maxIdle/minIdle:最大/小空闲实例数,默认8/0

(3)whenExhaustedAction:当池中的实例被分配完时,要采取的操作,默认有三种:

WHEN_EXHAUSTED_FAIL:直接抛出NoSuchElementException WHEN_EXHAUSTED_BLOCK:阻塞住,达到maxWaitMillis时抛出例外,默认选项 WHEN_EXHAUSTED_GROW:新建一个实例,也就说设置的maxTotal无用

(4)maxWaitMillis:获取一个实例时,最大的等待毫秒数,如果超时抛出JedisConnectionException,默 认-1,表示永远等待

(5)testOnBorrow:在获取实例时,是否验证对象有效,如果无效,会重新选择一个,默认false

(6)testOnReturn:在归还连接给池时,是否验证对象有效性,默认false

(7)testWhileIdle:是否对空闲实例验证对象有效性,失效的对象会被删除,默认false,仅在 timeBetweenEvictionRunsMillis设置为正值时有效

(8)timeBetweenEvictionRunsMillis:空闲实例验证,两次扫描之间要sleep的毫秒数;默认是-1

(9)numTestsPerEvictionRun:空闲实例验证,每次扫描的最多的对象数,默认是3,仅在 timeBetweenEvictionRunsMillis设置为正值时有效

(10)minEvictableIdleTimeMillis:一个实例至少停留在idle状态的最短时间,然后才能被空闲实例验证扫描并驱逐;默认30分钟,仅在timeBetweenEvictionRunsMillis设置为正值时有效

(11)lifo:设置采用last in first out队列,默认true

 

连接集群 以前的老版本Redis不支持集群的功能,因此是在客户端采用一致性Hash来对数据进行分片,jedis中对应的是SharedJedis;既然现在Redis已经支持集群了,

就先看新的集群的写法:

Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>(); //Jedis Cluster will attempt to discover cluster nodes automatically jedisClusterNodes.add(new HostAndPort("127.0.0.1", 7379)); JedisCluster jc = new JedisCluster(jedisClusterNodes);

jc.set("foo", "bar");

String value = jc.get("foo");

 

客户端分片的方式

1:定义一个List,里面包含多个JedisShardInfo

2:创建ShardedJedis对象,然后就可以通过这个对象操作命令了,操作完后可以disconnect

3:可以通过getShardInfo(key)方法来获取使用的分片信息

4:可以通过设置key tag pattern来保证key 位于同一个shard

5:分片的连接池对象是:ShardJedisPool,配置对象仍然是JedisPoolConfig,例如:

ShardJedisPool pool =new ShardedJedisPool(jedisPoolConfig, jedsInfoList, Hashing.MURMUR_HASH,Sharded.DEFAULT_KEY_TAG_PATTERN);

 

Redis和Spring集成 

构建开发环境,在Maven中添加

spring-data-redis支持的jedis版本目前只是到了2.7.0,所以要修改一下前面的配置,然

后添加:

<dependency>

<groupId>org.springframework.data</groupId>

<artifactId>spring-data-redis</artifactId>

<version>1.5.1.RELEASE</version>

</dependency>
<dependency>

<groupId>net.sourceforge.cobertura</groupId>

<artifactId>cobertura</artifactId>

<version>2.1.1</version>

</dependency>

<dependency>

<groupId>org.apache.commons</groupId>

<artifactId>commons-pool2</artifactId>

<version>2.4</version>

</dependency>

在Spring的配置文件中添加

<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">

<property name="maxTotal" value="8"></property> <property name="maxIdle" value="8"></property> <property name="maxWaitMillis" value="1000"></property>

</bean>

<bean id="jedisConnectionFactory"

class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <property name="hostName" value="192.168.1.106" />

<property name="port" value="6379" />

<property name="usePool" value="true" />

<property name="timeout" value="100000" />

<constructor-arg index="0" ref="poolConfig" /> </bean>

<bean id="testClient" class="com.javass.TestClient">

<property name="connectionFactory" ref="jedisConnectionFactory"></property>

</bean>

 

在Java程序中,就可以使用RedisTemplate了,

例如:

String s = ""+this.execute(new RedisCallback(){

public Object doInRedis(RedisConnection jr) throws DataAccessException { return new String(jr.get("k1".getBytes()));

}});

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值