1. pom
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
2 String
/**
* Redis 字符串数据类型的相关命令用于操作 redis 字符串值
*/
public void operateString() {
Jedis jedis = new Jedis("localhost", 6379);
//如果返回 pang 代表链接成功
System.out.println("jedis.ping():" + jedis.ping());
//设置key0的值 123456
jedis.set("key0", "123456");
System.out.println("jedis.set(key0),123456");
//返回数据类型 string
System.out.println("jedis.type(key0): " + jedis.type("key0"));
//get key
System.out.println("jedis.get(key0): " + jedis.get("key0"));
// key是否存在
System.out.println("jedis.exists(key0):" + jedis.exists("key0"));
//返回key的长度
System.out.println("jedis.strlen(key0): " + jedis.strlen("key0"));
//返回截取字符串, 范围 0,-1 表示截取全部
System.out.println("jedis.getrange(key0): " + jedis.getrange("key0", 0, -1));
//返回截取字符串, 范围 1,4 表示从表示区间[1,4]
System.out.println("jedis.getrange(key0): " + jedis.getrange("key0", 1, 4));
//追加
System.out.println("jedis.append(key0): " + jedis.append("key0", "appendStr"));
System.out.println("jedis.get(key0): " + jedis.get("key0"));
//重命名
jedis.rename("key0", "key0_new");
//判断key 是否存在
System.out.println("jedis.exists(key0): " + jedis.exists("key0"));
//批量插入
jedis.mset("key1", "val1", "key2", "val2", "key3", "100");
//批量取出
System.out.println("jedis.mget(key1,key2,key3): " + jedis.mget("key1", "key2", "key3"));
//删除
System.out.println("jedis.del(key1): " + jedis.del("key1"));
System.out.println("jedis.exists(key1): " + jedis.exists("key1"));
//取出旧值 并set新值
System.out.println("jedis.getSet(key2): " + jedis.getSet("key2", "value3"));
//自增1 要求数值类型
System.out.println("jedis.incr(key3): " + jedis.incr("key3"));
//自增15 要求数值类型
System.out.println("jedis.incrBy(key3): " + jedis.incrBy("key3", 15));
//自减1 要求数值类型
System.out.println("jedis.decr(key3): " + jedis.decr("key3"));
//自减5 要求数值类型
System.out.println("jedis.decrBy(key3): " + jedis.decrBy("key3", 15));
//增加浮点类型
System.out.println("jedis.incrByFloat(key3): " + jedis.incrByFloat("key3", 1.1));
//返回0 只有在key不存在的时候才设置
System.out.println("jedis.setnx(key3): " + jedis.setnx("key3", "existVal"));
System.out.println("jedis.get(key3): " + jedis.get("key3"));// 3.1
//只有key都不存在的时候才设置,这里返回 null
System.out.println("jedis.msetnx(key2,key3): " + jedis.msetnx("key2", "exists1", "key3", "exists2"));
System.out.println("jedis.mget(key2,key3): " + jedis.mget("key2", "key3"));
//设置key 2 秒后失效
jedis.setex("key4", 2, "2 seconds is no Val");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 2 seconds is no Val
System.out.println("jedis.get(key4): " + jedis.get("key4"));
jedis.set("key6", "123456789");
//下标从0开始,从第三位开始,将新值覆盖旧值
jedis.setrange("key6", 3, "abcdefg");
//返回:123abcdefg
System.out.println("jedis.get(key6): " + jedis.get("key6"));
//返回所有匹配的key
System.out.println("jedis.get(key*): " + jedis.keys("key*"));
jedis.close();
}
结果:
jedis.ping():PONG
jedis.set(key0),123456
jedis.type(key0): string
jedis.get(key0): 123456
jedis.exists(key0):true
jedis.strlen(key0): 6
jedis.getrange(key0): 123456
jedis.getrange(key0): 2345
jedis.append(key0): 15
jedis.get(key0): 123456appendStr
jedis.exists(key0): false
jedis.mget(key1,key2,key3): [val1, val2, 100]
jedis.del(key1): 1
jedis.exists(key1): false
jedis.getSet(key2): val2
jedis.incr(key3): 101
jedis.incrBy(key3): 116
jedis.decr(key3): 115
jedis.decrBy(key3): 100
jedis.incrByFloat(key3): 101.1
jedis.setnx(key3): 0
jedis.get(key3): 101.09999999999999
jedis.msetnx(key2,key3): 0
jedis.mget(key2,key3): [value3, 101.09999999999999]
jedis.get(key4): null
jedis.get(key6): 123abcdefg
jedis.get(key*): [key:__rand_int__, key2, key0_new, key6, key3]
3. List
/**
* Redis列表是简单的字符串列表,按照插入顺序排序。
* 可以添加一个元素到列表的头部(左边)或者尾部(右边)
*/
public void operateList() {
Jedis jedis = new Jedis("localhost");
System.out.println("jedis.ping(): " + jedis.ping());
jedis.del("list1");
//从list尾部添加3个元素
jedis.rpush("list1", "zhangsan", "lisi", "wangwu");
//取得类型, list
System.out.println("jedis.type(): " + jedis.type("list1"));
//遍历区间[0,-1],取得全部的元素
System.out.println("jedis.lrange(0,-1): " + jedis.lrange("list1", 0, -1));
//遍历区间[1,2],取得区间的元素
System.out.println("jedis.lrange(1,2): " + jedis.lrange("list1", 1, 2));
//获取list长度
System.out.println("jedis.llen(list1): " + jedis.llen("list1"));
//获取下标为 1 的元素
System.out.println("jedis.lindex(list1,1): " + jedis.lindex("list1", 1));
//左侧弹出元素
System.out.println("jedis.lpop(): " + jedis.lpop("list1"));
//右侧弹出元素
System.out.println("jedis.rpop(): " + jedis.rpop("list1"));
//设置下标为0的元素val
jedis.lset("list1", 0, "lisi2");
//最后,遍历区间[0,-1],取得全部的元素
System.out.println("jedis.lrange(0,-1): " + jedis.lrange("list1", 0, -1));
jedis.close();
}
4. Set
/**
* Redis 的 Set 是 String 类型的无序集合。
* 集合成员是唯一的,这就意味着集合中不能出现重复的数据。
* Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。
* 集合中最大的成员数为 2^32 - 1 (4294967295, 每个集合可存储40多亿个成员)。
*/
public void operateSet() {
Jedis jedis = new Jedis("localhost");
jedis.del("set1");
System.out.println("jedis.ping(): " + jedis.ping());
System.out.println("jedis.type(): " + jedis.type("set1"));
//sadd函数: 向集合添加元素
jedis.sadd("set1", "user01", "user02", "user03");
//smembers函数: 遍历所有元素
System.out.println("jedis.smembers(): " + jedis.smembers("set1"));
//scard函数: 获取集合元素个数
System.out.println("jedis.scard(): " + jedis.scard("set1"));
//sismember 判断是否是集合元素
System.out.println("jedis.sismember(user04): " + jedis.sismember("set1", "user04"));
//srem函数:移除元素
System.out.println("jedis.srem(): " + jedis.srem("set1", "user02", "user01"));
//smembers函数: 遍历所有元素
System.out.println("jedis.smembers(): " + jedis.smembers("set1"));
jedis.close();
}
5. Hash
/**
* Redis hash 是一个string类型的field和value的映射表,
* hash特别适合用于存储对象。
* Redis 中每个 hash 可以存储 2^32 - 1 键值对(40多亿)
*/
public void operateHash() {
Jedis jedis = new Jedis("localhost");
jedis.del("config");
//设置hash的 field-value 对
jedis.hset("config", "ip", "127.0.0.1");
//取得hash的 field的关联的value值
System.out.println("jedis.hget(): " + jedis.hget("config", "ip"));
//取得类型:hash
System.out.println("jedis.type(): " + jedis.type("config"));
//批量添加 field-value 对,参数为java map
Map<String, String> configFields = new HashMap<String, String>();
configFields.put("port", "8080");
configFields.put("maxalive", "3600");
configFields.put("weight", "1.0");
//执行批量添加
jedis.hmset("config", configFields);
//批量获取:取得全部 field-value 对,返回 java map
System.out.println("jedis.hgetAll(): " + jedis.hgetAll("config"));
//批量获取:取得部分 field对应的value,返回 java map
System.out.println("jedis.hmget(): " + jedis.hmget("config", "ip", "port"));
//浮点数增加: 类似于String的 incrByFloat
jedis.hincrByFloat("config", "weight", 1.2);
System.out.println("jedis.hget(weight): " + jedis.hget("config", "weight"));
//获取所有的key
System.out.println("jedis.hkeys(config): " + jedis.hkeys("config"));
//获取所有的val
System.out.println("jedis.hvals(config): " + jedis.hvals("config"));
//获取长度
System.out.println("jedis.hlen(): " + jedis.hlen("config"));
//判断field是否存在
System.out.println("jedis.hexists(weight): " + jedis.hexists("config", "weight"));
//删除一个field
jedis.hdel("config", "weight");
System.out.println("jedis.hexists(weight): " + jedis.hexists("config", "weight"));
jedis.close();
}
6. Zet
/**
* Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。
* 不同的是每个元素都会关联一个double类型的分数。
* redis正是通过分数来为集合中的成员进行从小到大的排序。
* 有序集合的成员是唯一的,但分数(score)却可以重复。
* 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。
* 集合中最大的成员数为 2^32 - 1 (4294967295, 每个集合可存储40多亿个成员)。
*/
public void operateZset() {
Jedis jedis = new Jedis("localhost");
System.out.println("jedis.get(): " + jedis.ping());
jedis.del("salary");
Map<String, Double> members = new HashMap<String, Double>();
members.put("u01", 1000.0);
members.put("u02", 2000.0);
members.put("u03", 3000.0);
members.put("u04", 13000.0);
members.put("u05", 23000.0);
//批量添加元素
jedis.zadd("salary", members);
//类型,zset
System.out.println("jedis.type(): " + jedis.type("salary"));
//获取集合元素个数
System.out.println("jedis.zcard(): " + jedis.zcard("salary"));
//按照下标[起,止]遍历元素
System.out.println("jedis.zrange(): " + jedis.zrange("salary", 0, -1));
//按照下标[起,止]倒序遍历元素
System.out.println("jedis.zrevrange(): " + jedis.zrevrange("salary", 0, -1));
//按照分数(薪资)[起,止]遍历元素
System.out.println("jedis.zrangeByScore(): " + jedis.zrangeByScore("salary", 1000, 10000));
//按照薪资[起,止]遍历元素,带分数返回
Set<Tuple> res0 = jedis.zrangeByScoreWithScores("salary", 1000, 10000);
for (Tuple temp : res0) {
System.out.println("Tuple.get(): " + temp.getElement() + " -> " + temp.getScore());
}
//按照分数[起,止]倒序遍历元素
System.out.println("jedis.zrevrangeByScore(): " + jedis.zrevrangeByScore("salary", 1000, 4000));
//获取元素[起,止]分数区间的元素数量
System.out.println("jedis.zcount(): " + jedis.zcount("salary", 1000, 4000));
//获取元素score值:薪资
System.out.println("jedis.zscore(): " + jedis.zscore("salary", "u01"));
//获取元素下标
System.out.println("jedis.zrank(u01): " + jedis.zrank("salary", "u01"));
//倒序获取元素下标
System.out.println("jedis.zrevrank(u01): " + jedis.zrevrank("salary", "u01"));
//删除元素
System.out.println("jedis.zrem(): " + jedis.zrem("salary", "u01", "u02"));
//删除元素,通过下标范围
System.out.println("jedis.zremrangeByRank(): " + jedis.zremrangeByRank("salary", 0, 1));
//删除元素,通过分数范围
System.out.println("jedis.zremrangeByScore(): " + jedis.zremrangeByScore("salary", 20000, 30000));
//按照下标[起,止]遍历元素
System.out.println("jedis.zrange(): " + jedis.zrange("salary", 0, -1));
Map<String, Double> members2 = new HashMap<String, Double>();
members2.put("u11", 1136.0);
members2.put("u12", 2212.0);
members2.put("u13", 3324.0);
//批量添加元素
jedis.zadd("salary", members2);
//增加指定分数
System.out.println("jedis.zincrby(10000): " + jedis.zincrby("salary", 10000, "u13"));
//按照下标[起,止]遍历元素
System.out.println("jedis.zrange(): " + jedis.zrange("salary", 0, -1));
jedis.close();
}
jedis.get(): PONG
jedis.type(): zset
jedis.zcard(): 5
jedis.zrange(): [u01, u02, u03, u04, u05]
jedis.zrevrange(): [u05, u04, u03, u02, u01]
jedis.zrangeByScore(): [u01, u02, u03]
Tuple.get(): u01 -> 1000.0
Tuple.get(): u02 -> 2000.0
Tuple.get(): u03 -> 3000.0
jedis.zrevrangeByScore(): []
jedis.zcount(): 3
jedis.zscore(): 1000.0
jedis.zrank(u01): 0
jedis.zrevrank(u01): 4
jedis.zrem(): 2
jedis.zremrangeByRank(): 2
jedis.zremrangeByScore(): 1
jedis.zrange(): []
jedis.zincrby(10000): 13324.0
jedis.zrange(): [u11, u12, u13]
Process finished with exit code 0
7. JedisPool
JedisPoolConfig
public class JredisPoolBuilder {
public static final int MAX_IDLE = 50; //允许最大空闲连接数
public static final int MAX_TOTAL = 50;//最大连接数
private static JedisPool pool = null;
static {
//创建连接池
buildPool();
//预热连接池
hotPool();
}
//创建连接池
private static JedisPool buildPool() {
if (pool == null) {
long start = System.currentTimeMillis();
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(MAX_TOTAL);
config.setMaxIdle(MAX_IDLE);
config.setMaxWaitMillis(1000 * 10);
// 在borrow一个jedis实例时,是否提前进行validate操作;
// 如果为true,则得到的jedis实例均是可用的;
config.setTestOnBorrow(true);
//new JedisPool(config, ADDR, PORT, TIMEOUT, AUTH);
pool = new JedisPool(config, "127.0.0.1", 6379, 10000);
long end = System.currentTimeMillis();
Logger.info("buildPool 毫秒数:", end - start);
}
return pool;
}
//获取连接
public synchronized static Jedis getJedis() {
return pool.getResource();
}
//连接池的预热
public static void hotPool() {
long start = System.currentTimeMillis();
List<Jedis> minIdleJedisList = new ArrayList<Jedis>(MAX_IDLE);
Jedis jedis = null;
for (int i = 0; i < MAX_IDLE; i++) {
try {
jedis = pool.getResource();
minIdleJedisList.add(jedis);
jedis.ping();
} catch (Exception e) {
Logger.error(e.getMessage());
} finally {
}
}
for (int i = 0; i < MAX_IDLE; i++) {
try {
jedis = minIdleJedisList.get(i);
jedis.close();
} catch (Exception e) {
Logger.error(e.getMessage());
} finally {
}
}
long end = System.currentTimeMillis();
Logger.info("hotPool 毫秒数:", end - start);
}
}
JedisPool的使用
可以使用前面定义好的getJedis()方法,间接地通过pool.getResource()从连接池获取连接;也可以直接通过pool.getResource()方法获取Jedis连接。
主要的要求是Jedis连接使用完后,一定要调用close方法关闭连接,这个关闭操作不是真正地关闭连接,而是归还给连接池。
8. spring-data-redis
在使用spring-data-redis时,虽然没有直接用到Jedis库,但是spring-data-redis库底层对Redis服务的操作还是调用Jedis库完成的。
也就是说,spring-data-redis库从一定程度上使大家更好地使用Jedis库。
spring-data-redis库在RedisConnection连接类的基础上,针对不同的缓存类型,设计了五大数据类型的命令API集合,用于完成不同类型的数据缓存操作,并封装在RedisTemplate模板类中。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
@Autowired
private RedisTemplate<String, Object> redisTemplate;
(1)@CachePut作用是设置缓存。先执行方法,并将执行结果缓存起来。
(2)@CacheEvict的作用是删除缓存。在执行方法前,删除缓存。
(3)@Cacheable的作用更多是查询缓存。首先检查注解中的Key键是否在缓存中,如果是,则返回Key的缓存值,不再执行方法;否则,执行方法并将方法结果缓存起来。从后半部分来看,@Cacheable也具备@CachePut的能力。