1.mavn依赖
<!-- 引入redis客户端依赖 --> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.4.2</version> </dependency>
2.redis数据格式
字符串(String)可以被编码为 raw (常规字符串) 或者int (用字符串表示64位无符号整数这种编码方式是为了节省空间).
列表类型(List)可以被编码为ziplist 或者 linkedlist. ziplist 是为了节省较小的列表空间而设计一种特殊编码方式.
集合(Set)被编码为 intset 或者 hashtable. intset 是为了存储数字的较小集合而设计的一种特殊编码方式.
哈希表(Hash)可以被编码为 zipmap 或者hashtable. zipmap 是专为了较小的哈希表而设计的一种特殊编码方式
有序集合(Sorted Set)被编码为ziplist 或者 skiplist 格式. ziplist可以表示较小的有序集合, skiplist 表示任意大小多的有序集合.
‘
4.String类型
String是简单的key-value类型,value其实不仅是String,也可以是数字。
实现方式:String在redis内部存储默认就是一个字符串,被redisObject所引用,当遇到incr,decr等操作时会转成数值型进行计算,此时redisObject的encoding字段为int。
jedis
jedis.set(key, value); //增加&修改
jedis.del(key) //删除
jedis.setex(key, expireSecond, value); //设置超期时间jedis.mset("key01","value01","key02","value02","key03","value03"));
jedis.mget("key01","key02","key03"));jedis.del(new String[]{"key01","key02"})
jedis.setnx("key1", "value1") //新增键值对防止覆盖原先值
jedis.getSet(key,newValue)// 设置为新value 但返回旧value//memcached和redis同样有append的操作,但是memcached有prepend的操作,redis中并没有。
jedis.append("key3", "End")jedis.incr("key1") //加1
jedis.decr("key2") //减1
jedis.incrBy("key1", n) //加n decrBy 减n
command命令
1)设置一个字符串值
语法:set key value
eg: set userId "12232"
(2)得到一个字符串的值
语法:get key
eg:get userId
(3)删除一个key
del key
eg:del userId
5.List
常用命令:lpush,rpush,lpop,rpop,lrange等。
实现方式:
Redis list的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销,Redis内部的很多实现,包括发送缓冲队列等也都是用的这个数据结构。
jedis
1). 右边入队:jedis.rpush("collections", "ArrayList", "Vector")
jedis.rpush("userList", "James");
2). 左边出队:右边出栈(rpop),即为对堆栈的操作 压栈 弹栈
jedis.lpop("userList");
3). 返回列表范围:从0开始,到最后一个(-1) [包含]
List<String> userList = jedis.lrange("userList", 0, -1);
Redis的TopN操作,即使用list完成:lrange
//获取collections下标为2的元素
jedis.lindex("collections", 2)
4). 删除:使用key jedis.del("userList");
//删除列表指定的值 ,第二个参数为删除的个数(有重复时),后add进去的值先被删,类似于出栈
jedis.lrem("collections", 2, "HashMap")
5). 设置:位置1处为新值----区别于入队
jedis.lset("userList", 1, "Nick Xu");
6). 返回长度:Long size = jedis.llen("userList");
7). 进行裁剪:包含 jedis.ltrim("userList", 1, 2);
command命令
edis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。是有顺序的,第一条插入的在最上面
(1)设置值
语法:lpush key value
eg:
lpush nosql redis
lpush nosql mongdb
lpush nosql mecache
(2)得到一个list
lrange key 开始数 结束数 (注意包含开始和结束)
eg:
lrange nosql 0,1 //获得2条数据 0,1
(3)删除一个hash值
del key
eg:
del nosql
6.set
Set是一堆不重复值,无序的组合。set 的内部实现是一个 value永远为null的HashMap,实际就是通过计算hash的方式来快速排重的,这也是set能提供判断一个成员是否在集合内的原因。
jedis
jedis.sadd("fruit", "pear", "watermelon"); 添加到set:可一次添加多个
Set<String> fruit = jedis.smembers("fruit"); 遍历集合
jedis.srem("fruit", "pear"); 移除元素:remove
jedis.scard("fruit"); 返回长度
jedis.sismember("fruit", "pear"); 是否包含jedis.smove("fruit", "food", "cookie") 将cookie从fruit移入food中
jedis.spop("fruit") //随机移除一个元素jedis.sadd("food", "bread", "milk");
//集合的交运算(sinter)、差集(sdiff)、并集(sunion)
Set<String> fruitFood = jedis.sunion("fruit", "food");
command
Redis 的 Set 是 string 类型的无序集合。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。
注意:增加要去重
(1)设置set值
语法:sadd key 值
eg:
sadd nosql redis
sadd nosql mecache
sadd nosql mongdb
sadd nosql mongdb
7.zset
有序集合在集合的基础上,增加了一个用于排序的参数,通过用户额外提供一个优先级(score)的参数来为成员排序。
Redis sorted set的内部使用HashMap和跳跃表(SkipList)来保证数据的存储和有序,HashMap里放的是成员到score的映射,而跳跃表里存放的是所有的成员,排序依据是HashMap里存的score,使用跳跃表的结构可以获得比较高的查找效率,并且在实现上比较简单。
jedis.zadd("user", 22, "James"); //第二个参数为score
jedis.zadd("user", 24, "James"); //更新score
Set<String> user = jedis.zrange("user", 0, -1); zset的范围:找到从0到-1的所有元素SortingParams sortingParameters = new SortingParams();
jedis.sort(key, sortingParameters.asc()) 按照指定方式对value排序
有序集合
Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
zset的成员是唯一的,但分数(score)却可以重复。
(1)设置zset值
语法:zadd key score value //sore是确定显示的顺序,值越小排到最前面
eg:
zadd home 0 jzk
zadd home 1 xhp
zadd home 2 jth
zadd home 1 jfy
(2)得到zsetz值
zrangebyscore key min_score max_score
获得值,score在给出的值内(包含)
zrange key 开始值 结束值
语法和set一致
(3)删除zset值
del key
eg:
del home
8.hash
在Memcached中,我们经常将一些结构化的信息打包成HashMap,在客户端序列化后存储为一个字符串的值,比如用户的昵称、年龄、性别、积分等,这时候在需要修改其中某一项时,通常需要将所有值取出反序列化后,修改某一项的值,再序列化存储回去。这样不仅增大了开销,也不适用于一些可能并发操作的场合(比如两个并发的操作都需要修改积分)。而Redis的Hash结构可以使你像在数据库中Update一个属性一样只修改某一项属性值。
Redis的Hash实际是内部存储的Value为一个HashMap,并提供了直接存取这个Map成员的接口。这样对数据的修改和存取都可以直接通过其内部Map的 Key(Redis里称内部Map的key为field), 也就是通过 key+ field就可以操作对应属性数据了,既不需要重复存储数据,也不会带来序列化和并发修改控制的问题。
需要注意的是,Redis提供了接口(hgetall)可以直接取到全部的属性数据,但是如果内部Map的成员很多,那么涉及到遍历整个内部 Map的操作,由于Redis单线程模型的缘故,这个遍历操作可能会比较耗时,而令其它客户端的请求完全不响应。
1). 存放数据:使用HashMap
Map<String, String> capital = new HashMap<String, String>();
capital.put("shannxi", "xi'an");
...
jedis.hmset("capital", capital);
jedis.hset("hash", "key5", "value5");
2 ) 获取数据
List<String> cities = jedis.hmget("capital", "shannxi", "shanghai");Map<String, String> map=jedis.hgetAll(String key)//所有键值对
jedis.hkeys("hash") 所有键
jedis.hvals("hash") 所有值
jedis.hincrBy("hash", "key6", 6) 将key6保存的值加上一个整数,如果key6不存在则添加key6
hdel("hash", "key2") 删除一个或者多个键值对
jedis.hlen("hash") 散列hash中键值对的个数
jedis.hexists("hash","key2") 判断hash中是否存在key2
Redis hash 是一个键值(key=>value)对集合。
Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。
(1)设置一个hash值
语法:HMSET key filed1 field1_value filed2 field2_value ...
eg:
hmset user id "1" userName "jiangzk" birth "1978-06-10"
(2)得到hash的一个属性值
语法:hget key filed
eg:
hget user userName //得到key user的一个字段userName的值
(3)删除一个hash值
del key
eg:
del user
9.redis中list set zset的区别
3.附工具类
package com.jyj.comm;
import redis.clients.jedis.Jedis;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @class: com.jyj.comm.RedisUtil
* @description:jredis操作的封装类
* @author: jiangzengkui
* @company: 教育家
* @create: 2021-01-19 16:55
*/
public class RedisUtil {
/****************************************字符串操作***********************/
/**
* 新增字符串key,无则新增,有则覆盖
* @param jedis
* @param key
* @param cont
*/
public static void str_add(Jedis jedis,String key,String cont){
jedis.set(key,cont);
}
/**
* 新增多个,
* @param jedis
* @param keysvalues "key1","kval1","key2","keyval2" ..
*/
public static void str_adds(Jedis jedis,String... keysvalues){
jedis.mset(keysvalues);
}
/**
* 得到一个内容,如果key不存在,则返回null
* @param jedis
* @param key
* @return
*/
public static String str_getByKey(Jedis jedis,String key){
return jedis.get(key);
}
/**
* 得到多个key值
* @param jedis
* @param keys eg: "k1","k2"
* @return
*/
public static List<String> str_getbyKeys(Jedis jedis, String... keys){
return jedis.mget(keys);
}
/****************************hash操作************************************/
/**
* 通过map写入
* @param jedis
* @param key
* @param map
*/
public static void hash_addByMap(Jedis jedis,String key,Map <String,String> map){
jedis.hmset(key,map);
}
/**
* 增加hash类型,一个字段一个字段的增加
* @param jedis
* @param key
* @param field
* @param val
*/
public static void hash_addFieldVal(Jedis jedis,String key,String field,String val){
jedis.hset(key, field,val);
}
/**
* 得到一个hash类型的所有字段值
* @param jedis
* @param key
* @return
*/
public static Map <String,String> hash_getAll(Jedis jedis,String key){
return jedis.hgetAll(key);
}
/**
* 通过传递字段获得值
* @param jedis
* @param key
* @param fields
* @return
*/
public static List<String> hash_getValByField(Jedis jedis,String key,String... fields){
return jedis.hmget(key, fields);
}
/**
* 移除hash的值
* @param jedis
* @param key
* @param fields
*/
public static void hash_removdVal(Jedis jedis,String key,String... fields){
jedis.hdel(key, fields); //删除一个或者多个键值对
}
/**
* 得到长度
* @param jedis
* @param key
* @return
*/
public static long hash_getLen(Jedis jedis,String key){
return jedis.hlen(key);
}
/**
* 字段是否存在
* @param jedis
* @param key
* @param filed
* @return
*/
public static boolean hash_fieldIsExist(Jedis jedis,String key,String filed){
return jedis.hexists(key,filed) ;//判断hash中是否存在key2
}
/****************************************整数加减的操作***********************/
/***注意:redis没有存储指定数字的方法,可以以字符串存储读出来再转化**/
/**
* 如果没有key,则创建,初始值为1,如果有,则在原值加1
* @param jedis
* @param key
*/
public static void incr(Jedis jedis,String key){
jedis.incr("key1");
}
/**
* 如果没有key,则创建,初始值为-1,如果有,则在原值减1
* @param jedis
* @param key
*/
public static void decr(Jedis jedis,String key){
jedis.decr(key) ;
}
/**
* 加减n
* @param jedis
* @param key
* @param n
*/
public static void incrBy(Jedis jedis,String key,int n){
jedis.incrBy(key,n) ;
}
/****************************list操作************************************/
/**
* 增加list数据类型,注意,不会去重
* @param jedis
* @param key
* @param values
*/
public static void list_add(Jedis jedis,String key,String... values){
jedis.lpush(key,values);
}
/**
* 得到所有list数据
* @param jedis
* @param key
* @return
*/
public static List<String> list_getAll(Jedis jedis,String key){
return jedis.lrange(key,0,-1) ;
}
/**
* 得到list
* @param jedis
* @param key
* @param start 开始索引
* @param end 结束索引 -1表示到最后一个索引
* @return
*/
public static List<String> list_getByIndex(Jedis jedis,String key,int start,int end){
List<String> list = jedis.lrange(key, start ,end);
return list;
}
/****************************set操作************************************/
/**
Set是一堆不重复值,无序的组合。set 的内部实现是一个 value永远为null的HashMap,实际就是通过计算hash的方式来快速排重的,这也是set能提供判断一个成员是否在集合内的原因。
*/
/**
* 新增set类型,会去重
* @param jedis
* @param key
* @param vals
*/
public static void set_add(Jedis jedis,String key,String... vals){
jedis.sadd(key,vals);
}
/**
* 删除set对应的值
* @param jedis
* @param key
* @param vals
*/
public static void set_remove(Jedis jedis,String key,String... vals){
jedis.srem(key,vals);
}
/**
* 得到set集合的值
* @param jedis
* @param key
* @return
*/
public Set<String> set_getAll(Jedis jedis,String key){
return jedis.smembers(key);
}
/**
* 得到set长度,不存在返回0
* @param jedis
* @param key
* @return
*/
public static Long set_getLen(Jedis jedis,String key){
return jedis.scard(key);
}
/**
* 值在set里是否存在
* @param jedis
* @param key
* @param val
* @return
*/
public static boolean set_isExist(Jedis jedis,String key,String val){
return jedis.sismember(key, val);
}
/****************************zset操作************************************/
/**
set是有序的排列,去重
*/
/**
* 新增一个zset成员 score是用来排序的
* @param jedis
* @param key
* @param score
* @param member
*/
public static void zset_add(Jedis jedis,String key,double score,String member){
jedis.zadd(key, score,member);
}
/**
* 新增多个zset
* @param jedis
* @param key
* @param map
*/
public static void zset_adds(Jedis jedis,String key,Map<String ,Double> map){
jedis.zadd(key,map);
}
/**
* 得到一个zset的集合
* @param jedis
* @param key
* @return
*/
public static Set<String> zset_getAll(Jedis jedis,String key){
return jedis.zrange(key, 0, -1);
}
/****************************通用操作************************************/
/**
* 删除一个key
* @param jedis
* @param key
*/
public static void comm_delKey(Jedis jedis,String key) {
if(jedis.exists(key)){
jedis.del(key);
System.out.println("删除成功,key="+key);
}
}
/**
* 设置过期时间
* @param jedis
* @param key
* @param seconds
*/
public static void comm_setExpireTime(Jedis jedis,String key,int seconds){
jedis.expire(key, seconds);
}
/**
* 删除多个key
* @param jedis
* @param keys eg:"k1","k2"
*/
public static void comm_delKeys(Jedis jedis,String... keys){
jedis.del(keys);
}
/**
* 删除所有key
* @param jedis
*/
public static void comm_delAll(Jedis jedis){
System.out.println("清空库中所有数据:"+jedis.flushDB());
}
/**
* 得到所有key
* @param jedis
* @return
*/
public static Set<String> comm_getAllKey(Jedis jedis){
// 获取数据并输出
Set<String> keys = jedis.keys("*");
return keys;
}
/**
* 链接jdis
* @return
*/
public static Jedis getJedis(){
//连接本地的 Redis 服务
Jedis jedis = new Jedis("localhost",6379,2000);
// jedis.auth("segns");//设置密码
System.out.println("连接成功");
return jedis;
}
}
8.连接池
单个连接开销太大,则用连接池进行处理
<!-- 引入redis客户端依赖 --> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.4.2</version> </dependency> <!--配合redis连接池用,好像不用也可以 --> <dependency> <groupId>commons-pool</groupId> <artifactId>commons-pool</artifactId> <version>1.5.4</version> </dependency>
连接池代码
package com.jyj.comm;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
/**
* @class: com.jyj.comm.RedisPoolUtil
* @description: 连接池的配置
* @author: jiangzengkui
* @company: 教育家
* @create: 2021-01-20 17:42
*/
public class RedisPoolUtil {
/**
* 配置这些可以写到配置文件里
*/
//Redis服务器IP
private static String ADDR = "127.0.0.1";
//Redis的端口号
private static int PORT = 6379;
//访问密码
private static String AUTH = "1234";
//可用连接实例的最大数目,默认值为8;
//如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。
private static int MAX_TOTAL = 8;
//最小空闲连接数, 默认0
private static int MIN_IDLE=0;
//控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。
//最大空闲连接数, 默认8个
private static int MAX_IDLE = 8;
//获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间, 默认-1
//等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException;
private static int MAX_WAIT = -1;
private static int TIMEOUT = 10000;
//连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true
private static boolean BLOCK_WHEN_EXHAUSTED = false;
//设置的逐出策略类名, 默认DefaultEvictionPolicy(当连接超过最大空闲时间,或连接数超过最大空闲连接数)
private static String EVICTION_POLICY_CLASSNAME="org.apache.commons.pool2.impl.DefaultEvictionPolicy";
//是否启用pool的jmx管理功能, 默认true
private static boolean JMX_ENABLED=true;
//MBean ObjectName = new ObjectName("org.apache.commons.pool2:type=GenericObjectPool,name=" + "pool" + i); 默认为"pool", JMX不熟,具体不知道是干啥的...默认就好.
private static String JMX_NAME_PREFIX="pool";
//是否启用后进先出, 默认true
private static boolean LIFO=true;
//逐出连接的最小空闲时间 默认1800000毫秒(30分钟)
private static long MIN_EVICTABLE_IDLE_TIME_MILLIS=1800000L;
//对象空闲多久后逐出, 当空闲时间>该值 且 空闲连接>最大空闲数 时直接逐出,不再根据MinEvictableIdleTimeMillis判断 (默认逐出策略)
private static long SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS=1800000L;
//每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3
private static int NUM_TESTS_PER_EVICYION_RUN=3;
//在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;
//在获取连接的时候检查有效性, 默认false
private static boolean TEST_ON_BORROW = false;
//在空闲时检查有效性, 默认false
private static boolean TEST_WHILEIDLE=false;
//逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
private static long TIME_BERWEEN_EVICTION_RUNS_MILLIS=-1;
private static JedisPool jedisPool = null;
/**
* 初始化Redis连接池
*/
static {
try {
JedisPoolConfig config = new JedisPoolConfig();
config.setBlockWhenExhausted(BLOCK_WHEN_EXHAUSTED);
config.setEvictionPolicyClassName(EVICTION_POLICY_CLASSNAME);
config.setJmxEnabled(JMX_ENABLED);
config.setJmxNamePrefix(JMX_NAME_PREFIX);
config.setLifo(LIFO);
config.setMaxIdle(MAX_IDLE);
config.setMaxTotal(MAX_TOTAL);
config.setMaxWaitMillis(MAX_WAIT);
config.setMinEvictableIdleTimeMillis(MIN_EVICTABLE_IDLE_TIME_MILLIS);
config.setMinIdle(MIN_IDLE);
config.setNumTestsPerEvictionRun(NUM_TESTS_PER_EVICYION_RUN);
config.setSoftMinEvictableIdleTimeMillis(SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS);
config.setTestOnBorrow(TEST_ON_BORROW);
config.setTestWhileIdle(TEST_WHILEIDLE);
config.setTimeBetweenEvictionRunsMillis(TIME_BERWEEN_EVICTION_RUNS_MILLIS);
jedisPool = new JedisPool(config, ADDR, PORT, TIMEOUT, AUTH);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取Jedis实例
* @return
*/
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;
}
}
/**
* 释放jedis资源
* @param jedis
*/
public static void close(final Jedis jedis) {
if (jedis != null) {
jedis.close();
}
}
}
代码地址