Redis事务机制

严格意义来讲,Redis的事务和我们理解的传统数据库(如mysql)的事务是不一样的;Redis的事务实质上是命令的集合,在一个事务中要么所有命令都被执行,要么所有事物都不执行。 
一个事务从开始到执行会经历以下三个阶段:

  1. 开始事务。
  2. 命令入队。
  3. 执行事务。

在MySQL中我们使用START TRANSACTION 或 BEGIN开启一个事务,使用COMMIT提交一个事务;而在Redis中我们使用MULTI 开始一个事务,由 EXEC 命令触发事务, 一并执行事务中的所有命令。

可以看到,MULTI 开始到 EXEC结束前,中间所有的命令都被加入到一个命令队列中;当执行 EXEC命令后,将QUEUE中所有的命令执行。

此外我们可以使用DISCARD取消事务。

需要注意的是: 
1.Redis的事务没有关系数据库事务提供的回滚(rollback),所以开发者必须在事务执行失败后进行后续的处理;

WATCH

研究过java的J.U.C包的人应该都知道CAS,CAS是一种保证原子性的操作。那么redis也提供了这样的一个机制,就是利用watch命令来实现的。

WATCH命令可以监控一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会执行,监控一直持续到EXEC命令。

分布式锁

什么是分布式锁?

分布式锁是控制分布式系统之间同步访问共享资源的一种方式。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁。

实现分布式锁有很多实现方式和工具,如Zookeeper、Redis等。

使用Redis实现分布式锁原理:

Redis为单进程单线程模式,采用队列模式将并发访问变成串行访问,且多客户端对Redis的连接并不存在竞争关系,基于此,Redis中可以使用SETNX命令实现分布式锁。

SETNX——SET if Not eXists(如果不存在,则设置):

setnx key value

将 key 的值设为 value ,当且仅当 key 不存在。 
若给定的 key 已经存在,则 SETNX 不做任何动作。

如果需要解锁,使用 del key 命令就能释放锁:

左图首先使用setnx对键加锁成功返回1,右图再次使用setnx命令对键加锁失败返回0,说明有客户端持有锁。使用del释放锁以后,右图就可以使用setnx命令对键加锁。

解决死锁

如果一个持有锁的客户端失败或崩溃了不能释放锁,该怎么解决?

答:给锁设置一个过期时间,可以通过两种方法实现:通过命令 “setnx 键名 过期时间 “;或者通过设置锁的expire时间,让Redis去删除锁(指的是键)。

第一种实现方式(有问题,语法有误): 
使用 setnx key “当前系统时间+锁持有的时间”和getset key “当前系统时间+锁持有的时间”组合的命令就可以实现。 
具体做法如下:

客户端2发送SETNX lock.test 想要获得锁,由于之前的客户端1还持有锁,所以Redis返回一个0 
客户端2发送GET lock.test 以检查锁是否超时了,如果没超时,则等待或重试。 
反之,如果已超时,客户端2通过下面的操作来尝试获得锁: 
GETSET lock.test 过期的时间 
通过GETSET,客户端2拿到的时间戳如果仍然是超时的,那就说明,客户端2如愿以偿拿到锁了。 
如果在客户端2之前,有个客户端3比客户端2快一步执行了上面的操作,那么客户端2拿到的时间戳是个未超时的值,这时,说明客户端2没有如期获得锁,需要再次等待或重试。 
尽管客户端2没拿到锁,但它改写了客户端3设置的锁的超时值,不过这一点非常微小的误差带来的影响可以忽略不计。

第二种就非常简单了: 
通过Redis中expire()给锁设定最大持有时间,如果超过,则Redis来帮我们释放锁。

1.客户端1使用setnx获得了锁,并且使用expire设定一个过期时间,假定是10ms

2.过了4ms后,客户端1不幸运的宕机了,此时客户端2想要通过setnx尝试获得锁,但是锁还没有过期,任然被客户端1所持有。

3.到了11ms时,锁过期了,Redis帮我们删除了锁,此时客户端2想要通过setnx尝试获得锁,此时就能成功获得锁。

在实际过程中,我们可以设定一个时间T,用来表示客户端在初次尝试获得锁失败以后,在多次尝试获得锁所花的时间。如果次时间为0,表示除此尝试获得锁失败以后就不会再去尝试获得锁了。

