Java客户端Jedis
这里只讲Jedis常规用法和五种数据结构的方法(关于集群的搭建以后再写)
2.稍微修饰下
3.运行效果
4.相应的jar包(第一个不兼容,没用,junit4.4:@test 做测试所需)
二,redis数据类型(String List Set Sorted Hash )方法介绍(方法参数类型如果每注明都是String)
1. Jedis jedis = new Jedis("192.168.0.163", 6379); //写自己的地址
2.JedisCluster jedis = new JedisCluster(jedisClusterNodes);//jedisClusterNodes是多个IP组成
redis的String类型数据结构的缓存操作:
/**
* 字符串缓存操作类或者JavaBean缓存操作类
* key String, value String-->看下边的注意点2
* key byte[], value byte[]-->key.getBytes[], value 序列化为byte[],通常需要自己写一个序列化工具
* 注意:这一点与memcached不一样,memcached可以key String, value Object
* 1、memcached直接加序列化器就可以,或者在业务层中将Object-->String
* 2、redis执行此接口,一般只会采用后者Object-->String
*/
String:
1. jedis.set(key,value);//set(String,String),value除了string以外,还可以是byte[]
/**
* 设置缓存
* 类似于memcached的set,不管是否已经有相同的key,都成功
* 实际上只是set(String, String)
*/
2.jedis.setex(key, value, expire);
/**
* 设置缓存,并指定缓存过期时间,单位是秒
*/
3.jedis.setnx(key, value);
/**
* 设置缓存,如果设置的key不存在,直接设置,如果key已经存在了,则什么操作都不做,直接返回
* 类似于memcached的add
*/
long setCount = jedis.setnx(keyPrefix+KEY_SPLIT+key, value);
4. jedis.get(key);
/**
* 根据key获取缓存
* @param key
* @return String
*/
5. jedis.del(key);
/**
* 根据key删除缓存
*/
6. jedis.expire(key, expire);
/**
* 更新缓存过期时间,单位:秒
* 从运行该方法开始,为相应的key-value设置缓存过期时间expire
* 类似于memcached中的touch命令
*/
redis的List类型数据结构的缓存操作:
List(有序列表工具类)
1. jedis.lpush(list, values);//可以多值(String list, String... values)
/**
* 从左边(首部)加入列表
* 注意:
* 1、可以一次性入队n个元素(这里使用了不定参数,当然可以换做数组)
* 2、左边入队,相当于在队头插入元素,则之后的元素都要后移一位;而右边入队的话元素直接插在队尾,之前的元素的索引不变
*/
2.
jedis.lpush(list, values);
jedis.expire(list, expire);//为该list设置缓存过期时间
/**
* 从左边(首部)加入列表
* 并指定列表缓存过期时间
*/
3. jedis.rpush(list, values);
/**
* 从右边(尾部)加入列表
*/
4.
jedis.rpush(list, values);
jedis.expire(list, expire);//设置缓存过期时间
/**
* 从右边(尾部)加入列表
* 并设置缓存过期时间
*/
5. jedis.lset(list, index, value);
/**
* 设置list中index位置的元素
* index==-1表示最后一个元素
*/
6.jedis.lpop(list);
/**
* 从左边(首部)出列表
*/
7.jedis.rpop(list);
/**
* 从右边出列表
*/
8.jedis.lindex(list, index);
/**
* 返回list中index位置的元素
*/
9.jedis.lrange(list, start, end);
/**
* 返回list指定区间[start,end]内的元素
*/
10. lrange(list, 0, -1);
/**
* 返回list内的全部元素
*/
11. jedis.ltrim(list, start, end);
/**
* 让list只保留指定区间[start,end]内的元素,不在指定区间内的元素都将被删除
*/
12. jedis.lrem(list, count, value);//返回删除了多少个元素
/**
* 删除list中所有与value相等的元素
* 注意:
* count
* ==0 :删除表中所有与value相等的元素
* >0:从表头开始向表尾搜索,移除count个与value相等的元素
* <0:从表尾开始向表头搜索,移除count个与value相等的元素
*/
13.lremove(list, 0, value);
/**
* 删除list中所有与value相等的元素
*/
14.jedis.llen(list);
/**
* 返回list中共有多少个元素
*/
set无序集合工具类
注意:
-
元素在set中的存放顺序为:与插入set的先后书顺序无关(即无序)
-
不允许存放重复元素
-
对于set而言,Jedis有交集、差集、并集运算,可是ShardJedis没有
1.jedis.sadd(set, values);
/*
* 对比:
* lpush(String key, String... strings);
* 返回push之后的list中包含的元素个数
*
* sadd(String key, String... members)
* 1:添加元素成功
* 0:set中已经有要添加的元素了
*/
2.jedis.smembers(set)
/**
* 获取set集合中的所有缓存
* @param set
*/
3. jedis.srem(set, values)
/**
* 删除缓存
* @param set
* @param values
*/
4.jedis.sismember(set, value);
/**
* set集合是否包含value
* @param set
*/
5.jedis.scard(set);
/**
* 返回set集合的元素个数
* @param set
*/
Sorted Set(有序集合工具类)
/**
* sorted set缓存操作类
* 1、有序集合,最后的顺序是按照score从小到大的顺序排列
* 2、元素不能重复
* 3、没有从set中获取指定value的运算
*/
1.jedis.zadd(String sortedSet,double score, String value);
/**
* 添加缓存(一个)
* @param sortedSet 添加入的集合
* @param score 权重
* @param value 值
*/
2.jedis.zadd(String sortedSet,Map<String, Double> value2score);
/**
* 添加缓存(一次可添加多个)
* @param sortedSet 添加入的集合
* @param value2score 加入集合的元素集
*/
/***************************获取缓存*****************************/
3.jedis.zrange(sortedSet,long start, long end);
/**
* 返回sortedSet内[start,end]索引的元素set
* 1、在sortedSet中,元素是按照score从小到大排列的,
* 此方法从前向后获取元素(即按元素的score从小到大排列)
*/
4.zrange(sortedSet, 0, -1);
/**
* 返回sortedSet内所有元素,元素按照score从小到大排列
*/
5.jedis.zrevrange(sortedSet,long start, long end);
/**
* 返回sortedSet集合[start, end]中的元素
* 1、此方法相当于从后向前取元素,即元素从大到小排列
* 或者相当于将sortedSet从大到小排列,然后从前向后去元素
*/
6.zrevrange(sortedSet, 0, -1);
/**
* 返回sortedSet内所有元素,元素按照score从大到小排列
*/
7.jedis.zrangeByScore(String sortedSet, double minScore, double maxScore);
/**
* 获取sortedSet内[minScore, maxScore]的元素
*/
8. jedis.zrem(String sortedSet, String... values);
/**
* 删除多个缓存
* @param sortedSet
* @param values
*/
9. jedis.zremrangeByRank(String sortedSet, long start, long end);
/**
* 删除指定范围(按照索引,包前包后)的缓存
*/
10. jedis.zremrangeByScore(String sortedSet, double minScore, double maxScore);
/**
* 删除指定范围(按照分数,包前包后)的缓存
*/
11.jedis.zcard(String sortedSet);
/**
* 获取集合sortedSet的长度
*/
12.edis.zscore(sortedSet, value);
/**
* 获取sortedSet中的value的权重score
*/
13. jedis.zincrby(String sortedSet,double score, String value);
/**
* 为sortedSet中的value的权重加上增量score
*/
Hash(hash工具类)
1.jedis.hset(String map, String key, String value);
/**
* 添加单个缓存key-value到map中
*/
2.jedis.hsetnx(String map, String key, String value);
/**
* 添加单个缓存key-value到map中
* 若已经存在于指定key相同的key,那么就不操作
*/
3. jedis.hmset(String map, Map<String, String> key2value);
/**
* 在map中添加key2value的map,即一次性添加多条缓存
* @param map
* @param key2value
*/
4.jedis.hkeys(String map);//返回类型Set<String>
/**
* 获取map中key的集合
* @param set
*/
5.jedis.hvals(String map)//返回类型List<String>
/**
* 获取map中的所有key的value
*/
6.jedis.hmget(String map, String... keys) //返回类型List<String>
/**
* 从map中获取多个key的value,并放在List集合中
*/
7.jedis.hgetAll(String map);//返回类型Map<String, String>
/**
* 从map中获取全部的缓存key-value对
*/
8.jedis.hget(String map, String key);// 返回类型String
/**
* 从map中获取相应key的缓存value
*/
9. jedis.hdel(String map, String... keys);
/**
* 从map中删除多个缓存
*/
10. jedis.hlen(map);
/**
* 获取map中的key-value数
*/
11.jedis.hexists(String map, String key);
/**
* map中是否存在键为key的缓存
*/
总结:
-
list
-
元素在list中的存放顺序为:插入list的顺序(从左边插入在头部,从右边插入在尾部)
-
允许存放重复元素
-
可用作模拟队列(queue)、堆栈(stack),支持双向操作(L--首部或者R--尾部)
-
左边入队,相当于在队头插入元素,则之后的元素都要后移一位;而右边入队的话元素直接插在队尾,之前的元素的索引不变(推荐使用右边入队,即队尾入队)
-
-
set
-
元素在set中的存放顺序为:与插入set的先后书顺序无关(即无序)
-
不允许存放重复元素
-
对于set而言,Jedis有交集、差集、并集运算,可是ShardJedis没有
-
-
soretd set
-
元素在set中的存放顺序为:根据score(权重)从小到大排列
-
不允许存放重复元素
-
相同点:
-
index
-
从0开始 -1表示结尾 -2表示倒数第二个
-
-
API中的 start end参数
-
都是包前也包后的
-
-
按key查找功能
-
list、set、sorted set没有按key查找的功能
-
String、hash具有按key查找value的功能
-
-
直接的指定缓存过期的API
-
String有
-
list、set、sorted set、hash没有,但是可以按例如如下的方式指定缓存过期时间
-
jedis.lpush(list, values);19
jedis.expire(list, expire);//为该list设置缓存过期时间
删除整个元素
-
jedis.del(list):可用于五种结构
package test;
import java.util.HashSet;
import java.util.Set;
import org.junit.Test;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPool;
public class RedisCesi {
@Test
public void testJedisSingle() {
System.err.println("start1");
//创建jedis对象
Jedis jedis = new Jedis("192.168.0.163", 6379);
//调用jedis对象的方法,方法名称和redis 的命令一致
//jedis.set("key1", "jedis songtie02");
// jedis.set("key07", "jedis songtie02");
// jedis.del("key07");
// String string = jedis.get("key07");
// Long list= jedis.lpush("list", "value1","value2","value4");
System.err.println( jedis.lindex("list", 0)+" "+ jedis.lindex("list", 1)+" "+jedis.lindex("list", 2)+" "+jedis.lindex("list", 3));
//System.err.println(jedis.rpop("list"));
//System.out.println("single "+string);
//关闭jedis
jedis.close();
}
/**
*使用jedis连接池
*/
@Test
public void testJedisPool(){
@SuppressWarnings("resource")
JedisPool jedisPool = new JedisPool("192.168.0.163", 6379);
//获得jedis 连接对象
Jedis jedis = jedisPool.getResource();
System.out.println("链接池 "+ jedis.lindex("list", 0)+" "+ jedis.lindex("list", 1)+" "+jedis.lindex("list", 2)+" "+jedis.lindex("list", 3));
jedis.close();
}
/**
* 集群连接测试
*/
@Test
public void testJedisCluster(){
Set<HostAndPort> nodes = new HashSet<>();
nodes.add(new HostAndPort("192.168.0.163", 6379));
nodes.add(new HostAndPort("192.168.0.164", 6379));
nodes.add(new HostAndPort("192.168.0.165", 6379));
nodes.add(new HostAndPort("192.168.0.163", 6380));
nodes.add(new HostAndPort("192.168.0.164", 6380));
nodes.add(new HostAndPort("192.168.0.165", 6380));
@SuppressWarnings("resource")
JedisCluster cluster = new JedisCluster(nodes );
cluster.set("key01", "1000");
System.out.println("集群 "+cluster.get("key01"));
System.out.println("key2 "+cluster.get("key02"));
System.out.println("key7 "+cluster.get("key07"));
}
}
单纯的集群代码:
package test;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.junit.Test;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
public class why123 {
private String serverInfo = "192.168.0.163:6379,192.168.0.163:6380,192.168.0.164:6379,192.168.0.164:6380,192.168.0.165:6379,192.168.0.165:6380";
private Set<HostAndPort> getClusterInfo(String serverInfo) {
Set<HostAndPort> set = new HashSet<HostAndPort>();
if(serverInfo==null||"".equals(serverInfo.length())) {
throw new RuntimeException("serverInfo 不能为空");
}
String ipPort[] = serverInfo.split(",");
int len = ipPort.length;
for(int i=0;i<len;i++) {
String server[] = ipPort[i].split(":");
System.out.println(server[0]+"-----------------"+server[1]);
set.add(new HostAndPort(server[0], Integer.parseInt(server[1])));
}
return set;
}
@SuppressWarnings("resource")
@Test
public void test() {
Set<HostAndPort> jedisClusterNodes = getClusterInfo(serverInfo);
// Jedis 集群尝试自动发现节点
JedisCluster jc = new JedisCluster(jedisClusterNodes);
System.err.println("----------------------------测试hash------------------------------");
System.err.println("---------插入--------");
//插入一条
jc.hset("aamap", "aa1", "aa11");
Map<String,String> maps = new HashMap<String, String>();
maps.put("aa2", "aa22");
maps.put("aa3", "aa33");
//插入多条
jc.hmset("aamap", maps);
//获取所有的key
System.out.println(jc.hkeys("aamap"));//[aa3, aa2, aa1]
//获取所有的value
System.out.println(jc.hvals("aamap"));//[aa33, aa22, aa11]
//从map中获取全部的缓存key-value对
System.out.println(jc.hgetAll("aamap"));//{aa3=aa33, aa2=aa22, aa1=aa11}
//从map中获取相应key的缓存value
System.out.println(jc.hget("aamap","aa2"));//aa22
//从map中获取多个key的value,并放在List集合中
System.out.println(jc.hmget("aamap","aa2","aa1"));//[aa22, aa11]
//获取map中的key-value数
System.out.println(jc.hlen("aamap"));//3
//map中是否存在键为key的缓存
System.out.println(jc.hexists("aamap","aa3"));//true
System.out.println(jc.hexists("aamap","aa0"));//false
// jc.hdel("aamap","aa0");
// jc.hdel("aamap","aa1");
// System.out.println(jc.hgetAll("aamap"));//{aa3=aa33, aa2=aa22}
}
}
redis整理来源开源中国:
二,Redis整理
1.redis是什么?
redis(remote dictionary server):是一个以key-value形式存储于内存中的数据库.提供了 String / List / Set / Sort Set /Hash 五种数据结构。服务器在断电之后,仍然可以恢复到断电之前的状态(另外的解释:集群是一个提供在多个Redis间节点间共享数据的程序集.)
2.redis特点?
线程模型:单线程-多路复用io模型
性能高:支持读 11万/秒 , 写 8万/秒
存储: 内存 ; RDB文件(二进制安全的真实数据) ; AOF文件(客户端的命令集合)
事务: 支持事务(每个客户端串行执行命令,其他客户端处于阻塞状态)
3.redis数据类型
String:动态字符串(每个key都是一个String)
编码方式:int / raw() /embstr
应用场景:普通的string场景
List:列表结构,有序可重复的结构。它拥有队列的特性。
编码方式:ziplist / linkedlist (如果数据量较小,且是数字或者字符串,则内部结构为 ziplist)
应用场景:普通的集合数据
Set:集合结构,不重复的集合结构。
编码方式:intset(整数集合) / hashtable
应用场景:普通的非重复集合数据;支持取交集、取并集等操作
Sort Set:有序集合结构,和Set比较起来,它是有序的。
编码方式:ziplist / skiplist
应用场景:有序不重复的集合数据
Hash:哈希结构,存储多个key:value的结构,此种结构可以存储对象 ; 如 HMSET user(key) username value1 password value2
编码方式:ziplist / hashtable
应用场景: 从关系型数据库去出一条数据,就可以让入到此种结构中
4.内存优化
redis提供内存回收策略,根据使用的情况可以选择适当的回收策略
redis提供内存共享策略,服务器启动时,会自动创建0-9999的数字对象,其他地方使用,可以直接引用。
本质:对内存的操作,其实是在每一个redis对象结构内都有一个count的属性,该属性记录了这个对象被引用的次数,如果为0,那么在内存回收时将回收该空间。
save参数调整:当满足条件时,触发SAVE命令,持久化到RDB文件
appendonly参数: 默认no ,若yes,则开启AOF文件持久化; BGREWRITEAOF 命令 持久化。其中appendsync参数调整具体的持久化策略,默认为每秒
5.事务
单线程处理所有客户端发来的请求,所以当有一个客户端在执行,其他客户端只能处于阻塞态。只有当前客户端请求完毕,其他客户端才能请求
6.主从复制
功能:数据备份,读写分离(测试环境,主服务器写,从服务器读)
步骤:在从服务端器执行: slaveof <masterip> <masterport> 即可维持关系;配置文件中也可以
特点:
1.master可以有多个slave
2.除了多个slave连到相同的master外,slave也可以连接其他slave形成图状结构
3.主从复制不会阻塞master。也就是说当一个或多个slave与master进行初次同步数据时,master可以继续处理client发来的请求。相反slave在初次同步数据时则会阻塞不能处理client的请求。
4.主从复制可以用来提高系统的可伸缩性,我们可以用多个slave 专门用于client的读请求,比如sort操作可以使用slave来处理。也可以用来做简单的数据冗余
5.可以在master禁用数据持久化,只需要注释掉master 配置文件中的所有save配置,然后只在slave上配置数据持久化。
6.主服务器可以关闭持久化功能(注释掉save参数)
7.sentinel(监测系统)
本质:是一个运行在特殊模式下的redis服务器。
功能:监控运行在多机上的主redis服务器,若有某一台主服务器出现故障,将自动把其他正常的从服务器切换为主服务器,代替出现故障主服务器的工作。
特点:
1.不发挥数据库的功能(所有对key以及数据类型操作的命令不能使用)
2.将会给监控的主服务器以及主服务器所属的从服务器发送命令,确认是否下线
3.会和监控同一个主服务器的其他sentinel服务器通信,作用是在共同判断所监控的主服务器的状态
4.根据多个sentinel判断的主服务器状态,来决定是否要进行主从切换,故障转移等
转移:sentinel监控的主服务器配置参数要在 sentinel.conf 文件中配置,启动时加载
8.集群
功能:将众多的key-value集合存在多个节点上,当某一个节点出现障碍,不影响整个集群的功能。
涉及到的关键词:
节点:一个端口的redis服务便是一个节点
槽指派(集群将整个系统分为16384个hash槽):这16384个槽位要全部分布在集群中的主节点上。
重新分片:若某个主节点故障了,将该主节点的槽位分配到其他可以用的主节点上。
上线/下线状态: 是否全部的槽位都分布在节点上。
特点:
1.如果某个节点要集群,必须要设置cluster-enabled yes
2.每个节点都有这16384个槽位所属的节点信息,如果值没有正确进入槽位,那么该节点会提示系统将信息放入正确槽位。重定向的过程会出现一个面向客户端隐藏的MOVED错误
3.集群在线状态也可以进行重新分片
4.集群中的主节点用户处理客户端命令,从节点用于复制主节点的数据,主节点下线时,从节点代替主节点的工作
//注意:目前官方提供的集群功能仍处于内测版本。
9.redis基准
redis自带的redis-benchmark 工具,支持各种参数进行性能测试
特点:
1.可以模拟多个客户端处理任意个请求
2.可以测试仅仅少数使用的命令等
注意:测试发现,linux环境下部署的redis服务器性能远高于windows下部署的redis服务器性能, 不在一个层级上面
10.关系数据库模型的转换
关系型数据库表结构:user表 (uid username password birthday )
在redis中可以这样存在:
1.主键: SET user:uid 1 、 GET user:1
2.其他字段:SET user:uid:username GET user:5:username ( 5 是通过参数值传进来的)
3.表数据也可以存在hash结构中: HMSET user:uid username value1 password value2 birthday value3
11.管道
功能:客户端一次可以传送多个命令到服务器,减少往返时延。大大提高性能。
12.优化
redis提供一些简单的内存优化策略,如过期数据清除,内存数据共享。