一,redis的了解
Redis 是一个开源软件拥有( Berkly Software Distribution 许可 ),它是一个 内存数据结构存贮,通常被用于 数据库 , 缓存 , 消息代理。 。 它支持: 字符串 , 哈希 , 列表 , 集
合 , 数组集合 , 位图 , 高压缩算法以及地图索引等数据结构。Redis 支持集群,lua 脚本,以及 LRU(近期最少使用 Least Recently Used )淘汰算法,事物以及不同级别的 磁盘
持久化,能够提供一个高可用的 Redis Sentinel 的集群方案。从这段简介中我们应该掌握一下几点:
1. Redis 是把数据存放在内存当中,所以它的运行速度会非常快
2. Redis 具有多种数据存储结构
3. Redis 具有持久化的功能
4. Redis 上的数据可以设置过期
5. Redis 支持集群,而且可以自动切换
6. 跨平台 支持多种语言客户端
Redis 用途:
缓存(StackOverFlow),数据库(微博),消息中间件(队列,微博)
二,redis的安装
1,通过 xshell 建立连接,下载 redis 并执行解压
wget http://download.redis.io/releases/redis-3.2.8.tar.gz
2,解压的命令 :tar -zxvf redis-3.2.8.tar.gz
3,编译安装,解压之后进入redis-3.2.8的目录,在进入src目录,然后make.注意:执行 e make 命令前 如果没有gcc,安装会报错
三,启动服务
进入src目录执行./redis-server &
启动成功的界面如下:
四,redis的基本命令
exists key 检测指定 key 是否存在,返回 1 表示存在, 0 不存在
del key1 key2 ...... keyN 删除给定 key,返回删除 key 的数目, 0 表示给定 key 都不存在
type key 返回给定 key 值的类型。 返回 none 表示 key 不存在,string 字符类型, list 链表类型 set 无序集合类型......
keys pattern 返回匹配指定模式的所有 key
randomkey 返回从当前数据库中随机选择的一个 key,如果当前数据库是空的,返回空串
rename oldkey newkey 重命名一个 key,如果 newkey 存在,将会被覆盖,返回1 表示成功,0 失败。可能是 oldkey 不存在或者和 newkey 相同。
renamenx oldkey newkey 同上,但是如果 newkey 存在返回失败。
expire key seconds 为 key 指定过期时间, 单位是秒。 返回 1 成功, 0 表示key 已经设置过过期时间或者不存在。
ttl key 返回设置过过期时间 key 的剩余过期秒数。 -1 表示 key 不存在或者未设置过期时间。
select db-index 通过索引选择数据库, 默认连接的数据库是 0,默认数据库数是16 个。 返回 1表示成功, 0 失败。
move key db-index 将 key 从当前数据库移动到指定数据库。返回 1 表示成功。0 表示 key不存在或者已经在指定数据库中。
五,五种基本数据类型
redis 提供五种数据类型: string,hash,list,set 及sorted set
String 类型
string 是最基本的类型,而且 string 类型是二进制安全的。意思是 redis 的string 可以包含任何数据。比如 jpg 图片或者序列化的对象。从内部实现来看其实string 可以看作 byte 组,最大上限是 1G 字节。1G=1024MB
string 类型数据操作指令简介:
set key value 设置 key 对应 string 类型的值, 返回 1 表示成功, 0 失败。
setnx key value 如果 key 不存在, 设置 key 对应 string 类型的值。 如果key 已经存在,返回 0。
get key 获取 key 对应的 string 值,如果 key 不存在返回 nil
getset key value 先获取 key 的值,再设置 key 的值。如果 key 不存在返回 nil。
mget key1 key2 ......keyN 一次获取多个 key 的值,如果对应 key 不存在,则对应返回 nil。
mset key1 value1 ......keyN valueN 一次设置多个 key 的值,成功返回 1表示所有的值都设置了,失败返回 0 表示没有任何值被设置。
msetnx key1 value1 ......keyN valueN 一次设置多个 key 的值,但是不会覆盖已经存在的 key
incr key 对 key 的值做++操作, 并返回新的值。 注意 incr 一个不是 int 的
value 会返回错误, incr 一个不存在的 key,则设置 key 值为 1。
decr key 对 key 的值做--操作, decr 一个不存在 key,则设置 key 值为-1。
incrby key integer 对 key 加上指定值 , key 不存在时候会设置 key,并认为原来的 value 是 0。
decrby key integer 对 key 减去指定值。decrby 完全是为了可读性,我们完全可以通过 incrby 一个负值来实现同样效果,反之一样
应用场景
String 是最常用的一种数据类型,普通的 key/value 存储都可以归为此类,value 其实不仅是 String,也可以是数字:比如想知道什么时候封锁一个 IP 地址(访问超过几次)。
INCRBY 命令让这些变得很容易,通过原子递增保持计数
Hash 类型
Hash 类型数据操作指令
hset key field value 设置 hash field 为指定值,如果 key 不存在,则创建
hget key field 获取指定的 hash field。
hmget key filed1....fieldN 获取全部指定的 hash filed。
hmset key filed1 value1 ......filedN valueN 同时设置hash的多个 field。
hincrby key field integer 将指定的 hash filed 加上指定值。成功返回 hash
filed 变更后的值。
hexists key field 检测指定 field 是否存在。
hdel key field 删除指定的 hash field。
hlen key 返回指定 hash 的 field 数量
hkeys key 返回 hash 的所有 field。
hvals key 返回 hash 的所有 value。
hgetall key 返回 hash 的所有 filed 和 value。
List类型
lpush key string 在 key 对应 list 的头部添加字符串元素,返回 1 表示成功, 0表示 key 存在且不是 list 类型。
rpush key string 在 key 对应 list 的尾部添加字符串元素。
llen key 返回 key 对应 list 的长度, 如果 key 不存在返回 0, 如果 key 对应类型不是 list 返回错误。
lrange key start end 返回指定区间内的元素, 下标从 0 开始, 负值表示从后面计算, -1 表示倒数第一个元素 , key 不存在返回空列表。
ltrim key start end 截取 list 指定区间内元素,成功返回 1, key 不存在返回错误。
lset key indexvalue 设置 list 中指定下标的元素值,成功返回 1, key 或者下标不存在返回错误。
lrem key count value 从 List 的头部 ( count 正数)或尾部 ( count 负数)删除一定数量 ( count)匹配 value 的元素,返回删除的元素数量。 count 为 0时候删除全部。
lpop key 从 list 的头部删除并返回删除元素。如果 key 对应 list 不存在或者是空返回 nil,如果 key 对应值不是 list 返回错误。
rpop key 从 list 的尾部删除并返回删除元素。
blpop key1 ......keyN timeout 从左到右扫描,返回对第一个非空 list 进行
lpop 操作并返回,比如 blpop list1 list2 list3 0 ,如果 list 不存在list2,list3 都是非空则对 list2 做 lpop 并返回从 list2 中删除的元素。如果所有的 list 都是空或不存在,则会阻塞 timeout 秒, timeout 为 0 表示一直阻塞。当阻塞时,如果有 client 对 key1...keyN 中的任意 key 进行 push 操作, 则第一在这个 key 上被阻塞的 client 会立即返回。 如果超时发生, 则返回 nil。有点像unix 的 select 或者 poll。
brpop 同 blpop,一个是从头部删除一个是从尾部删除
Set 类型
是无序集合,最大可以包含(2 的 32 次方-1)个元素。 set 的是通过 hashtable 实现的,所以添加, 删除, 查找的复杂度都是 O(1)。 hash table 会随着添加或者删除自动的调整大小。需要注意的是调整 hashtable 大小时候需要同步(获取写锁)会阻塞其他读写操作。可能不久后就会改用跳表( skip list)来实现。 跳表已经在 sortedsets 中使用了。关于 set 集合类型除了基本的添加删除操作, 其它有用的操作还包含集合的取并集(union), 交集(intersection),差集(difference)。通过这些操作可以很容易的实现 SNS 中的好友推荐和 blog 的 tag 功能
set 类型数据操作指令简介
sadd key member 添加一个 string 元素到 key 对应 set 集合中,成功返回 1,如果元素以及在集合中则返回 0, key 对应的 set 不存在则返回错误。
srem key member 从 key 对应 set 中移除指定元素,成功返回 1,如果 member在集合中不存在或者 key 不存在返回 0,如果 key 对应的不是 set 类型的值返回错误。
spop key 删除并返回 key 对应 set 中随机的一个元素,如果 set 是空或者 key不存在返回 nil。
srandmember key 同 spop,随机取 set 中的一个元素,但是不删除元素。
smove srckey dstkey member 从 srckey 对应 set 中移除 member 并添加到
dstkey 对应 set 中,整个操作是原子的。 成功返回 1,如果 member 在 srckey 中不存在返回 0, 如果 key 不是 set 类型返回错误。
Scard key 返回 set 的元素个数,如果 set 是空或者 key 不存在返回 0。
sismember key member 判断 member 是否在 set 中,存在返回 1, 0 表示不存在或者 key 不存在。
sinter key1 key2 …… keyN 返回所有给定 key 的交集。
sinterstore dstkey key1 ....... keyN 返回所有给定 key 的交集, 并保存交集存到 dstkey 下。
sunion key1 key2 ...... keyN 返回所有给定 key 的并集。
sunionstore dstkey key1 ......keyN 返回所有给定 key 的并集, 并保存并集到 dstkey 下。
sdiff key1 key2 ......keyN 返回所有给定 key 的差集。
sdiffstore dstkey key1 ......keyN 返回所有给定 key 的差集,并保存差集到 dstkey 下。
smembers key 返回 key 对应 set 的所有元素,结果是无序的。
Sorted Set 类型
Sorted Set 是有序集合, 它在 set 的基础上增加了一个顺序属性,这一属性在添加修改元素的时候可以指定, 每次指定后, 会自动重新按新的值调整顺序。 可以理解了有两列的 mysql 表,一列存 value,一列存顺序。操作中 key 理解为sorted set 的名字,最多包含 2^32-1 个元素
Sorted t Set 类型数据操作指令简介
zadd key score member 添加元素到集合,元素在集合中存在则更新对应 score。
zrem key member 删除指定元素, 1 表示成功,如果元素不存在返回 0。
zincrby key incrmember 增加对应 member 的 score 值, 然后移动元素并保持 skip list 保持有序。返回更新后的 score 值。
zrank key member 返回指定元素在集合中的排名(下标), 集合中元素是按 score从小到大排序的。
zrevrankkey member 同上,但是集合中元素是按 score 从大到小排序。
zrange key start end 类似 lrange 操作从集合中去指定区间的元素。返回的是有序结果
zrevrange key start end 同上,返回结果是按 score 逆序的。
zrangebyscore key min max 返回集合中 score 在给定区间的元素。
zcount key min max 返回集合中 score 在给定区间的数量。
zcard key 返回集合中元素个数。
zscore key element 返回给定元素对应的 score
应用场景
以某个条件为权重,比如按顶的次数排序.ZREVRANGE 命令可以用来按照得分来获取前 100 名的用户,ZRANK 可以用来获取用
户排名,非常直接而且操作容易。
Redis sorted set 的使用场景与 set 类似,区别是 set 不是自动有序的,而 sortedset 可以通过用户额外提供一个优先级(score)的参数来为成员排序,并且是插入有序的,
即自动排序。比如:twitter 的 public timeline 可以以发表时间作为 score 来存储,这样获取时就是自动按时间排好序的。
比如:全班同学成绩的 SortedSets,value 可以是同学的学号,而 score 就可以是其考试得分,这样数据插入集合的,就已经进行了天然的排序。
比如网易云音乐排行榜实现;另外还可以用 Sorted Sets 来做带权重的队列,比如普通消息的 score 为 1,重要消息的 score 为 2,然后工作线程可以选择按 score 的倒序来获取工作任务。让重要的任务优先执行
需要精准设定过期时间的应用
比如你可以把上面说到的 sorted set 的 score 值设置成过期时间的时间戳,那么就可以简单地通过过期时间排序,定时清除过期数据了,不仅是清除 Redis 中的过期数据,你完全可以把 Redis 里这个过期时间当成是对数据库中数据的索引,用 Redis 来找出哪些数据需要过期删除,然后再精准地从数据库中删除相应的记录
Redis 搭建主从复用- - 读写分离
Redis 支持主从复用。数据可以从主服务器向任意数量的从服务器上同步,同步使用的是发布/订阅机制。Mater Slave 的模式,从 Slave 向 Master 发起 SYNC 命令。可以是 1 台Master 多 Slave,可以分层,Slave 下可以再接 Slave,可扩展成树状结构。因为没有两台电脑,所以只能在一台机器上搭建两个 Redis 服务端。这里使用单机来模拟 redis 主从服务器 ,实现读写分离配置
在 home 目录文件夹并拷贝两份 redis 服务器文件到该目录下,命名如下
修改主服务器的配置
1、slave-read-only yes 从服务器默认是只读的不允许输入,主服务器的端口号是6379
修改从服务器的配置
1,修改从服务器配置,从服务器的端口号为6380
slaveof 127.0.0.1 6379 这个只能配置在从服务器中,当主从配置中出现都是从服务器和都是主服务器的时候一定是这个地方出现问题了,将从服务器的这行命令打开或者主服务器上的这个命令要注释掉就可以了.
然后分别分启动主服务器和从服务器
主服务器的启动
从服务器的启动
Redis 主备切换服务器端配置
1.redis 节点准备(单台服务器不同端口模拟 2 2 台服务器配置)
127.0.0.1 6379(master-主节点)
127.0.0.1 6380(slave-从节点)
主节点的redis.config的配置
设置端口 ,daemonize(启动后台进程),密码,连接主节点密码,requirepass 禁用 bind 等 基本配置
配置密码为 liuqingfeng
禁用bind服务
端口
后台进程开启
从节点的redis.config的配置
设置端口 ,daemonize,密码,连接主节点密码 禁用 bind 等 基本配置,slave of 属性设置等
禁用bind
设置端口
开启后台进程
默认的数据库个数为16(默认设置即可,不用修改);
配置从服务器
配置连接主服务器的密码
设置从服务器为只读
sentinel.conf 哨兵文件配置
设置监控主服务器的名称,ip地址,端口号,以及
配置对应的主服务器的密码
redis的持久化
对于 Redis,其提供了不同级别的持久化操作:
1.RDB 持久化可以在指定的时间间隔内生成数据集的时间点快照
2.AOF 持久化记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集。AOF 文件中的命令全部以 Redis 协议的格式来保存,新命令会被追加到文件的末尾。Redis 还可以在后台对 AOF 文件进行重写(rewrite),使得 AOF文件的体积不会超出保存数据集状态所需的实际大小。
3. Redis 还可以同时使用 AOF 持久化和 RDB 持久化。在这种情况下,当 Redis 重启时,它会优先使用 AOF 文件来还原数据集,因为 AOF 文件保存的数据集通常比 RDB文件所保存的数据集更完整。
4.持久化功能当然也可以进行关闭操作,让数据仅在服务器运行时存在.
RDB 持久化操作(快照 SnapShot 方式)
在默认情况下, Redis 将数据库快照保存在名字为 dump.rdb 的二进制文件中。当然,这里可以通过修改 redis.conf 配置文件来对数据存储条件进行定义,规定在“ N 秒内数据集至少有 M 个改动”这一条件被满足时,自动保存一次数据集。也可以通过调用 save 或 bgsave ,手动让 Redis 进行数据集保存操作
Save |Bgsave 手动方式保存数据,通过 save 操作 ,当前 io 操作被阻塞,当 save 保存执行完毕才会进行后续 io 操作
save 操作执行成功后可以看到 dump.rdb 文件
bgsave 操作在背后开启一个新的进行来对数据进行快照处理
快照运行方式
当 Redis 需要保存 dump.rdb 文件时, 服务器执行以下操作:
1. Redis 调用 fork() ,同时拥有父进程和子进程。
2. 子进程将数据集写入到一个临时 RDB 文件中。
3. 当子进程完成对新 RDB 文件的写入时,Redis 用新 RDB 文件替换原来的 RDB 文件,并删除旧的 RDB 文件。
RDB 优缺点
优点:
1. RDB 是一个非常紧凑(compact)的文件,它保存了 Redis 在某个时间点上的数据集。该文件适合用于进行备份 。比如说,可以在最近的 24 小时内,每小时备份一次 RDB 文件,并且在每个月的每一天,也备份一个 RDB 文件。 这样的话,即使遇上问题,也可以随时将数据集还原到不同的版本。
2. RDB 非常适用于灾难恢复(disaster recovery):它只有一个文件,并且内容都非常紧凑,可以(在加密后)将它传送到别的数据中心
3. RDB 可以最大化 Redis 的性能:父进程在保存 RDB 文件时唯一要做的就是 fork 出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘 I/O操作。
4. RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。
缺点:
1. 如果想要做到数据实时备份级别,此时使用 rdb 快照进行备份可能会出现数据无法备份完整情况,比如在数据备份完毕下次备份操作发起前,服务器由于某种原因意外宕机,此时采用 rdb 就无法对当前情况做的实时响应处理
2. RDB 需要经常 fork 子进程来保存数据集到硬盘上,当数据集比较大的时候,fork 的过程是非常耗时的,可能会导致Redis在一些毫秒级内不能响应客户端的请求.如果数据集巨大并且CPU性能不是很好的情况下,这种情况会持续 1 秒,AOF 也需要 fork,但是你可以调节重写日志文件的频率来提高数据集的耐久度.
AOF 只追加操作的文件
RDB 需要经常 fork 子进程来保存数据集到硬盘上,当数据集比较大的时候,fork 的过程是非常耗时的,可能会导致Redis在一些毫秒级内不能响应客户端的请求.如果数据集巨大并且 CPU性能不是很好的情况下,这种情况会持续1 秒,AOF也需要fork,但是你可以调节重写日志文件的频率来提高数据集的耐久度.
appendonly yes
从现在开始, 每当 Redis 执行一个改变数据集的命令时(比如 SET), 这个命令就会被追加到 AOF 文件的末尾。这样的话, 当 Redis 重新启时, 程序就可以通过重新执行
AOF 文件中的命令来达到重建数据集的目的
日志重写
因为 AOF 的运作方式是不断地将命令追加到文件的末尾, 所以随着写入命令的不断增加,AOF 文件的体积也会变得越来越大。举个例子, 如果你对一个计数器调用了 100 次
INCR , 那么仅仅是为了保存这个计数器的当前值, AOF 文件就需要使用 100 条记录(entry)。然而在实际上, 只使用一条 SET 命令已经足以保存计数器的当前值了, 其
余 99 条记录实际上都是多余的
为了处理这种情况,Redis 支持一种有趣的特性:可以在不打断服务客户端的情况下,对AOF 文件进行重建(rebuild)。执行 BGREWRITEAOF 命令, Redis 将生成一个新的
AOF 文件, 这个文件包含重建当前数据集所需的最少命令。Redis 2.2 需要自己手动执行 BGREWRITEAOF 命令; Redis 2.4 则可以自动触发 AOF 重写。参考:
http://www.redis.cn/topics/persistence.html
AOF 重写文件配置:
使用 s Jedis 客户端工具操作
1,Redis 服务器配置文件修改,添加认证密码,外界进行访问时 通过密码来进行访问操作
2,ip 地址 的 bind 属性修改,注释掉,将 bind 127.0.0.1 属性禁用,(如果不禁用,仅限本机 ip 访问 redis 服务器) 能够让外界客户端进行访问
3. 关闭防火墙
service iptables stop
4. 重新启动 redis服务器
Java客户端代码的实现
1,创建普通的maven项目
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
</dependencies>
通过Junit进行单元测试
blic void test01() {
// 新建 redis 客户端连接对象
Jedis jedis=new Jedis("192.168.1.120", 6379);
// 设置认证密码
jedis.auth("123456");
// 通过 set 方法 添加字符串类型数据
jedis.set("shsxt", "实战化教学第一品牌!");
// 获取缓存数据并输出
System.out.println(jedis.get("shsxt"));
}
@Test
public void test02(){
// 初始化 redis 客户端连接词
JedisPool jedisPool=new JedisPool(new JedisPoolConfig(),
"192.168.2.180", 6379,10000, "123456");
// 从连接池获取连接
Jedis jedis=jedisPool.getResource();
jedis.set("redis", "redis is so easy");
System.out.println("redis:"+jedis.get("redis"));
}
封装 RedisUtil 对外提供连接对象获取方法
package com.shsxt.util; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; import java.sql.Time; /** * @author Created by lqf on 2018/10/26. */ public final class RedisUtil { //redis的服务器ip private static String ADDR="192.168.1.3"; //redis的端口号 private static Integer PORT=6379; //访问密码 private static String AUTH="liuqingfeng"; //设置最大的连接数 private static int MAX_ACTIVE=1024; //设置一个连接池中最大有多少个空闲的连接 private static int MAX_IDLE=200; //等待可用连接最大时间 private static int MAX_WAIT = 10000; private static int TIMEOUT=10000; //确认连接是否可用,为true,表示不用校验 private static boolean TEST_ON_BORROW = true; private static JedisPool jedisPool=null; //初始化redis的连接池 static{ try { JedisPoolConfig config=new JedisPoolConfig(); config.setMaxTotal(MAX_ACTIVE); config.setMaxIdle(MAX_IDLE); config.setMaxWaitMillis(MAX_WAIT); config.setTestOnBorrow(TEST_ON_BORROW); jedisPool=new JedisPool(config,ADDR,PORT, TIMEOUT,AUTH); }catch (Exception e){ e.printStackTrace(); } } public synchronized static Jedis getJedis(){ try{ if(jedisPool!=null){ Jedis resource =jedisPool.getResource(); return resource; }else{ return null; } }catch (Exception e){ e.printStackTrace(); return null; } } //释放资源 public static void returnResouce(final Jedis jedis){ if(jedis!=null){ jedisPool.close(); } } }
测试
import com.shsxt.util.RedisUtil; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.data.redis.core.BoundValueOperations; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ValueOperations; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import redis.clients.jedis.Jedis; import javax.annotation.Resource; import java.util.*; import java.util.concurrent.TimeUnit; /** * @author Created by lqf on 2018/10/26. */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:application-bak.xml"}) public class test02 { private Jedis jedis; @Before public void init(){ jedis= RedisUtil.getJedis(); } @Test public void test_redis(){ //set,get jedis.set("shsxt","实战化教学"); jedis.append("shsxt","第一品牌"); System.out.println(jedis.get("shsxt")); System.out.println("*******************************************"); //mset,mget jedis.mset("name","liuqingfeng","age","18","sex","man"); List<String> list=jedis.mget("name","age","sex"); if(list!=null || list.size()>0){ for(String str:list){ System.out.println(str); } } System.out.println("*******************************************"); //incr, incyBy System.out.println(jedis.get("age")+"before"); System.out.println(jedis.incr("age")+"incr"+"after"); jedis.incrBy("age",20); System.out.println(jedis.get("age")); System.out.println("*******************************************"); } @Test public void test02(){ Map<String,String> map=new HashMap<String,String>(); map.put("id","1"); map.put("username","柳庆峰"); map.put("addr","上海尚学堂"); map.put("age","18"); System.out.println("结果"+jedis.hmset("user1",map)); System.out.println("结果"+jedis.hget("user1","username")); // System.out.println("删除"+jedis.del("user1","age")); System.out.println(jedis.hexists("user1","age")); //返回的是一个set集合,可以用迭代器 Set<String> set= jedis.hkeys("user1"); Iterator<String> iterator =set.iterator(); while(iterator.hasNext()){ System.out.println("***"); String key=iterator.next(); System.out.println("key:"+key+" value:"+jedis.hget("user1",key)); } RedisUtil.returnResouce(jedis); } /* list 操作 * */ @Test public void test03(){ jedis.del("java"); jedis.lpush("java","java se"); jedis.lpush("java","java me"); jedis.lpush("java","java ee"); System.out.println(jedis.lrange("java",0,-1)); RedisUtil.returnResouce(jedis); } //set操作 @Test public void test04(){ jedis.sadd("user","老刘"); jedis.sadd("user","老六"); jedis.sadd("user","老牛"); System.out.println(jedis.smembers("user")); //判断一个集合中是否存在某个值 System.out.println(jedis.sismember("user", "老六")); //从set中随机抽取一个元素,不会删除 System.out.println(jedis.srandmember("user")); //删除并返回一个元素 System.out.println(jedis.spop("user")); System.out.println(jedis.smembers("user")); //返回set中元素的个数 System.out.println(jedis.scard("user")); RedisUtil.returnResouce(jedis); } @Test public void test05(){ jedis.zadd("百家姓",100,"赵"); jedis.zadd("百家姓",90,"钱"); jedis.zadd("百家姓",80,"孙"); jedis.zadd("百家姓",70,"李"); System.out.println(jedis.zrange("百家姓",0,-1)); System.out.println(jedis.zrevrange("百家姓",0,-1)); System.out.println(jedis.zrangeByScore("百家姓", 70, 90)); } @Resource private RedisTemplate<String, Object> template; @Test public void test06() { ValueOperations<String, Object> stringOperations= template.opsForValue(); stringOperations.set("str", "string 数据类型"); System.out.println(stringOperations.get("str")); } @Test //过期秒数的实现 public void test07(){ BoundValueOperations<String,Object> sbvo=template.boundValueOps("13689854565"); sbvo.append("123456"); System.out.println("验证码: "+sbvo.get()); sbvo.expire(20, TimeUnit.SECONDS); } }
Spring环境下配置读写分离
application的配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 连接池配置 --> <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <!-- 最大连接数 --> <property name="maxTotal" value="1024" /> <!-- 最大 空闲连接数 --> <property name="maxIdle" value="200" /> <!-- 获取连接时最大等待毫秒数 --> <property name="maxWaitMillis" value="10000" /> <!-- 在获取连接时检查有效性 --> <property name="testOnBorrow" value="true" /> </bean> <bean id="redisSentinelConfiguration" class="org.springframework.data.redis.connection.RedisSentinelConfiguration"> <property name="master"> <bean class="org.springframework.data.redis.connection.RedisNode"> <property name="name" value="mymaster"></property> </bean> </property> <property name="sentinels"> <set> <bean class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="192.168.1.3"></constructor-arg> <constructor-arg name="port" value="26379"></constructor-arg> </bean> <bean class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="192.168.1.3"></constructor-arg> <constructor-arg name="port" value="26380"></constructor-arg> </bean> </set> </property> </bean> <!-- 客户端连接工厂 --> <bean id="jedisConnFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <!-- 连接池引用 --> <constructor-arg name="poolConfig" ref="jedisPoolConfig" /> <constructor-arg name="sentinelConfig" ref="redisSentinelConfiguration"/> <property name="password" value="liuqingfeng"></property> </bean> <!-- redisTemplate 配置 --> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" p:connection-factory-ref="jedisConnFactory" > <!-- 配置序列化操作 --> <property name="keySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" /> </property> <property name="valueSerializer"> <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" /> </property> <property name="hashKeySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" /> </property> <property name="hashValueSerializer"> <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" /> </property> </bean> </beans>
test code
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:application.xml"}) public class TestSpringDataRedis { @Resource private RedisTemplate<String, String> redisTemplate; @Test public void test01() { ValueOperations valueOperations = redisTemplate.opsForValue(); valueOperations.set("redis02", "hello redis"); } }