Jedis是Java中操作redis的一个客户端,类似通过jdbc访问mysql数据库。
一、基本操作
1.添加pom依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
2.测试连接
@Test
public void testGetConnection(){
Jedis jedis = new Jedis("192.168.126.129",6379);
//jedis.auth("密码") 数据库有密码的话执行它
String ping = jedis.ping();
System.out.println(ping);
}
}
3.String类型练习
@Test
public void testStringOper() throws InterruptedException {
//建立链接(与redis建立链接)
Jedis jedis=new Jedis("192.168.126.130",6379);
//存储数据(key/value)
jedis.set("count","1");
jedis.set("id","10001");
jedis.set("content","aaaaaaaadfas");
//更新数据
jedis.expire("id",1);//设置key的有效时长
jedis.incr("count");//对key的值进行自增操作
//获取数据
String count = jedis.get("count");
//TimeUnit是Java中枚举类型,SECONDS为枚举类型的实例,sleep底层会调用Thread.sleep()方法
//TimeUnit.SECONDS.sleep(1);//休眠一秒
Thread.sleep(1000);
String id=jedis.get("id");
Long num=jedis.strlen("content");
System.out.println("cart.count="+count);
System.out.println("id="+id);
System.out.println("num="+num);
//释放资源
jedis.close();
}
//json数据练习
@Test
public void testJsonOper(){
//构建对象
Map<String,Object> map=new HashMap<>();
map.put("id",100);
map.put("title","spring 认证");
map.put("content","very good");
//将对象转换为json格式字符串
Gson gson=new Gson();
String jsonStr=gson.toJson(map);
//将json字符串写入到redis
Jedis jedis=new Jedis("192.168.126.128",6379);
jedis.set("user",jsonStr);
//读取redis中数据
jsonStr=jedis.get("user");
System.out.println(jsonStr);
Map<String,Object> obj=gson.fromJson(jsonStr,Map.class);
System.out.println(obj);
jedis.close();
}
这样情况下的修改太麻烦了,还需要把把json串再次转化为map对象再修改再改回去,所以一般不用这个,我们用Hash
4.Hash类型练习
@Test
public void testHashOper01(){
//1.建立连接
Jedis jedis=new Jedis("192.168.126.130",6379);
//2.基于hash类型存储对象信息
jedis.hset("member","id","101");
jedis.hset("member","username","jack");
jedis.hset("member","mobile","3333333");
//3.更新hash类型存储的数据
jedis.hset("member","username","tony");
//4.获取hash类型数据信息
String username=jedis.hget("member","username");
String mobile = jedis.hget("member", "mobile");
System.out.println(username);
System.out.println(mobile);
//5.释放资源
jedis.close();
}
//hash类型练习(直接存储map对象)
@Test
public void testHashOper02(){
//1.建立连接
Jedis jedis=new Jedis("192.168.126.130",6379);
//2.存储一篇博客信息
Map<String,String> map=new HashMap<>();
map.put("x","100");
map.put("y","200");
jedis.hset("point",map);
//3.获取博客内容并输出
map=jedis.hgetAll("point");
System.out.println(map);
//4.释放资源
jedis.close();
}
5.List类型练习
模拟先进先出队列
@Test
public void testListOper01(){
//1.连接
Jedis jedis = new Jedis("192.168.126.129", 6379);
jedis.flushAll();
//2.存储
jedis.lpush("list1", "A","B","C","C");
//3.修改
Long index = jedis.lpos("list1", "A");
jedis.lset("list1", index, "D");
// Long Cindex = jedis.lpos("list1", "C");
//4.删除
jedis.rpop("list1",1);
//5.查询
System.out.println(jedis.lrange("list1", 0, -1));
//6.释放
jedis.close();
}
模拟阻塞式队列
@Test
public void testListOper02(){
//1.连接
Jedis jedis = new Jedis("192.168.126.129", 6379);
jedis.flushAll();
//2.存储
jedis.lpush("list2", "A","B","C");
//3.基于阻塞方式取数据
System.out.println(jedis.brpop(20, "list2"));
System.out.println(jedis.brpop(20, "list2"));
System.out.println(jedis.brpop(20, "list2"));
System.out.println(jedis.brpop(20, "list2"));
//4.释放
jedis.close();
}
list取完为空时,运行不会停止,进入等待状态,cpu使用权转移,当集合里出现了新的内容或者等待超时时会自动停止运行
6.Set类型练习
@Test
public void testSetOper01() {
//1.连接redis
Jedis jedis = new Jedis("192.168.126.128", 6379);
//2.朋友圈点赞
jedis.sadd("count", "1", "1", "2");
//3.取出点赞数
Set<String> set = jedis.smembers("count");
System.out.println(set);
//4.释放资源
jedis.close();
}
这样的操作的问题在于频繁的连接和释放资源会对性能有所下降,我们可以利用池的概念创建一个Redis连接池
二、连接池
public void testJedisPool(){
//0.构建连接池配置
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(16);//最大连接数默认为8
config.setMaxIdle(60);//最大空闲时间,超时后会释放连接
final String IP="192.168.126.129";
final int PORT=6379;
//1.构建jedis连接池
JedisPool jedisPool = new JedisPool(config, IP, PORT);
//2.从池中获取连接
Jedis resource = jedisPool.getResource();
//3.执行redis操作
resource.set("pool", "JedisPool");
String pool = resource.get("pool");
System.out.println(pool);
//4.释放(不是关闭,而是将连接还回池中)
resource.close();
//5.关闭连接池(一般不关,服务停止时才关)
//jedisPool.close();
}
我们可以创建一个数据源,将来直接调用获取连接就好了
public class JedisDataSource {
final static String IP="192.168.126.129";
final static int PORT=6379;
private static final JedisPool jedisPool;
static {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxIdle(60);
config.setMaxTotal(16);
jedisPool = new JedisPool(config, IP, PORT);
}
public static Jedis getConnection(){
return jedisPool.getResource();
}
public static JedisPool getJedisPool() {
return jedisPool;
}
}
三、实战练习Demo
1.投票系统简易设计
public class VoteDemo01 {
final static String IP="192.168.126.129";
final static int PORT=6379;
/*投票*/
static void doVote(String activityId,String userId){
//1.创建jedis对象
Jedis jedis = new Jedis(IP, PORT);
//2.投票
jedis.sadd(activityId, userId);
//3.释放
jedis.close();
}
/*查看活动投票数量*/
static Long doGetVotes(String activityId){
//1.创建jedis对象
Jedis jedis = new Jedis(IP, PORT);
//2.查看活动的投票数
Long count = jedis.scard(activityId);
//3.释放
jedis.close();
return count;
}
/*获取参与投票的用户*/
static Set<String> doGetUsers(String activityId){
//1.创建jedis对象
Jedis jedis = new Jedis(IP, PORT);
//2.查看参与投票的用户
Set<String> smembers = jedis.smembers(activityId);
//3.释放
jedis.close();
return smembers;
}
/*检查是否参与过投票*/
static Boolean isVote(String activityId,String userId){
//1.创建jedis对象
Jedis jedis = new Jedis(IP, PORT);
//2.检查是否参与投票
Boolean flag = jedis.sismember(activityId, userId);
//3.释放
jedis.close();
return flag;
}
public static void main(String[] args) {
//1.定义活动ID,用户ID
String user1="yjh";
String user2="zzf";
String activityId="1001";
//2.投票检查
Boolean flag = isVote(activityId, user1);
//3.投票
if (flag==true){
System.out.println("已经投过了,换个人再来把");
return;
}
doVote(activityId, user1);
doVote(activityId, user2);
//4.查看投票总数
Long aLong = doGetVotes(activityId);
System.out.println(activityId+"号的投票总数为:"+aLong);
//5.获取参与投票用户
Set<String> users = doGetUsers(activityId);
System.out.println("参与"+activityId+"活动的投票用户为"+users);
}
}
2.分布式ID生成策略
//分布式ID生成策略
public class IdGenerator {
/*每次调用此方法都可以得到一个唯一的递增的整数值*/
public static Long getId(){
Jedis jedis = new Jedis("192.168.126.129",6379);
Long id = jedis.incr("id");
jedis.close();
return id;
}
public static void main(String[] args) {
for (int i=0;i<10;i++){
new Thread(){
@Override
public void run(){
System.out.println(IdGenerator.getId());
}
}.start();
}
}
}
3.购物车简易实现
/*性能高于数据安全可以存储到redis*/
public class CartDemo01 {
final static String IP="192.168.126.129";
final static int PORT=6379;
//添加商品
//修改商品数量
static void doAddCart(String userId,String productId,int num){
//1.创建Jedis对象
Jedis jedis = new Jedis(IP, PORT);
//2.基于hash存储商品信息
jedis.hincrBy("cart:"+userId, productId, num);
//3.释放
jedis.close();
}
//查看购物车商品
static Map<String, String> doViewCart(String userId){
//1.创建Jedis对象
Jedis jedis = new Jedis(IP, PORT);
//2.查看购物车信息
Map<String, String> cart = jedis.hgetAll("cart:" + userId);
//3.释放
jedis.close();
return cart;
}
//清空购物车
static void delAll(String userId){
//1.创建Jedis对象
Jedis jedis = new Jedis(IP, PORT);
//2.设置有效期为0
jedis.expire("cart:"+userId, 0);
//3.释放
jedis.close();
}
//删除购物车商品
/*
*用连接池获取连接
* */
static void delCart(String userId,String... productId){
//1.创建Jedis对象
Jedis jedis = JedisDataSource.getConnection();
//2.删除
jedis.hdel("cart:" + userId, productId);
//3.释放
jedis.close();
}
public static void main(String[] args) {
String userId="yjh";
//1.购买商品时,将商品信息添加到购物车
doAddCart(userId, "201",1);
doAddCart(userId, "202",2);
doAddCart(userId, "203",3);
//2.修改购物车商品数量
doAddCart(userId, "201",2);
doAddCart(userId, "202",1);
doAddCart(userId, "203",7);
//3.查看购物车商品
Map<String, String> cart = doViewCart(userId);
System.out.println(cart);
//4.删除购物车商品
delCart(userId, "203");
System.out.println(doViewCart(userId));
//5.清空购物车
delAll(userId);
System.out.println(doViewCart(userId));
}
}
4.抢购秒杀队列
算法:FIFO
逻辑:生产者(购买商品的用户):创建请求并将请求存储到队列 消费者(处理购买请求的底层对象):从队列取请求,然后处理请求
public class SecondsKillDemo01 {
/**
* 入队操作
*/
public static void enque(String request){
Jedis jedis=new Jedis("192.168.126.129", 6379);
jedis.lpush("queue-1",request);
jedis.close();
}
/**
* 出队操作
*/
public static String deque(){
Jedis jedis=new Jedis("192.168.126.129", 6379);
//非阻塞式取数据
//return jedis.rpop("queue-1");
//阻塞式取数据
List<String> list = jedis.brpop(3, "queue-1");
jedis.close();
return list!=null?list.get(1):null;//0为key
}
public static void main(String[] args) {
//1.构建生产对象(购买商品的用户)
Thread t1=new Thread(){
@Override
public void run() {
for(int i=1;i<=10;i++){
enque("request-"+i);
}
}
};
//2.构建消费者对象(处理请求的对象)
Thread t2=new Thread(){
@Override
public void run() {
for(;;){
String request=deque();
if(request==null)continue;
System.out.println("process "+request);
}
}
};
//3.开启抢购活动
t1.start();
t2.start();
}
}
5.简易单点登录
方案一
/**
* SSO(单点登录系统) 案例演示:
* 1)访问资源(假如没有登录,要提示先登录,如何判定是否登录了)
* 2)执行登录(登录成功,存储用户登录信息)
* 3)访问资源(已登录)
* 解决方案
* 1)方案1:SpringSecurity+jwt+oauth2 (并发比较大)
* 2)方案2:SpringSecurity+redis+oauth2 (中小型并发)
*
*/
public class SSODemo01 {
/**认证中心的登录设计*/
static String doLogin(String username,String password){
//1.执行用户身份校验
if(!"jack".equals(username))//将来这个jack来自数据库
throw new IllegalArgumentException("这个用户不存在");
//2.用户存在并且密码正确,表示用户是系统的合法用户
if(!"123456".equals(password))
throw new IllegalArgumentException("密码不正确");
//3.将合法用户信息存储到redis
Jedis jedis=new Jedis("192.168.126.129", 6379);
String token=UUID.randomUUID().toString();
jedis.set(token,username);
jedis.expire(token, 2);
jedis.close();
return token;//token
}
/**获取资源服务中的资源*/
static Object doGetResource(String token){
//1.检查用户是否已经登录
if(token==null||"".equals(token))
throw new IllegalArgumentException("请先登录");
Jedis jedis=new Jedis("192.168.126.129", 6379);
String username=jedis.get(token);
jedis.close();
//2.假如没有登录,则提示先登录
if(username==null)
throw new RuntimeException("登录超时或token无效,请重新登录");
//3.已登录则可以访问资源
System.out.println("继续访问资源");
//.....
return "the resource of user";
}
//假设这里的main方法为客户端
public static void main(String[] args) throws InterruptedException {
String token=null;
//第一次访问资源
// doGetResource(token);
//执行登录操作(将来认证要在认证中心实现)
token=doLogin("jack", "123456");
//第二次访问资源
doGetResource(token);
}
}
方案二
public class SSODemo02 {
/**认证中心的登录设计*/
static String doLogin(String username,String password){
//1.执行用户身份校验
if(!"jack".equals(username))//将来这个jack来自数据库
throw new IllegalArgumentException("这个用户不存在");
//2.用户存在并且密码正确,表示用户是系统的合法用户
if(!"123456".equals(password))
throw new IllegalArgumentException("密码不正确");
//3.将合法用户信息存储到redis
Jedis jedis=new Jedis("192.168.126.129", 6379);
String token=UUID.randomUUID().toString();
jedis.hset(token,"username",username);
jedis.hset(token, "status", "1");
//....
jedis.expire(token, 2);
jedis.close();
return token;//token
}
/**获取资源服务中的资源*/
static Object doGetResource(String token){
//1.检查用户是否已经登录
if(token==null||"".equals(token))
throw new IllegalArgumentException("请先登录");
Jedis jedis=new Jedis("192.168.126.129", 6379);
Map<String,String> map=jedis.hgetAll(token);
jedis.close();
//2.假如没有登录,则提示先登录
if(map==null||map.isEmpty())
throw new RuntimeException("登录超时或token无效,请重新登录");
//3.已登录则可以访问资源
System.out.println("继续访问资源");
//.....
return "the resource of user";
}
//假设这里的main方法为客户端
public static void main(String[] args) throws InterruptedException {
String token=null;
//第一次访问资源
// doGetResource(token);
//执行登录操作(将来认证要在认证中心实现)
token=doLogin("jack", "123456");
//第二次访问资源
doGetResource(token);
}