Redis事务与可分布式锁
1 Redis事务
1.1 Redis事务介绍
l Redis的事务是通过MULTI,EXEC,DISCARD和WATCH这四个命令来完成的。
l Redis的单个命令都是原子性的,所以这里确保事务性的对象是命令集合。
l Redis将命令集合序列化并确保处于同一事务的命令集合连续且不被打断的执行
l Redis不支持回滚操作
1.2 相关命令
l MULTI
用于标记事务块的开始。
Redis会将后续的命令逐个放入队列中,然后使用EXEC命令原子化地执行这个命令序列。
语法:multi
l EXEC
在一个事务中执行所有先前放入队列的命令,然后恢复正常的连接状态
语法:exec
l DISCARD
清除所有先前在一个事务中放入队列的命令,然后恢复正常的连接状态。
语法:discard
l WATCH
当某个事务需要按条件执行时,就要使用这个命令将给定的键设置为受监控的状态。
语法:watch key [key…]
注意事项:使用该命令可以实现redis的乐观锁。
l UNWATCH
清除所有先前为一个事务监控的键。
语法:unwatch
1.3 事务失败处理
l Redis语法错误(可以理解为编译期错误)
l Redis类型错误(可以理解为运行期错误)
l Redis不支持事务回滚
为什么redis不支持事务回滚?
1、大多数事务失败是因为语法错误或者类型错误,这两种错误,在开发阶段都是可以预见的
2、redis为了性能方面就忽略了事务回滚
2 Redis实现分布式锁
2.1 锁的处理
l 单应用中使用锁:单进程多线程
synchronize、Lock
l 分布式应用中使用锁:多进程
2.2 分布式锁的实现方式
l 基于数据库的乐观锁实现分布式锁
l 基于zookeeper临时节点的分布式锁
l 基于redis的分布式锁
2.3 分布式锁的注意事项
l 互斥性:在任意时刻,只有一个客户端能持有锁
l 同一性:加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。
l 可重入性:即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。
2.4 实现分布式锁
2.4.1获取锁
l 方式1(使用set命令实现) --推荐:
/** * 使用redis的set命令实现获取分布式锁 * @param lockKey 可以就是锁 * @param requestId 请求ID,保证同一性 * @param expireTime 过期时间,避免死锁 * @return */ publicstaticboolean getLock(String lockKey,String requestId,intexpireTime) { //NX:保证互斥性 String result = jedis.set(lockKey, requestId, "NX", "EX", expireTime); if("OK".equals(result)) { returntrue; } returnfalse; } |
l 方式2(使用setnx命令实现):
publicstaticboolean getLock(String lockKey,String requestId,intexpireTime) { Long result = jedis.setnx(lockKey, requestId); if(result == 1) { jedis.expire(lockKey, expireTime); returntrue; } returnfalse; } |
2.4.2释放锁
l 方式1(del命令实现):
/** * 释放分布式锁 * @param lockKey * @param requestId */ publicstaticvoid releaseLock(String lockKey,String requestId) { if (requestId.equals(jedis.get(lockKey))) { jedis.del(lockKey); } } |
l 方式2(redis+lua脚本实现)--推荐:
publicstaticboolean releaseLock(String lockKey, String requestId) { String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId)); if (result.equals(1L)) { returntrue; } returnfalse; } |
1 Redis事务
1.1 Redis事务介绍
l Redis的事务是通过MULTI,EXEC,DISCARD和WATCH这四个命令来完成的。
l Redis的单个命令都是原子性的,所以这里确保事务性的对象是命令集合。
l Redis将命令集合序列化并确保处于同一事务的命令集合连续且不被打断的执行
l Redis不支持回滚操作
1.2 相关命令
l MULTI
用于标记事务块的开始。
Redis会将后续的命令逐个放入队列中,然后使用EXEC命令原子化地执行这个命令序列。
语法:multi
l EXEC
在一个事务中执行所有先前放入队列的命令,然后恢复正常的连接状态
语法:exec
l DISCARD
清除所有先前在一个事务中放入队列的命令,然后恢复正常的连接状态。
语法:discard
l WATCH
当某个事务需要按条件执行时,就要使用这个命令将给定的键设置为受监控的状态。
语法:watch key [key…]
注意事项:使用该命令可以实现redis的乐观锁。
l UNWATCH
清除所有先前为一个事务监控的键。
语法:unwatch
1.3 事务失败处理
l Redis语法错误(可以理解为编译期错误)
l Redis类型错误(可以理解为运行期错误)
l Redis不支持事务回滚
为什么redis不支持事务回滚?
1、大多数事务失败是因为语法错误或者类型错误,这两种错误,在开发阶段都是可以预见的
2、redis为了性能方面就忽略了事务回滚
2 Redis实现分布式锁
2.1 锁的处理
l 单应用中使用锁:单进程多线程
synchronize、Lock
l 分布式应用中使用锁:多进程
2.2 分布式锁的实现方式
l 基于数据库的乐观锁实现分布式锁
l 基于zookeeper临时节点的分布式锁
l 基于redis的分布式锁
2.3 分布式锁的注意事项
l 互斥性:在任意时刻,只有一个客户端能持有锁
l 同一性:加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。
l 可重入性:即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。
2.4 实现分布式锁
2.4.1获取锁
l 方式1(使用set命令实现) --推荐:
/** * 使用redis的set命令实现获取分布式锁 * @param lockKey 可以就是锁 * @param requestId 请求ID,保证同一性 * @param expireTime 过期时间,避免死锁 * @return */ publicstaticboolean getLock(String lockKey,String requestId,intexpireTime) { //NX:保证互斥性 String result = jedis.set(lockKey, requestId, "NX", "EX", expireTime); if("OK".equals(result)) { returntrue; } returnfalse; } |
l 方式2(使用setnx命令实现):
publicstaticboolean getLock(String lockKey,String requestId,intexpireTime) { Long result = jedis.setnx(lockKey, requestId); if(result == 1) { jedis.expire(lockKey, expireTime); returntrue; } returnfalse; } |
2.4.2释放锁
l 方式1(del命令实现):
/** * 释放分布式锁 * @param lockKey * @param requestId */ publicstaticvoid releaseLock(String lockKey,String requestId) { if (requestId.equals(jedis.get(lockKey))) { jedis.del(lockKey); } } |
l 方式2(redis+lua脚本实现)--推荐:
publicstaticboolean releaseLock(String lockKey, String requestId) { String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId)); if (result.equals(1L)) { returntrue; } returnfalse; } |
Redis事务与可分布式锁的更多相关文章
- redis事务机制和分布式锁
Redis事务机制 严格意义来讲,Redis的事务和我们理解的传统数据库(如mysql)的事务是不一样的:Redis的事务实质上是命令的集合,在一个事务中要么所有命令都被执行,要么所有事物都不执行. ...
- 使用Redis SETNX 命令实现分布式锁
基于setnx和getset http://blog.csdn.net/lihao21/article/details/49104695 使用Redis的 SETNX 命令可以实现分布式锁,下文介绍其 ...
- Redis 上实现的分布式锁
转载Redis 上实现的分布式锁 由于近排很忙,忙各种事情,还有工作上的项目,已经超过一个月没写博客了,确实有点惭愧啊,没能每天或者至少每周坚持写一篇博客.这一个月里面接触到很多新知识,同时也遇到很多 ...
- 在 Redis 上实现的分布式锁
由于近排很忙,忙各种事情,还有工作上的项目,已经超过一个月没写博客了,确实有点惭愧啊,没能每天或者至少每周坚持写一篇博客.这一个月里面接触到很多新知识,同时也遇到很多技术上的难点,在这我将对每一个有用 ...
- Redis整合Spring实现分布式锁
spring把专门的数据操作独立封装在spring-data系列中,spring-data-redis是对Redis的封装 <dependencies> <!-- 添加spring- ...
- 使用Redis SETNX 命令实现分布式锁(转载)
使用Redis的 SETNX 命令可以实现分布式锁,下文介绍其实现方法. SETNX命令简介 命令格式 SETNX key value 将 key 的值设为 value,当且仅当 key 不存在. 若 ...
- 【连载】redis库存操作,分布式锁的四种实现方式[一]--基于zookeeper实现分布式锁
一.背景 在电商系统中,库存的概念一定是有的,例如配一些商品的库存,做商品秒杀活动等,而由于库存操作频繁且要求原子性操作,所以绝大多数电商系统都用Redis来实现库存的加减,最近公司项目做架构升级,以 ...
- 基于 Redis 实现简单的分布式锁
摘要 分布式锁在很多应用场景下是非常有效的手段,比如当运行在多个机器上的不同进程需要访问同一个竞争资源的时候,那么就会涉及到进程对资源的加锁和释放,这样才能保证数据的安全访问.分布式锁实现的方案有很多 ...
- 基于Redis实现简单的分布式锁【理论】
摘要 分布式锁在很多应用场景下是非常有效的手段,比如当运行在多个机器上的不同进程需要访问同一个竞争资源的时候,那么就会涉及到进程对资源的加锁和释放,这样才能保证数据的安全访问.分布式锁实现的方案有很多 ...
随机推荐
- HDU_2191_多重背包
http://acm.hdu.edu.cn/showproblem.php?pid=2191 简单多重背包题. #include<iostream> #include<cstdio& ...
- HDU6446 Tree and Permutation(树、推公式)
题意: 给一棵N个点的树,对应于一个长为N的全排列,对于排列的每个相邻数字a和b,他们的贡献是对应树上顶点a和b的路径长,求所有排列的贡献和 思路: 对每一条边,边左边有x个点,右边有y个点,x+y= ...
- layui父子页面方法互调
父级页面调用子页面方法 layer.open({ type: 2, content: 'test/iframe.html', success: function(layero, index){ var ...
- HTML5与HTML4的区别-----新增的常用标签
做前端工程师这么长时间了, 对HTML5的一些标签的用法还不是很熟悉.这篇随笔算是对学过的知识的梳理.常言道,温故而知新 ~哈哈.里面有不正确的地方还望各位大牛们指正,评论. 在做网页时习惯把网页分 ...
- 《C/C++实现Console下的加载进度条模拟[美观版]》
前言 有时候我们会遇到在CMD或DOS控制台上出现的加载进度条,虽然不是如网页和软件写的美观.但确确实实也有着自己的特色.而且,一个好看的加载进度条也能增加用户使用控制台程序的体验!所以,拿来研究 ...
- 杭电-------2098 分拆素数和(c语言写)
#include<stdio.h> #include<math.h> ] = { , }; ;//全局变量,用来标志此时已有多少个素数 int judge(int n) {// ...
- 曹工说Spring Boot源码(19)-- Spring 带给我们的工具利器,创建代理不用愁(ProxyFactory)
写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...
- Jenkins 插件使用国内镜像源-解决插件下载慢的问题
问题 我们在Jenkins里面经常会遇到安装插件很慢,这是由于我们使用的是更新中心镜像默认为国外的源.现在我们可以进行设置为国内镜像源,来解决安装插件慢的问题. 解决办法 安装插件localizati ...
- HttpMessageNotReadableException
HttpMessageNotReadableException 情况描述: spring boot web项目,尝试使用热部署工具. Controller只写了用来测试异常的方法, 异常处理器去捕获异 ...
- Centos 7 使用(Service iptables stop/start)关闭/打开防火墙 Failed to stop iptables.service: Unit iptables.service not loaded.
背景: 测试部署NetCore 项目到linux 系统时,窗口显示项目部署成功:但是本机无法访问(linux 在虚拟机上[ centos 7.6] ); 如下图↓ 能够相互ping 通,(Xshe ...