hash redis springboot_Redis常见的工作场景使用实战,Redisson分布式锁的实现
迎关注我的头条号:Wooola,10 年 Java 软件开发及架构设计经验,专注于 Java、Go 语言、微服务架构,致力于每天分享原创文章、快乐编码和开源技术。
前言
本项目基于springboot+ spring-boot-starter-data-redis+redisson
简单的redis demo可以参考:SpringBoot整合redis
https://www.jianshu.com/p/8e71737a1101
github地址:
Redisson:https://github.com/weiess/redis-and-Redisson.git
源码地址:https://github.com/weiess/redis-and-Redisson.git
redis大家工作的时候都很多,笔者根据自己经验总结下redis的几个数据类型,常用场景,也欢迎大家留言总结自己的经验。
hash
hash在redis里可以存储对象,当然string也可以,只不过hash相比较string,效率更高一点,而且功能也很强大,可以实现简单的购物车:
下面先给大家看下简单的存储对象hash实现:
/* * hash实现存储对象 * */ @Test public void testHsetpojo(){ User user = new User(); user.setId(123); user.setAge(20); user.setAddr("北京"); user.setName("yang"); Map map = BeanUtils.beanToMap(user); String key = "user"; redisUtil.hmset(key,map); System.out.println(redisUtil.hmget(key)); System.out.println("id="+redisUtil.hget(key,"id")); String key2 = "user:"+user.getId(); redisUtil.hmset(key2,map); System.out.println(redisUtil.hmget(key2)); }
这里的redisUtil是笔者封好的工具类,源码在文章最底下。
hash存储对象的时候可以把user当作key,例如代码中的key,因为hash是 key item value三种结构,可以把后面的item和value看成一个map,这样结构就是key map,方便理解。
实际项目中可以给key加个标示符,比如key = userId:a123456,这个大家可以根据项目来定义。
可以用hash实现购物车功能:
例如:
hash.jpg
代码如下:
/* * hash实现购物车 * */ @Test public void testcar(){ String key ="carUser:123456"; redisUtil.del(key); Map map = new HashMap(); map.put("book:a11111",1); map.put("book:a11112",2); map.put("book:a11113",3); boolean b = redisUtil.hmset(key,map); System.out.println("key = "+redisUtil.hmget(key)); //增加book:a11111的数量 redisUtil.hincr(key,"book:a11111",1); System.out.println(redisUtil.hmget(key)); //减少book:a11112的数量 redisUtil.hincr(key,"book:a11112",-3); //或者redisUtil.hdecr(key,"book:a11111",1); System.out.println(redisUtil.hmget(key)); //获取所有key1的field的值 System.out.println("hegetall="+redisUtil.hmget(key)); //获取key下面的map数量 System.out.println("length="+redisUtil.hlen(key)); //删除某个key下的map redisUtil.hdel(key,"book:a11112"); System.out.println(redisUtil.hmget(key)); }
hash里的key就是当前用户的购物车,map就是商品(map里的key是商品id,map的v是数量)
功能实现注释都有。注意这里的减操作是可以为负数的,所以大家一定要注意判断负数的情况。
list
常见的list可以分为下面三个数据结构方便大家理解:
stack(栈)= LPUSH + LPOP Queue(队列)= LPUSH + RPOP BlockingMQ(阻塞队列)= LPUSH + BRPOP
@Test public void testList(){ String key = "a123456"; redisUtil.del(key); String v1 = "aaaaa"; String v2 = "bbbbb"; String v3 = "ccccc"; List list = new ArrayList(); list.add(v1); list.add(v2); list.add(v3); boolean b1 = redisUtil.lSet(key,list); System.out.println(redisUtil.lGet(key,0,-1)); System.out.println(redisUtil.lGetIndex(key,0)); System.out.println(redisUtil.lpop(key)); System.out.println(redisUtil.rpop(key)); System.out.println(redisUtil.lGet(key,0,-1)); redisUtil.del(key); redisUtil.rpush(key,v1); System.out.println(redisUtil.lGet(key,0,-1)); redisUtil.rpush(key,v2); System.out.println(redisUtil.lGet(key,0,-1)); redisUtil.lpush(key,v3); System.out.println(redisUtil.lGet(key,0,-1)); }
实际工作中常用于消息推送,比如vx订阅号推送,微博推送
代码实现:
@Test public void testVX(){ String key = "VXuser:a123456"; redisUtil.del(key); String message1 = "a1"; String message2 = "b2"; String message3 = "c3"; //订阅号a发表了一片文章,文章id是a1 redisUtil.lpush(key,message1); //订阅号b发表了一片文章,文章id是b2 redisUtil.lpush(key,message2); //订阅号b发表了一片文章,文章id是c3 redisUtil.lpush(key,message3); //用户获取 System.out.println(redisUtil.lGet(key,0,-1)); }
比如user:a23456订阅了这个订阅号a,订阅号a写了一片内容,只需要加入user:a123456的队列中,user就能查看到,这里的redisUtil.lGet(key,0,-1)表示获取key下的所有v。
set
set常用于一些数学运算,他有求交集,并集,差集的功能:
@Test public void testset(){ String key1 = "a1"; redisUtil.del(key1); String key2 = "a2"; redisUtil.del(key2); redisUtil.sSet(key1,1,2,3,4,5); System.out.println("key1="+redisUtil.sGet(key1)); redisUtil.sSet(key2,1,2,5,6,7); System.out.println("key1="+redisUtil.sGet(key2)); //获取key的数量 System.out.println("length="+redisUtil.sGetSetSize(key1)); //取key1和key2的交集 System.out.println("交集="+redisUtil.sIntersect(key1,key2)); //取key1和key2的差集 System.out.println("差集="+redisUtil.sDifference(key1,key2)); //取key1和key2的并集 System.out.println("并集="+redisUtil.sUnion(key1,key2)); //取key1的随机一个数 System.out.println("随机数="+redisUtil.sRandom(key1)); System.out.println("key1="+redisUtil.sGet(key1)); //取key1的随机一个数,并且这个值在key中删除 System.out.println("随机数="+redisUtil.spop(key1)); System.out.println("key1="+redisUtil.sGet(key1)); }
实际工作中可以实现抽奖,共同关注,推荐好友等功能:
@Test public void testSet2(){ String key ="act:123456"; redisUtil.del(key); long l = redisUtil.sSet(key,"a1","a2","a3","a4","a5"); System.out.println(redisUtil.sGet(key)); //抽奖 System.out.println(redisUtil.spop(key)); String user1 = "vxuser:a123456"; String user2 = "vxuser:b123456"; String user3 = "vxuser:c123456"; String user4 = "vxuser:d123456"; String user5 = "vxuser:e123456"; String user6 = "vxuser:f123456"; redisUtil.del("gzuser1"); redisUtil.del("gzuser2"); //gzuser1关注user2,user3,user6 redisUtil.sSet("gzuser1",user2,user3,user6); //gzuser2关注user1,user3,user4,user5 redisUtil.sSet("gzuser2",user1,user3,user4,user5); //共同好友 System.out.println("共同好友"+redisUtil.sIntersect("gzuser1","gzuser2")); //你关注的好友也关注了他 Set set = redisUtil.sUnion(user1,user2); //这里取并集,放在中间表bj里 for (String s:set){ redisUtil.sSet("bj",s); } System.out.println(redisUtil.sGet("bj")); System.out.println("你关注的好友也关注了他"+redisUtil.sDifference("bj","gzuser1")); }
zset
zset相比较set一个有序,一个无序,具体功能大同小异,我就不多说。
string
简单的string基本功能我就不多说了,这里要说的是分布式常见的setnx命令实现分布式锁:
setnx命令其实表示『SET if Not eXists』(如果不存在,则 SET)的简写。设置成功,返回 1 ;设置失败,返回 0 。
如果set 的key已经在redis里了,你再setnx,就会失败,但是你继续用set命令,是会覆盖当前的key,且返回成功。
/* * setnx 实现最简单的分布式锁 * */ @Test public void setlock() { DefaultRedisScript script = new DefaultRedisScript(); script.setScriptSource(new ResourceScriptSource(new ClassPathResource("lua/deleteLua.lua"))); script.setResultType(Long.class); String key ="product:001"; String value = Thread.currentThread().getId()+""; try { boolean result = redisUtil.setnx(key,value,100); if(!result){ System.out.println("系统繁忙中"); } else { System.out.println("这里是你业务代码"); } }catch (Exception e){ e.printStackTrace(); }finally { Object result = redisUtil.execute(script,Collections.singletonList(key),value); System.out.println(result);// if (value.equals(redisUtil.get(key))){// redisUtil.del(key); } } }
这是最简单的分布式锁实现,我给大家简单解释下:
首先,DefaultRedisScript这个类是为了读取lua脚本,这里笔者的finally代码块用了lua脚本删除redis的key,其实
Object result = redisUtil.execute(script,Collections.singletonList(key),value);
这行代码等价于下面这行代码
if (value.equals(redisUtil.get(key))){ redisUtil.del(key); }
为什么要用lua脚本呢,更多的是为了原子性,如果用if操作,要执行两部,在大型的环境下很容易出问题,而lua脚本就不会,他把两个步骤合成一个步骤去执行,这样保证原子性。
hash redis springboot_Redis常见的工作场景使用实战,Redisson分布式锁的实现相关推荐
- Redis实战——Redisson分布式锁
目录 1 基于Redis中setnx方法的分布式锁的问题 2 Redisson 2.1 什么是Redisson 2.2 Redisson实现分布式锁快速入门 2.3 Redisson 可重入锁原理 什 ...
- Redis:Redisson分布式锁的使用(推荐使用)
Redis:Redisson分布式锁的使用(生产环境下)(推荐使用) 关键词 基于NIO的Netty框架,生产环境使用分布式锁 redisson加锁:lua脚本加锁(其他客户端自旋) 自动延时机制:启 ...
- Redis进阶- Redisson分布式锁实现原理及源码解析
文章目录 Pre 用法 Redisson分布式锁实现原理 Redisson分布式锁源码分析 redisson.getLock(lockKey) 的逻辑 redissonLock.lock()的逻辑 r ...
- redis redisson 分布式锁 WRONGTYPE Operation against a key holding the wrong kind of value
在使用redisson加锁的时候报错如下 trylock WRONGTYPE Operation against a key holding the wrong kind of value 错误场景: ...
- SpringBoot实战实现分布式锁一之重现多线程高并发场景
实战前言:上篇博文我总体介绍了我这套视频课程:"SpringBoot实战实现分布式锁" 总体涉及的内容,从本篇文章开始,我将开始介绍其中涉及到的相关知识要点,感兴趣的小伙伴可以关注 ...
- 用分布式锁来防止库存超卖,但是是每秒上千订单的高并发场景,如何对分布式锁进行高并发优化来应对这个场景?
用分布式锁来防止库存超卖,但是是每秒上千订单的高并发场景,如何对分布式锁进行高并发优化来应对这个场景? 转载 codeing_doc 最后发布于2018-11-23 09:44:41 阅读数 1073 ...
- redis ,redisson 分布式锁深入剖析
目录 为什么要用分布式锁? 分布式锁所遵循的原则? redis 分布式锁 redis 原始分布式锁实现 加锁 释放锁 redis 分布式锁存在的问题 redisson 实现分布式锁 redisson ...
- Redisson分布式锁实战(适用于Redis高并发场景)
实现方式一:存在抛异常后lock值无法归0的问题 @Autowired private StringRedisTemplate stringRedisTemplate;@RequestMapping( ...
- 顶级“Redis学习笔记”,缓存雪崩+击穿+穿透+集群+分布式锁,NB了
如果你是一位后端工程师,面试时八成会被问到 Redis,特别是那些大型互联网公司,不仅要求面试者能简单使用 Redis,还要深入理解其底层实现原理,具备解决常见问题的能力.可以说,熟练使用 Redis ...
最新文章
- 关于CENTOS6.X下修改网卡名称的方法
- 笔记-项目范围管理-工作说明书与项目范围说明书的区别
- WebLogic下载地址
- 支持Windows 7的CAD—AutoCAD Civil 3D 2010
- app把信息添加到mysql_如何将数据库表中的数据添加到ListView C#Xamarin Android App
- lambda 使用_如何使用Lambda和API网关构建API
- 778. 水位上升的泳池中游泳
- python动态变量名_python实现可变变量名方法详解
- 频率分布直方图组距如何确定_频率分布有关的概念
- HttpRunnerManager接口自动化测试框架在win环境下搭建教程
- C#中Socket用法,多个聊天和单一聊天。
- ORACLE 9 默认密码
- EmguCv模板匹配学习日记
- 对计算机科学的总体认识,浅谈对计算机科学与技术的认识
- 2022年证券大宗交易研究报告
- Detach Procedure
- 论文笔记:HIE-SQL:History Information Enhanced Network for Context-Dependent Text-to-SQL Semantic Parsing
- rtmp断线重连_rtsp转rtmp rtsp2rtmp 同时16路视频 rtmp推流器 支持ipc dvr nvr
- Settings Preference 的理解
- Android两个app间跳转-deepLink的使用
热门文章
- 如何使用代码创建service contract并实现partner determination
- SAP WebIDE 是如何加载SAP UI5里自定义的XML view的 - JerryMaster.view.xml
- 处理SAP gateway service使用过程中遇到的400 error - Malformed URI literal syntax
- PHP CLI应用的调试原理
- 使用javap分析Java的字符串操作
- 如何使用SAP CRM Marketing Survey创建一个市场问卷调查
- paraView做动画(终极教程)
- php代码执行相关函数,关于当前PHP脚本运行时系统信息相关函数
- 一个点是否在矩形内的算法_478,回溯算法解单词搜索
- 二维碰撞检测matlab,二维平面内的碰撞检测【二】