本文共 30812 字,大约阅读时间需要 102 分钟。
Redis学习结构
Redis基础
Redis概述
Redis是一个开源,先进的key-value存储,并用于构建高性能,可扩展的应用程序的完美解决方案。
Redis从它的许多竞争继承来的三个主要特点:
ØRedis数据库完全在内存中,使用磁盘仅用于持久性。
Ø相比许多键值数据存储,Redis拥有一套较为丰富的数据类型。
ØRedis可以将数据复制到任意数量的从服务器。
Redis 优势
Ø异常快速:Redis的速度非常快,每秒能执行约11万集合,每秒约81000+条记录。
Ø支持丰富的数据类型:String(字符串)、List(列表)、set(集合)、Sort Set(有序集合)、Hash(散列数据)。
Ø操作都是原子性:所有Redis操作是原子的,这保证了如果两个客户端同时访问的Redis服务器将获得更新后的值。
Ø多功能实用工具:Redis是一个多实用的工具,可以在多个用例如缓存,消息,队列使用(Redis原生支持发布/订阅),任何短暂的数据,应用程序,如Web应用程序会话,网页命中计数等。
Redis 部署
参考:
Redis 持久化
两种持久化方案:RDB和AOF
1)RDB方式按照一定的时间间隔对数据集创建基于时间点的快照。
2)AOF方式记录Server收到的写操作到日志文件,在Server重启时通过回放这些写操作来重建数据集。
该方式类似于MySQL中基于语句格式的binlog。当日志变大时Redis可在后台重写日志。
•RDB持久化配置
默认情况下,Redis保存数据集快照到磁盘,名为dump.rdb的二进制文件。可以设置让Redis在N秒内至少有M次数据集改动时保存数据集,或者你也可以手动调用SAVE或者BGSAVE命令。 例如,这个配置会让Redis在每个60秒内至少有1000次键改动时自动转储数据集到磁盘 save 60 1000
•AOF持久化配置
1)修改redis.config配置文件,找到appendonly。默认是appendonly no。改成appendonly yes
2)再找到appendfsync 。默认是 appendfsync everysec
appendfsync always
#每次收到写命令就立即强制写入磁盘,最慢的,但是保证完全的持久化,不推荐使用
appendfsync everysec
#每秒钟强制写入磁盘一次,在性能和持久化方面做了很好的折中,推荐
appendfsync no
#完全依赖os,性能最好,持久化没保证
Jedis
Jedis是Java代码操控Redis的一个客户端工具。
Jedis API:
Jedis池相关:
package redis.other;import redis.clients.jedis.Jedis;import redis.clients.jedis.JedisPool;import redis.clients.jedis.JedisPoolConfig;/** * Describe: 请补充类描述 */public class MyJedisPool { // jedis池 public static JedisPool pool; // 静态代码初始化池配置 static { //change "maxActive" -> "maxTotal" and "maxWait" -> "maxWaitMillis" in all examples JedisPoolConfig config = new JedisPoolConfig(); //控制一个pool最多有多少个状态为idle(空闲的)的jedis实例。 config.setMaxIdle(5); //控制一个pool可分配多少个jedis实例,通过pool.getResource()来获取; //如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。 //在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的; config.setMaxTotal(1000 * 100); //表示当borrow(引入)一个jedis实例时,最大的等待时间,如果超过等待时间,则直接抛出JedisConnectionException; config.setMaxWaitMillis(5); config.setTestOnBorrow(true); config.setTestOnReturn(true); try { //如果你遇到 java.net.SocketTimeoutException: Read timed out exception的异常信息 //请尝试在构造JedisPool的时候设置自己的超时值. JedisPool默认的超时时间是2秒(单位毫秒) pool = new JedisPool(config, "127.0.0.1", 6379, 20); } catch (Exception e) { throw new RuntimeException("redis 连接池初始化失败!"); } } public static void main(String[] args) { // 从jedis池中获取一个jedis实例 Jedis jedis = MyJedisPool.pool.getResource(); // 添加key-value对象,如果key对象存在就覆盖该对象 jedis.set("name", "maoxiangyi"); jedis.set("company", "aaa"); // 查取key的value值,如果key不存在返回null String name = jedis.get("name"); String company = jedis.get("company"); System.out.println(company + ":" + name); // 删除key-value对象,如果key不存在则忽略此操作 jedis.del("name"); // 判断key是否存在,不存在返回false存在返回true jedis.exists("name"); //关闭jedis链接,自动回收 jedis.close(); }}
String
先讲个面试题吧:Redis对int类型数值进行加1操作如何实现?
我们知道Redis数据类型中没有int的,解释Redis数字操作:
String类型基本操作:
package redis.string;import redis.clients.jedis.Jedis;import java.util.List;/** * Describe: 请补充类描述 */public class StringMain { public static void main(String[] args) throws InterruptedException { //创建Jedis客户端 Jedis jedis = new Jedis("127.0.0.1", 6379); //操作一个String字符串 jedis.set("name", "liudehua"); //插入一个名字,叫做刘德华 System.out.println(jedis.get("name")); //读取一个名字 //对string类型数据进行增减,前提是kv对应的值是数字 jedis.set("age", "17");//给用户刘德华设置年龄,17岁 jedis.incr("age");//让用户刘德华年龄增加一岁 System.out.println(jedis.get("age")); //打印结果 18 jedis.decr("age");//让刘德华年轻一岁 System.out.println(jedis.get("age"));//在18的基础上,减一岁,变回17 //一次性插入多条数据 。为江湖大侠设置绝杀技能 jedis.mset("AAA", "Mysql数据库的操作" , "BBB", "熟悉LINXU操作系统" , "CCC", "熟悉SSH、SSM框架及配置" , "DDD", "熟悉Spring框架,mybatis框架,Spring IOC MVC的整合,Spring和Mybatis的整合"); Listresults = jedis.mget("AAA", "BBB", "CCC", "DDD"); for (String value : results) { System.out.println(value); } //设置字段的自动过期 jedis.setex("wumai", 10, "我们活在仙境中"); //让仙境保持10秒钟 while (jedis.exists("wumai")) { System.out.println("真是天上人间呀!"); Thread.sleep(1000); } System.out.println(); //对已经存在的字段设置过期时间 jedis.set("wumai", "我们活在仙境中"); jedis.expire("wumai", 10); //让天上人间的感觉保持更长的时间 while (jedis.exists("wumai")) { System.out.println("真是天上人间呀!"); Thread.sleep(1000); } }}
对象的保存:
package redis.string;import com.google.gson.Gson;import org.junit.Test;import redis.clients.jedis.Jedis;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.util.Map;/** * Describe: 保存Product对象到redis中 */public class ProductService { @Test public void saveProduct2Redis() throws Exception { //初始化刘德华的基本信息 Person person = new Person("刘德华", 17); //将刘德华的信息保存到Redis中 Jedis jedis = new Jedis("127.0.0.1", 6379); //直接保存对象的toString方法,这种方法不反序列化对象 jedis.set("user:liudehua:str", person.toString()); System.out.println(jedis.get("user:liudehua:str")); //保存序列化之后的对象 jedis.set("user:liudehua:obj".getBytes(), getBytesByProduct(person)); byte[] productBytes = jedis.get("user:liudehua:obj".getBytes()); Person pByte = getProductByBytes(productBytes); System.out.println(pByte.getName()+" " +pByte.getAge()); //保存Json化之后的对象 jedis.set("user:liudehua:json", new Gson().toJson(person)); String personJson = jedis.get("user:liudehua:json"); Person pjson = new Gson().fromJson(personJson, Person.class); System.out.println(pjson.getName()+" "+ pjson.getAge()); } /** * 从字节数组中读取Java对象 * * @param productBytes * @return * @throws Exception */ public Person getProductByBytes(byte[] productBytes) throws Exception { ByteArrayInputStream byteInputStream = new ByteArrayInputStream(productBytes); ObjectInputStream objectInputStream = new ObjectInputStream(byteInputStream); return (Person) objectInputStream.readObject(); } /** * 将对象转化成Byte数组 * * @param product * @return * @throws Exception */ public byte[] getBytesByProduct(Person product) throws Exception { ByteArrayOutputStream ba = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(ba); oos.writeObject(product); oos.flush(); return ba.toByteArray(); }}
应用场景:String数据类型实现计数功能
因为Redis都是原子性操作,可应用于多线程情景下实现计数功能。
package redis.string;import redis.clients.jedis.Jedis;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/** * Describe: 擂台比武 */public class Counter { /** * 计算 武林大会 三个擂台的比武次数 * * @param args */ public static void main(String[] args) { //创建一个固定大小的线程池,3个擂台 ExecutorService executorService = Executors.newFixedThreadPool(10); //擂台1:天龙八部 executorService.submit(new Arena("biwu:totalNum","天龙八部")); //擂台2:神雕侠侣 executorService.submit(new Arena("biwu:totalNum","神雕侠侣")); //擂台3:倚天屠龙记 executorService.submit(new Arena("biwu:totalNum","倚天屠龙记")); //报幕人员,一秒统计一次总共比了多少场 executorService.submit(new BaoMu("biwu:totalNum")); }}package redis.string;import redis.clients.jedis.Jedis;import java.util.Random;/** * Describe: 擂台 */public class Arena implements Runnable { private Random random = new Random(); private String redisKey; private Jedis jedis; private String arenaName; public Arena(String redisKey, String arenaName) { this.redisKey = redisKey; this.arenaName = arenaName; } public void run() { jedis = new Jedis("127.0.0.1",6379); String[] daxias = new String[]{"郭靖", "黄蓉", "令狐冲", "杨过", "林冲", "鲁智深", "小女龙", "虚竹", "独孤求败", "张三丰", "王重阳", "张无忌" , "王重阳", "东方不败", "逍遥子", "乔峰", "虚竹", "段誉" , "韦小宝", "王语嫣", "周芷若", "峨眉师太", "慕容复"}; while (true) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } int p1 = random.nextInt(daxias.length); int p2 = random.nextInt(daxias.length); while (p1 == p2) { //如果两个大侠出场名字一样,换一个人 p2 = random.nextInt(daxias.length); } System.out.println("在擂台" + arenaName + "上 " + daxias[p1] + " VS " + daxias[p2]); jedis.incr(redisKey); } }}package redis.string;import redis.clients.jedis.Jedis;import java.util.concurrent.Callable;/** * Describe: 报幕人员 */public class BaoMu implements Runnable { private Jedis jedis; private String redisKey; public BaoMu(String redisKey) { this.redisKey = redisKey; } public void run() { jedis = new Jedis("127.0.0.1",6379); while (true) { try { Thread.sleep(1000); System.out.println("===================当前总共比武次数为:" + jedis.get(redisKey)); } catch (Exception e) { System.out.println("擂台被损坏..."+e); } } }}
Hash数据类型
Hash基本操作,区别Redis的key和Hash的key不是同一个概念
package redis.map;import redis.clients.jedis.Jedis;import java.util.List;import java.util.Map;import java.util.Set;/** * Describe: 请补充类描述 */public class MapMain { public static void main(String[] args) { Jedis jedis = new Jedis("127.0.0.1", 6379); jedis.del("daxia:jingzhongyue"); //创建一个对象 jedis.hset("daxia:jingzhongyue", "姓名", "不为人知"); jedis.hset("daxia:jingzhongyue", "年龄", "18"); jedis.hset("daxia:jingzhongyue", "技能", "杀人于无形"); //打印对象 Mapjingzhongyue = jedis.hgetAll("daxia:jingzhongyue"); System.out.println("hgetAll 大侠的基本信息:"); for (Map.Entry entry : jingzhongyue.entrySet()) { System.out.println(entry.getKey() + ":-----------------" + entry.getValue()); } System.out.println(); //获取大侠的所有字段信息 Set fields = jedis.hkeys("daxia:jingzhongyue"); System.out.println("hkeys "); for (String field : fields) { System.out.print(field + " "); } System.out.println(); //获取大侠的所有值的信息 List values = jedis.hvals("daxia:jingzhongyue"); System.out.println("hvals " ); for (String value : values) { System.out.print(value + " "); } System.out.println(); //值获取大侠的年龄,进行研究 String age = jedis.hget("daxia:jingzhongyue", "年龄"); System.out.println("对大侠的年龄有质疑:" + age); //给大侠的年龄增加十岁 jedis.hincrBy("daxia:jingzhongyue", "年龄", 10); System.out.println("经过验核,大侠的实际年龄为:" + jedis.hget("daxia:jingzhongyue", "年龄")); System.out.println(); //删除大侠的姓名 jedis.hdel("daxia:jingzhongyue", "姓名"); for (Map.Entry entry : jedis.hgetAll("daxia:jingzhongyue").entrySet()) { System.out.println(entry.getKey() + ":" + entry.getValue()); } }}
应用场景:Hash数据类型实现购物车,一个购物车对应一个Map集合。
package redis.map;import com.google.gson.Gson;import redis.clients.jedis.Jedis;import redis.string.StringMain;import java.math.BigDecimal;import java.util.ArrayList;import java.util.List;import java.util.Map;import java.util.Set;/** * Describe: 购物车 */public class Cart { private Jedis jedis; public Cart() { jedis = new Jedis("127.0.0.1", 6379); } public Cart(Jedis jedis) { this.jedis = jedis; } /** * 修改购物车中的商品 * * @param userName 用户名 * @param productId 商品编号 * @param num 操作商品的数量 */ public void updateProduct2Cart(String userName, String productId, int num) { jedis.hincrBy("shop:cart:" + userName, productId, num); } /** * 获取用户购物车的商品信息 * * @param userName * @return */ public ListgetProductsByUserName(String userName) { List products = new ArrayList (); Map productMap = jedis.hgetAll("shop:cart:" + userName); if (productMap == null || productMap.size() == 0) { return products; } for (Map.Entry entry : productMap.entrySet()) { Product product = new Product(); product.setId((String) entry.getKey());//获取用户购物车中商品的编号 int num = Integer.parseInt((String) entry.getValue());//获取用户购物车中商品的数量 product.setNum(num > 0 ? num : 0);//如果商品数量大于0,返回正常的值,如果商品小于0,初始化为0 complementOtherField(product);//补全商品的其他信息 products.add(product); } return products; } private void complementOtherField(Product product) { String productId = product.getId(); String productJsonStr = jedis.get("shop:product:" + productId); Product productJson = (Product) new Gson().fromJson(productJsonStr, Product.class); if (productJson != null) { product.setName(productJson.getName()); product.setPrice(productJson.getPrice()); } } public static void main(String[] args) { //初始化商品的信息 initData(); //创建购物车对象 Cart cart = new Cart(); //创建用户 String userName = "liudehua"; //往用户购物车中添加商品 cart.updateProduct2Cart(userName, "1645080454", 10); cart.updateProduct2Cart(userName, "1788744384", 1000); cart.updateProduct2Cart(userName, "1645139266", -1000); //打印当前用户的购物车信息 List products = cart.getProductsByUserName(userName); for (Product product : products) { System.out.println(product); } } private static void initData() { System.out.println("========================初始化商品信息==========================="); Jedis jedis = new Jedis("127.0.0.1", 6379); //准备数据 Product product1 = new Product("1645139266", "战地鳄2015秋冬新款马甲可脱卸帽休闲时尚无袖男士羽绒棉外套马甲", new BigDecimal("168")); Product product2 = new Product("1788744384", "天乐时 爸爸装加厚马甲秋冬装中年大码男士加绒马夹中老年坎肩老年人", new BigDecimal("40")); Product product3 = new Product("1645080454", "战地鳄2015秋冬新款马甲可脱卸帽休闲时尚无袖男士羽绒棉外套马甲", new BigDecimal("230")); //将数据写入到Redis jedis.set("shop:product:" + product1.getId(), new Gson().toJson(product1)); jedis.set("shop:product:" + product2.getId(), new Gson().toJson(product2)); jedis.set("shop:product:" + product3.getId(), new Gson().toJson(product3)); //打印所有产品信息 Set allProductKeys = jedis.keys("shop:product:*"); //获取所有的商品信息 for (String key : allProductKeys) { String json = jedis.get(key); Product product = new Gson().fromJson(json, Product.class);//从字符串中解析出对象 System.out.println(product); } System.out.println("========================用户购物车信息如下==========================="); }}package redis.map;import java.math.BigDecimal;/** * Describe:商品类 */public class Product { private String id;//商品编号 private String name;//商品名称 private BigDecimal price;//商品价格 private int num;//商品数量 public Product() { } public Product(String id, String name, BigDecimal price) { this.id = id; this.name = name; this.price = price; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public BigDecimal getPrice() { return price; } public void setPrice(BigDecimal price) { this.price = price; } public int getNum() { return num; } public void setNum(int num) { this.num = num; } @Override public String toString() { return "Product{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", price=" + price + ", num=" + num + '}'; }}
List
List基本操作:List左右端均可以操作,相当于双向队列。
package redis.list;import redis.clients.jedis.BinaryClient;import redis.clients.jedis.Jedis;import java.util.List;/** * 天龙八部外传-麦当劳风云 */public class ListMain { public static void main(String[] args) { //创建一个Redis的客户端 Jedis jedis = new Jedis("127.0.0.1", 6379); jedis.del("柜台1"); //鸠摩智,虚竹,段誉,乔峰 排队买肯德基 jedis.lpush("柜台1", "乔峰", "段誉", "虚竹", "鸠摩智"); for (String name : jedis.lrange("柜台1", 0, -1)) { System.out.print(name + " "); } System.out.println(); //剧情:新来一个人 王语嫣,插队,到第一名。 jedis.rpush("柜台1", "王语嫣"); Listlist = jedis.lrange("柜台1", 0, -1); for (String name : list) { System.out.print(name + " "); } System.out.println(); //剧情:鸠摩智很不高兴,正好慕容复来了,说:慕容兄,你插我前面 jedis.linsert("柜台1", BinaryClient.LIST_POSITION.AFTER, "鸠摩智", "慕容复"); List list1 = jedis.lrange("柜台1", 0, -1); for (String name : list1) { System.out.print(name + " "); } System.out.println(); //剧情:看到慕容复插队大家很生气,正好阿紫和游坦之。让阿紫和游坦之依次插到虚竹的后面 jedis.linsert("柜台1", BinaryClient.LIST_POSITION.BEFORE, "虚竹", "阿紫"); jedis.linsert("柜台1", BinaryClient.LIST_POSITION.BEFORE, "阿紫", "游坦之"); List list2 = jedis.lrange("柜台1", 0, -1); for (String name : list2) { System.out.print(name + " "); } System.out.println(); //剧情:插队不文明,为了遏制这种不文明的现象,大决决定打一架。 鸠摩智被打跑了。 jedis.lpop("柜台1"); for (String name : jedis.lrange("柜台1", 0, -1)) { System.out.print(name + " "); } System.out.println(); //剧情:慕容复一看情况不好,以表哥的身份忽悠王语嫣,把王语嫣打伤。 jedis.rpop("柜台1"); for (String name : jedis.lrange("柜台1", 0, -1)) { System.out.print(name + " "); } System.out.println(); //剧情:在大家打架的时候,我偷偷插队,买了肯德基。 jedis.rpush("柜台1", "井中月"); for (String name : jedis.lrange("柜台1", 0, -1)) { System.out.print(name + " "); } System.out.println(); //剧情;等我买了肯德基,慕容复被打跑了 jedis.lpop("柜台1"); for (String name : jedis.lrange("柜台1", 0, -1)) { System.out.print(name + " "); } System.out.println(); //剧情:星宿老怪 突然来了,把 阿紫和游坦之同时弄走了。 String result = jedis.ltrim("柜台1", 2, 5); if ("OK".equals(result)) { for (String name : jedis.lrange("柜台1", 0, -1)) { System.out.print(name + " "); } } System.out.println(""); //剧情:这时候,乔峰三人发现了我,与我大战三百回合,我全身而退 String res = jedis.ltrim("柜台1", 0, 2); if ("OK".equals(res)) { for (String name : jedis.lrange("柜台1", 0, -1)) { System.out.print(name + " "); } } }}
应用场景:网络爬虫
package redis.list;import org.jsoup.Jsoup;import org.jsoup.helper.StringUtil;import org.jsoup.nodes.Document;import org.jsoup.nodes.Element;import org.jsoup.select.Elements;import redis.clients.jedis.Jedis;import java.util.Date;import java.util.List;public class Crawler { //定义需要爬取的url list private static final String redisUrlsWillKey = "crawler:urls:will"; //如果需要去重的话,可以使用set保存已经爬起过的url public static void main(String[] args) throws Exception { //准备Url String startUrl = "https://www.huxiu.com/article/259690.html"; String domain = "http://www.huxiu.com/"; //获取文章Url getUrls(startUrl, domain); //处理url,下载文章的内容并打印 parserUrl(); } private static void parserUrl() throws Exception { Jedis jedis = new Jedis("127.0.0.1", 6379); //从右边弹出一个url while (true) { String url = jedis.rpop(redisUrlsWillKey); try { Article article = parser(url); System.out.println(article); } catch (Exception e) {// jedis.lpush(redisUrlsWillKey, url); } } } private static Article parser(String url) throws Exception { Document articleDocument = Jsoup.connect(url).get(); Article article = new Article(); // 封装作者的信息 Elements author = articleDocument .getElementsByClass("author-name"); article.setAuthor(StringUtil.isBlank(author.text()) ? "jingzhongyue" : author.text()); // 抽取文章日期 Elements date = articleDocument .getElementsByClass("article-time"); article.setDate(StringUtil.isBlank(date.text()) ? new Date() : DateUtil.getDate(date.text())); // 抽取文章标题 Elements title = articleDocument.getElementsByTag("title"); article.setTitle(title.text()); // 抽取文章编号 // http://www.huxiu.com/article/124698/1.html String id = url.substring(29); int index = id.indexOf("/"); id = id.substring(0, index); article.setId(id); // 抽取文章正文 StringBuffer stringBuffer = new StringBuffer(); Elements contents = articleDocument .getElementsByAttribute("id"); for (Element element : contents) { String idTag = element.attr("id"); if ("article_content".equals(idTag)) { Elements childs = element.children(); Elements pElements = childs.tagName("p"); for (Element element2 : pElements) { stringBuffer.append(element2.text()); } } } return article; } private static void getUrls(String startUrl, String domain) throws Exception { Jedis jedis = new Jedis("127.0.0.1", 6379); Document document = Jsoup.connect(startUrl).get(); Elements elements = document.getElementsByAttribute("href"); for (Element element : elements) { String endUrl = element.attr("href"); if (endUrl.contains("article")) { String url = domain + endUrl; System.out.println(url); jedis.lpush(redisUrlsWillKey, url); } } }}
Set
Set基本操作:无序、无重复元素
package redis.set;import redis.clients.jedis.Jedis;import java.util.Set;/** * Describe: 请补充类描述 */public class SetMain { public static void main(String[] args) { Jedis jedis = new Jedis("127.0.0.1", 6379); //河南武林人物登记表---杜绝冒名顶替的情况 String[] daxias = new String[]{"郭靖", "黄蓉", "令狐冲", "杨过", "林冲", "鲁智深", "小女龙", "虚竹", "独孤求败", "张三丰", "王重阳", "张无忌" , "王重阳", "东方不败", "逍遥子", "乔峰", "虚竹", "段誉" , "韦小宝", "王语嫣", "周芷若", "峨眉师太", "慕容复", "郭靖", "乔峰", "王重阳"}; //创建并设置一个set的值 jedis.sadd("biwu:dengji", daxias); //获取一个set中所有的元素 SetdaxiaSet = jedis.smembers("biwu:dengji"); for (String name : daxiaSet) { System.out.print(name + " "); //set集合的特点:无序、无重复元素 } System.out.println(); //判断一个成员是否属于某条指定的set数据 boolean isComing = jedis.sismember("biwu:dengji", "井中月"); //判断大侠井中月是否到来 if (!isComing) { System.out.println("大侠 井中月尚未登记."); } //计算一个set中有多少元素 long totalNum = jedis.scard("biwu:dengji"); System.out.println("有" + totalNum + " 位大侠已经登记了!"); System.out.println(); //大侠井中月没有来,是因为报名参与另外一个会议 国际武林大会 String[] daxiaArr = new String[]{"王语嫣", "周芷若", "峨眉师太", "慕容复","郭靖", "乔峰", "井中月"}; jedis.sadd("guoji:dengji", daxiaArr); //国际武林大会登记表 Set xindaxias = jedis.smembers("guoji:dengji"); for (String name : xindaxias) { System.out.print(name + "--- "); //集合的特点:无序、无重复元素 } System.out.println(); //计算两个Set之间的交集 Set users = jedis.sinter("biwu:dengji", "guoji:dengji"); for (String name : users) { System.out.print(name + " "); } System.out.println(); //计算两个Set之间的并集 users = jedis.sunion("biwu:dengji", "guoji:dengji"); for (String name : users) { System.out.print(name + " "); } System.out.println(); System.out.println("井中月出来了"); //计算两个集合的差集 users = jedis.sdiff("biwu:dengji", "guoji:dengji"); for (String name : users) { System.out.print(name + " "); } System.out.println(); System.out.println(); //将两个集合计算出来的差集保存起来,升级为超级Vip jedis.sdiffstore("vipdaxia","biwu:dengji", "guoji:dengji"); for (String name : jedis.smembers("vipdaxia")) { System.out.print(name + " "); } }}
应用场景:通过对两个集合的操作计算订单浏览、下单、支付等转化率
package redis.set;import redis.clients.jedis.Jedis;import java.text.DecimalFormat;import java.text.NumberFormat;import java.util.Set;/** * Describe: 请补充类描述 */public class Transform { public static void main(String[] args) { Jedis jedis = new Jedis("127.0.0.1", 6379); //浏览某商品的用户 jedis.sadd("viewUsers", "郭靖", "黄蓉", "令狐冲", "杨过", "林冲", "鲁智深", "小女龙", "虚竹", "独孤求败", "张三丰", "王重阳", "张无忌" , "王重阳", "东方不败", "逍遥子", "乔峰", "虚竹", "段誉"); //下单用户 jedis.sadd("orderUsers", "郭靖", "黄蓉", "令狐冲", "杨过", "林冲", "鲁智深", "小女龙", "虚竹", "独孤求败", "乔峰", "虚竹", "段誉"); //支付用户 jedis.sadd("paymentUsers", "郭靖", "黄蓉", "令狐冲", "杨过", "独孤求败", "段誉"); //浏览过商品的用户,有哪些下单了。 jedis.sinterstore("view2order", "viewUsers", "orderUsers"); //求两个集合的交集 //计算浏览某商品的用户数量 和 既浏览又下单的用户的数量 double viewUserNum = jedis.scard("viewUsers"); double orderUserNum = jedis.scard("view2order"); NumberFormat formatter = new DecimalFormat("0.00"); Double x = new Double(orderUserNum / viewUserNum); System.out.print("订单" + orderUserNum + "/浏览" + viewUserNum + "转化:" + formatter.format(x) + " 他们是:"); for (String name : jedis.smembers("view2order")) { System.out.print(name + " "); } System.out.println(); //浏览并且下单的用户,最终支付的转化 jedis.sinterstore("order2Payment", "view2order", "paymentUsers"); //求两个集合的交集 double paymentUserNum = jedis.scard("paymentUsers"); x = new Double(paymentUserNum / orderUserNum); System.out.print("支付" + paymentUserNum + "/订单" + orderUserNum + "转化:" + formatter.format(x) + " 他们是:"); for (String name : jedis.smembers("order2Payment")) { System.out.print(name + " "); } System.out.println(); //浏览并最终支付的用户的转化 x = new Double(paymentUserNum / viewUserNum); System.out.print("支付" + paymentUserNum + "/浏览" + viewUserNum + "转化:" + formatter.format(x)+" 他们是:"); for (String name : jedis.smembers("order2Payment")) { System.out.print(name + " "); } System.out.println(); }}
Sort Set
Sort Set基本操作
package redis.sortSet;import redis.clients.jedis.Jedis;import java.util.Set;/** * Describe: 请补充类描述 */public class SortMain { public static void main(String[] args) { Jedis jedis = new Jedis("127.0.0.1", 6379); //往redis库中插入一条sortedset数据 jedis.zadd("比武成绩", 10, "乔峰"); jedis.zadd("比武成绩", 5, "王重阳"); jedis.zadd("比武成绩", 7, "虚竹"); jedis.zadd("比武成绩", 2, "王语嫣"); jedis.zadd("比武成绩", 5, "段誉"); jedis.zadd("比武成绩", 4, "峨眉师太"); jedis.zadd("比武成绩", 20, "张三丰"); //获取sortSet中所有的元素 Setnames = jedis.zrange("比武成绩", 0, -1); for (String name : names) { System.out.println(name + " 排名: " //打印用户升序排行 + jedis.zrank("比武成绩", name) + " 赢的场次: " //打印用户的比武成绩 + jedis.zscore("比武成绩", name)); } System.out.println("=============================="); names = jedis.zrevrange("比武成绩", 0, -1); for (String name : names) { System.out.println(name + " " + jedis.zrevrank("比武成绩", name) + " " + jedis.zscore("比武成绩", name)); } System.out.println("=============================="); //修改用户的分数 jedis.zincrby("比武成绩",100,"王语嫣"); names = jedis.zrevrange("比武成绩", 0, -1); for (String name : names) { System.out.println(name + " " + jedis.zrevrank("比武成绩", name) + " " + jedis.zscore("比武成绩", name)); } }}
应用场景:天猫订单量和销售总额动态排行榜
package redis.sortSet;import redis.clients.jedis.Jedis;import java.util.Random;import java.util.Set;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/** * Describe: 请补充类描述 */public class Bang { public static void main(String[] args) { //创建线程池 ExecutorService executorService = Executors.newFixedThreadPool(10); //创建销售线程-销售商品 executorService.submit(new Sale()); executorService.submit(new Sale()); //创建报表线程-周期型计算排行榜 executorService.submit(new BangView()); }}class Sale implements Runnable { //店铺销售排行榜 private static final String amountBang = "tmall:amountBang"; //店铺订单排行榜 private static final String orderBang = "tmall:orderBang"; //店铺名称 private static final String[] shops = new String[]{"小米", "华为", "魅族", "苹果", "联想", "奇酷", "中兴", "一加", "oppo"}; //Redis客户端 private Jedis jedis = new Jedis("127.0.0.1", 6379); //随机获取店铺 private Random random = new Random(); //随机计算价格 private Random priceRandom = new Random(); public void run() { while (true) { try { int shopIndex = random.nextInt(shops.length); jedis.zincrby(amountBang, priceRandom.nextInt(2500), shops[shopIndex]); jedis.zincrby(orderBang, 1, shops[shopIndex]); Thread.sleep(1000); } catch (InterruptedException e) { System.out.println(e); } } }}class BangView implements Runnable { //店铺销售排行榜 private static final String amountBang = "tmall:amountBang"; //店铺订单排行榜 private static final String orderBang = "tmall:orderBang"; //Redis客户端 private Jedis jedis = new Jedis("127.0.0.1", 6379); public void run() { while (true) { try { Thread.sleep(1000); System.out.println("==============店铺销售额排行=============================="); Setnames = jedis.zrevrange(amountBang, 0, 4); for (String name : names) { System.out.println(name + " " + jedis.zrevrank(amountBang, name) + " " + jedis.zscore(amountBang, name)); } System.out.println("==============店铺订单量排行=============================="); names = jedis.zrevrange(orderBang, 0, 1); for (String name : names) { System.out.println(name + " " + jedis.zrevrank(orderBang, name) + " " + jedis.zscore(orderBang, name)); } System.out.println(); System.out.println(); } catch (InterruptedException e) { e.printStackTrace(); } } }}