1.redis常见数据结构以及使用场景分析
(1)String:key+value的形式,即一个Key对应一个value
String数据结构是简单的key-value类型,value其实不仅可以是String,也可以是数字。 常规key-value缓存应用; 常规计数:微博数,粉丝数等。
(2)Hash:key + name-value的形式,即一个key对应一个Map(存放多个键值对),这个Map像一个对象一样,键为属性名,值为属性值;
hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象,后续操作的时候,你可以直接仅仅修改这个对象中的某个字段的值。 比如我们可以 hash 数据结构来存储对象,如用户信息,商品信息等等。
(3)List:key + {value1, value2, value3, ...} 即多个value构成一个List,这个List对应一个Key;
list 就是链表,Redis list 的应用场景非常多,也是Redis最重要的数据结构之一,比如微博的关注列表,粉丝列表,消息列表等功能都可以用Redis的 list 结构来实现。
另外可以通过 lrange 命令,就是从某个元素开始读取多少个元素,可以基于 list 实现分页查询,这个很棒的一个功能,基于 redis 实现简单的高性能分页,可以做类似微博那种下拉不断分页的东西(一页一页的往下走),性能高。
(4)Set:key + {value1, value2, value3, ...},与List类似,无序,无重复value;
set 对外提供的功能与list类似是一个列表的功能,特殊之处在于 set 是可以自动排重的。
当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。
可以基于 set 轻易实现交集、并集、差集的操作。
比如:在微博应用中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。
Redis可以非常方便的实现如共同关注、共同粉丝、共同喜好等功能。这个过程也就是求交集的过程,具体命令如下:
sinterstore key1 key2 key3 // 将交集存在key1内
(5)Sorted Set:key + {value1-score, value2-score, value3-score, ...},与Set相比,每个集合元素value都多了个score属性,作为排序的依据;
和set相比,sorted set增加了一个权重参数score,使得集合中的元素能够按score进行有序排列。
举例: 在直播系统中,实时排行信息包含直播间在线用户列表,各种礼物排行榜,弹幕消息(可以理解为按消息维度的消息排行榜)等信息,适合使用 Redis 中的 Sorted Set 结构进行存储。
2. redis在项目中的使用示例:
(1)本次的redis操作主要是针对String的(放已报名总人数),如下:
查找/设置redis:
redis操作的Api路径:package redis.clients.jedis;
(2)ZSet(key-value+score):消费排行
(3) HashMap(key-key/value)一般一个map对象对应一个对象,其key/value为对象属性名/值:
3.Redis的操作API示例代码(包括连接和API命令):
<!-- redis依赖 https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.0.1</version>
</dependency>
package jedis;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
/**
* @author A
* redis 连接工具类
*/
public class JedisUtils {
private static JedisPoolConfig config;
private static JedisPool pool;
static {
config = new JedisPoolConfig();
//最大连接数, 默认8个
config.setMaxTotal(30);
//控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值是8。
config.setMaxIdle(2);
//连接超时时是否阻塞,false时报异常,ture阻塞直到超时, 默认true
config.setBlockWhenExhausted(true);
//逐出策略(默认DefaultEvictionPolicy(当连接超过最大空闲时间,或连接数超过最大空闲连接数))
config.setEvictionPolicyClassName("org.apache.commons.pool2.impl.DefaultEvictionPolicy");
//获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间, 默认-1
config.setMaxWaitMillis(-1);
//逐出连接的最小空闲时间 默认1800000毫秒(30分钟)
config.setMinEvictableIdleTimeMillis(1800000);
//最小空闲连接数, 默认0
config.setMinIdle(0);
//每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3
config.setNumTestsPerEvictionRun(3);
//对象空闲多久后逐出, 当空闲时间>该值 且 空闲连接>最大空闲数 时直接逐出,不再根据MinEvictableIdleTimeMillis判断 (默认逐出策略)
config.setSoftMinEvictableIdleTimeMillis(1800000);
// 获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间,
// 默认-1
config.setMaxWaitMillis(100);
//对拿到的connection进行validateObject校验
config.setTestOnBorrow(true);
//在进行returnObject对返回的connection进行validateObject校验
config.setTestOnReturn(true);
//定时对线程池中空闲的链接进行validateObject校验
config.setTestWhileIdle(true);
//本机redis地址
pool = new JedisPool(config, "127.0.0.1", 6379);
}
/**
* 获取连接的方法
* @return
*/
public static Jedis getJedis() {
return pool.getResource();
}
/**
* 释放连接
* @param j
*/
public static void closeJedis(Jedis j) {
j.close();
}
}
package jedis;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.junit.After;
import org.junit.Before;
import org.junit.jupiter.api.Test;
import redis.clients.jedis.Jedis;
/**
* @author A
*/
public class TestRedis {
static Jedis jedis = JedisUtils.getJedis();
@Test
public void testString() {
// redis存储字符串
// -----添加数据----------
jedis.set("name", "a");// 向key-->name中放入了value-->xinxin
System.out.println(jedis.get("name"));// 执行结果:xinxin
jedis.append("name", " b"); // 拼接
System.out.println(jedis.get("name"));
jedis.del("name"); // 删除某个键
System.out.println(jedis.get("name"));
// 设置多个键值对
jedis.mset("name", "zhangsan", "age", "23", "qq", "xxxxxxxxxxx");
jedis.incr("age"); // 进行加1操作
System.out.println(jedis.get("name") + "-" + jedis.get("age") + "-" + jedis.get("qq"));
}
@Test
public void testMap() {
// redis操作Map
// -----添加数据----------
Map<String, String> map = new HashMap<String, String>();
map.put("name", "a");
map.put("age", "22");
map.put("qq", "xxxxx");
jedis.hmset("user", map);
// 取出user中的name,注意结果是一个泛型的List
// 第一个参数是存入redis中map对象的key,后面跟的是放入map中的对象的key,后面的key可以跟多个,是可变参数
List<String> rsmap = jedis.hmget("user", "name", "age", "qq");
System.out.println(rsmap);
// 删除map中的某个键值
jedis.hdel("user", "age");
System.out.println(jedis.hmget("user", "age")); // 因为删除了,所以返回的是null
System.out.println(jedis.hlen("user")); // 返回key为user的键中存放的值的个数2
System.out.println(jedis.exists("user"));// 是否存在key为user的记录 返回true
System.out.println(jedis.hkeys("user"));// 返回map对象中的所有key
System.out.println(jedis.hvals("user"));// 返回map对象中的所有value
Iterator<String> iter = jedis.hkeys("user").iterator();
while (iter.hasNext()) {
String key = iter.next();
System.out.println(key + ":" + jedis.hmget("user", key));
}
}
@Test
public void testList() {
// jedis操作List
// 开始前,先移除所有的内容
jedis.del("java framework");
System.out.println(jedis.lrange("java framework", 0, -1));
// 先向key java framework中存放三条数据
jedis.lpush("java framework", "spring");
jedis.lpush("java framework", "struts");
jedis.lpush("java framework", "hibernate");
// 再取出所有数据jedis.lrange是按范围取出,
// 第一个是key,第二个是起始位置,第三个是结束位置,jedis.llen获取长度 -1表示取得所有
System.out.println(jedis.lrange("java framework", 0, -1));
jedis.del("java framework");
jedis.rpush("java framework", "spring");
jedis.rpush("java framework", "struts");
jedis.rpush("java framework", "hibernate");
System.out.println(jedis.lrange("java framework", 0, -1));
}
@Test
public void testSet() {
// jedis操作Set
// 清空数据
System.out.println(jedis.flushDB());
// 添加
jedis.sadd("name", "a");
jedis.sadd("name", "b");
jedis.sadd("name", "c");
jedis.sadd("name", "d");
jedis.sadd("name", "e");
// 移除noname
jedis.srem("name", "c");
System.out.println(jedis.smembers("name"));// 获取所有加入的value
System.out.println(jedis.sismember("name", "c"));// 判断 c 是否是user集合的元素
System.out.println(jedis.srandmember("name")); // 返回集合中的一个随机元素
System.out.println(jedis.scard("name"));// 返回集合的元素个数
}
@Test
public void testZSet() {
// jedis操作ZSet
jedis.zadd("hackers", 1940, "Alan Kay");
jedis.zadd("hackers", 1953, "Richard Stallman");
jedis.zadd("hackers", 1965, "Yukihiro Matsumoto");
jedis.zadd("hackers", 1916, "Claude Shannon");
jedis.zadd("hackers", 1969, "Linus Torvalds");
jedis.zadd("hackers", 1912, "Alan Turing");
Set<String> setValues = jedis.zrange("hackers", 0, -1);//zset中的所有元素
System.out.println(setValues);
Set<String> setValues2 = jedis.zrevrange("hackers", 0, -1);//按分数值递减(从大到小)来排列
System.out.println(setValues2);
// 清空数据
System.out.println(jedis.flushDB());
// 添加数据
jedis.zadd("zset", 10.1, "hello");
jedis.zadd("zset", 10.0, ":");
jedis.zadd("zset", 9.0, "zset");
jedis.zadd("zset", 11.0, "zset!");
// 元素个数
System.out.println(jedis.zcard("zset"));
// 元素下标
System.out.println(jedis.zscore("zset", "zset"));
// 集合子集
System.out.println(jedis.zrange("zset", 0, -1));
// 删除元素
System.out.println(jedis.zrem("zset", "zset!"));
System.out.println(jedis.zcount("zset", 9.5, 10.5));
// 整个集合值
System.out.println(jedis.zrange("zset", 0, -1));
}
@Test
public void testLuaScript() {
}
@After
private void destroy() {
jedis.flushDB();
JedisUtils.closeJedis(jedis);
}
public static void main(String[] args) {
new TestRedis().destroy();
}
}
4.使用方法命令参考:
使用文档:
Redis命令参考 (这个网站很好用!!!)