Java连接Redis
Jedis是Redis官方推荐的Java连接开发工具。
api:https://tool.oschina.net/apidocs/apidoc?api=jedis-2.1.0
一、 导入包
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>2.9.0</version>
</dependency>
二、创建工具类 RedisUtil
package com.utils;import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;public class RedisUtil {//Redis服务器IPprivate static String ADDR = "127.0.0.1";//Redis的端口号private static int PORT = 6379;//访问密码private static String AUTH = "123456";//可用连接实例的最大数目,默认值为8;//如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。private static int MAX_ACTIVE = 1024;//控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。private static int MAX_IDLE = 200;//等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException;private static int MAX_WAIT = 10000;private static int TIMEOUT = 10000;//在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;private static boolean TEST_ON_BORROW = true;private static JedisPool jedisPool = null;//初始化redis连接池static {JedisPoolConfig config = new JedisPoolConfig();config.setMaxIdle(MAX_IDLE);config.setMaxWaitMillis(MAX_WAIT);config.setTestOnBorrow(TEST_ON_BORROW);//配置,IP,端口,超时时间,密码jedisPool = new JedisPool(config,ADDR,PORT,TIMEOUT,AUTH);}//获取Jedis实例public synchronized static Jedis getJedis(){if(jedisPool!=null){Jedis jedis = jedisPool.getResource();return jedis;}else{return null;}}//释放jedis资源public static void returnResource(Jedis jedis){if(jedis!=null){jedisPool.returnResource(jedis);}}}
三、在测试类中测试

测试代码
//redis存储字符串 string@Testpublic void testString(){jedis.select(2);jedis.set("name","laowang");jedis.set("name","laoli");System.out.println(jedis.get("name"));jedis.set("age","18");System.out.println(jedis.get("age"));//拼接jedis.append("name"," is my love");System.out.println(jedis.get("name"));//删除jedis.del("age");System.out.println(jedis.get("age"));//设置多个键值对jedis.mset("sname","laozhang","sage","28","qq","11223344");jedis.incr("sage");//加1操作System.out.println(jedis.get("sname")+"-"+jedis.get("sage")+"-"+jedis.get("qq"));}//redis操作hash--java里面操作Map map<String,String>@Testpublic void testMap(){Map<String,String> map = new HashMap<>();map.put("name","laozhang");map.put("age","16");map.put("qq","123456");jedis.hmset("user",map);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"));//删除了age的key 获取nullSystem.out.println(jedis.hlen("user"));//返回user的键中还有几个valueSystem.out.println(jedis.exists("user"));//是否存在某个keySystem.out.println(jedis.hkeys("user"));//返回map对象中所有的keySystem.out.println(jedis.hvals("user"));//返回map对象中所有的valueIterator<String> iterator = jedis.hkeys("user").iterator();while (iterator.hasNext()){String key = iterator.next();System.out.println(key+":"+jedis.hmget("user",key));}}/*** jedis操作List-- java里面操作的是List<String>*/@Testpublic void testList() {//开始前,先移除所有的内容jedis.del("java framework");System.out.println(jedis.lrange("java framework", 0, -1));//先向key java framework中存放三条数据jedis.lpush("java framework", "spring");//redis的list类型 每个元素都是stringjedis.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));}/*** jedis操作Set -- 在java里面返回的Set<String>或List<String>* (例如System.out.println(jedis.srandmember("user1"));时返回的就是一个List<String>)* 但是set类型本身是一个无序+不重复的list == java Set*/@Testpublic void testSet() {//添加jedis.sadd("user1", "liuling");jedis.sadd("user1", "xinxin");jedis.sadd("user1", "ling");jedis.sadd("user1", "zhangxinxin");jedis.sadd("user1", "who");//移除其中一个元素jedis.srem("user1", "who");System.out.println(jedis.smembers("user1"));//获取所有加入的valueSystem.out.println(jedis.sismember("user1", "who"));//判断 who 是否是user集合的元素//随机元素System.out.println(jedis.srandmember("user1"));System.out.println(jedis.scard("user1"));//返回集合的元素个数}//jedis操作zset -- java返回的是 Set<String> 排序+不重复的list 有点像 java TreeSet@Testpublic void test() throws InterruptedException {//如果要实现有序的集合,可以考虑使用list来排序(不去重)//注意,此处的rpush和lpush是List的操作。是一个双向链表(但从表现来看的)jedis.del("a");//先清除数据,再加入数据进行测试jedis.rpush("a", "1");jedis.lpush("a", "6");jedis.lpush("a", "3");jedis.lpush("a", "9");System.out.println(jedis.lrange("a", 0, -1));// [9, 3, 6, 1]System.out.println(jedis.sort("a")); //[1, 3, 6, 9] //输入排序后结果//使用zset类型实现有序集合去重//使用zadd命令 成绩排序 升序jedis.zadd("scoreList",100.0,"张三");jedis.zadd("scoreList",70.0,"李四");jedis.zadd("scoreList",85.5,"王朝");jedis.zadd("scoreList",100.0,"马汉");jedis.zadd("scoreList",90.0,"马汉");//展示全部System.out.println(jedis.zrange("scoreList",0,-1));}
四、Redis类型的使用场景
1、Redis 字符串(String)
典型应用场景:
1.作为缓存 -- 数据分两类冷数据与热数据,热数据表示经常使用的时常发生变化的数据但是对数据一致性要求不高的数据,如一个视频的点击量,某文件的浏览次数,某商品的日月销量,系统消息以及用户消息这些热数据都可以用Redis来做
2.限制某段时间内的访问次数,就比如我们登录的功能可以用手机获取验证码登录,但是我们发送验证码使用的第三方,是多少钱多少条的,肯定不能让他一直点,一直发短信,就算前端js做了校验,若有些人绕过前台就麻烦了,这时候可以用redis的incr命令和expire结合起来做一个解决方案
3.用于限流:计数器
举个栗子:
我们在双十一经常会有一些秒杀场景,比如我们现在需要秒杀一百台0.01元的手机,库存设置100。可想而知,会有很多十万甚至百万级别的用户都在等待到点抢手机,在使用redis之前,我们的流程是这样的,即所有的并发压力都压在服务(如果你服务不拦截,就压在数据库上),很可能高并发会彻底搞垮的服务或数据库:

使用redis之后:

2、Redis 哈希(Hash)
典型应用场景:
记录帖子的标题、摘要、作者和封面信息,用于列表页展示
记录帖子的点赞数、评论数和点击数
保存一个商品信息,该信息同时带有多个商品属性,就可以考虑使用hash的数据格式进行存储。但这种场景也可以考虑使用StringKey+jsonValue的情况来实现。两种方案中,如果商品信息可能会频繁变更,hash类型会更占优势。
3、Redis 列表(List)
典型使用场景:
简单的消息队列:
不推荐,不可靠,且市面上已有很多成熟的消息队列产品。
消息队列本身需要保证消息顺序不打乱、不处理重复的消息和保证消息可靠性。
如果我们一定要使用list类型实现消息队列,我们需要:
实现保证消息顺序
list类型可以支持。生产者使用LPUSH把消息写入队列,消费者使用RPOP把消息从队列中读取出来。
消息可靠性保证(如果消息出栈消费者就宕机没处理上如何保证可靠)
消费者从List中获取一条消息后,List不会再有这条消息的留存了,但是如果消费者获取了消息,但是还没来得及处理消费者就宕机了,那么这条消息就丢失了。为了解决留存问题。List类型提供了BRPOPLPUSH命令,这个命令的作用是让消费者程序从一个List中读取消息,同时,Redis会自动把这个消息再插入到另一个List(可以叫作备份List)留存,这样就可以保证消息可靠。
消息不重复处理保证(一个消息不处理两次)
list类型本身不能实现这个效果,我们需要在list的设计中加入唯一id自行保证。
分页展示
获取最新的列表(最新评论等等)
4、Zset有序集合
典型场景
排行版(例如热度榜、分类热榜)
虽然有序集合的成员是唯一的,但是分数(score)却可以重复。就比如在一个班中,学生的学号是唯一的,但是每科成绩却是可以一样的,redis可以利用有序集合存储学生成绩快速做成绩排名功能。
根据点赞数展示...
例如记录帖子的点赞用户 ID 列表,评论 ID 列表,用于显示(zset同时带有排序加去重)
5、Set(集合)
典型应用场景
好友/关注/粉丝/感兴趣的人集合
随机展示