redis事务机制和分布式锁的更多相关文章

  1. 【连载】redis库存操作,分布式锁的四种实现方式[三]--基于Redis watch机制实现分布式锁

    一.redis的事务介绍 1. Redis保证一个事务中的所有命令要么都执行,要么都不执行.如果在发送EXEC命令前客户端断线了,则Redis会清空事务队列,事务中的所有命令都不会执行.而一旦客户端发 ...

  2. Redis事务与可分布式锁

    1    Redis事务 1.1   Redis事务介绍 l  Redis的事务是通过MULTI,EXEC,DISCARD和WATCH这四个命令来完成的. l  Redis的单个命令都是原子性的,所以 ...

  3. REDIS 事务机制

    基本事务操作: 任何数据库都必须要保证一种原子执行操作:最基本的原子执行操作肯定是需要提供: 举一个例子来说明: 当对某个Key 做一个统计: 可能不同的Client做它那部分的统计,一段时间后,服务 ...

  4. 使用Redis SETNX 命令实现分布式锁

    基于setnx和getset http://blog.csdn.net/lihao21/article/details/49104695 使用Redis的 SETNX 命令可以实现分布式锁,下文介绍其 ...

  5. Redis整合Spring实现分布式锁

    spring把专门的数据操作独立封装在spring-data系列中,spring-data-redis是对Redis的封装 <dependencies> <!-- 添加spring- ...

  6. 使用Redis SETNX 命令实现分布式锁(转载)

    使用Redis的 SETNX 命令可以实现分布式锁,下文介绍其实现方法. SETNX命令简介 命令格式 SETNX key value 将 key 的值设为 value,当且仅当 key 不存在. 若 ...

  7. 【连载】redis库存操作,分布式锁的四种实现方式[一]--基于zookeeper实现分布式锁

    一.背景 在电商系统中,库存的概念一定是有的,例如配一些商品的库存,做商品秒杀活动等,而由于库存操作频繁且要求原子性操作,所以绝大多数电商系统都用Redis来实现库存的加减,最近公司项目做架构升级,以 ...

  8. Redis、Zookeeper实现分布式锁——原理与实践

    Redis与分布式锁的问题已经是老生常谈了,本文尝试总结一些Redis.Zookeeper实现分布式锁的常用方案,并提供一些比较好的实践思路(基于Java).不足之处,欢迎探讨. Redis分布式锁 ...

  9. Redis 上实现的分布式锁

    转载Redis 上实现的分布式锁 由于近排很忙,忙各种事情,还有工作上的项目,已经超过一个月没写博客了,确实有点惭愧啊,没能每天或者至少每周坚持写一篇博客.这一个月里面接触到很多新知识,同时也遇到很多 ...

随机推荐

  1. 网络编程之NIO

    传统的BIO(Blocking IO)的缺点: 1.基于阻塞式IO建立起来的,导致服务端一直阻塞等待着客户端发起请求,如果客户端不发起,服务端的的业务线程会一直存. 2.弹性伸缩能力差,线程数和客户端 ...

  2. lua table vs closure

    最近在重构自己写的框架中的定时器模块,需要把回调函数保存起来,大概如下: function timer_mgr:save_timer( this,callback ) return { this = ...

  3. Browser Security-超文本标记语言(HTML)

    Browser Security-超文本标记语言(HTML) 瞌睡龙 · 2013/06/19 18:55 重要的4个规则: 1 &符号不应该出现在HTML的大部分节点中. 2 尖括号< ...

  4. Hive2.0常用函数(对编辑器很无语😓)

    Hive内部提供了很多函数给开发者使用,包括数学函数,类型转换函数,条件函数,字符函数,聚合函数,表生成函数等等,这些函数都统称为内置函数. 参考:https://cwiki.apache.org/c ...

  5. C#DataGrid列值出现E形式的小数,将DataGrid表格上的数据保存至数据库表时会因格式转换不正确导致报错

    问题描述:在DataGridView中调整金额一列,当输入小数0.000001后会显示1E-6,此时进行保存操作时报错,提示无法将string类型转换成Decimal 原因分析:由于列调整金额为1E- ...

  6. input子系统驱动

    input子系统驱动 框架分析 核心层 文件为:/drivers/input/input.c: 首先找到入口函数为**static int __init input_init(void)**,在该函数 ...

  7. Android使用WebView打包网页成app

    原生app的开发成本和网页相比相对较高,所以越来越多的app使用网页来作为界面,甚至完全将一个网站封装成app,可以提高开发速度,还能基本实现跨平台. 下面以Android为例,在ubuntu-14. ...

  8. Python&Selenium 数据驱动【unittest+ddt+xml】

    一.摘要 本博文将介绍Python和Selenium做自动化测试的时候,基于unittest框架,借助ddt模块使用xml文件作为数据文件作为测试输入 二.xml文件 <?xml version ...

  9. python批量下载邮件附件

    背景 由于同学每周要通过邮箱收数学建模作业,100多人给她发附件,她要一个个地点着下载. 太麻烦了,所以想用程序实现下载附件的功能. 在网上查资料后,最终实现了稍为简单的下载附件功能,代码有些细节还不 ...

  10. python: json模块 --JSON编码和解码

    json 源代码: Lib/json/__init__.py json.dump() import json numbers = [1, 2, 3, 4] with open('linshi.py', ...