十年河东,十年河西,莫欺少年穷
学无止境,精益求精
首先说下,我的 Redis 系列博客如下:
[置顶] 高并发时,使用Redis应注意的问题【缓存穿透、缓存击穿.、缓存雪崩】
windows环境下配置Redis主从复制-一主二仆,薪火相传、反客为主、哨兵模式
Redis 持久化技术 ,大名鼎鼎的Rdb和Aof,你会选谁呢?
简单介绍下Redis消息队列,实际生产环境中,大数据高并发时,不建议使用Redis做消息队列中间件
Redis 事务,和传统的关系型数据库ACID并不同,别搞混了
Redis常用配置redis.conf介绍,别把默认配置部署到到服务器,否则,会被领导骂的
C# Nuget程序集StackExchange.Redis操作Redis 及 Redis 视频资源 及 相关入门指令 牛逼不,全都有
Window环境下安装Redis 并 自启动Redis 及 Redis Desktop Manager
进入正文
1、Redis事务是什么
首先需要说的是,Redis事务不同于传统关系型数据库的事务,也不存在ACID属性,传统关系型数据库事务对操作结果的强一致性要求很严格,事务中的操作要么全做,要么全不做。
而,Redis事务则没有那么严格的强一致性,Redis事务是将一系列的指令加入到队列中,具有一致性,排他性的执行,但在执行过程中并不保证每条指令都成功,他可能是部分成功,部分不成功,也可能是全部不成功,或者全部成功。因此,这点和传统的关系型数据库差别还是很大的。
2、Redis事务的相关指令
Redis事务有五个指令,分别为:MULTI 、 EXEC 、 DISCARD 、 WATCH、UNWATCH
用法
MULTI 命令用于开启一个事务,它总是返回 OK
。
MULTI 执行之后, 客户端可以继续向服务器发送任意多条命令, 这些命令不会立即被执行, 而是被放到一个队列中, 当 EXEC 命令被调用时, 所有队列中的命令才会被执行。
另一方面, 通过调用 DISCARD , 客户端可以清空事务队列, 并放弃执行事务。
WATCH 使得 EXEC 命令需要有条件地执行: 事务只能在所有被监视键都没有被修改的前提下执行, 如果这个前提不能满足的话,事务就不会被执行。
如果你使用 WATCH 监视了一个带过期时间的键, 那么即使这个键过期了, 事务仍然可以正常执行, 关于这方面的详细情况,请看这个帖子: http://code.google.com/p/redis/issues/detail?id=270
WATCH 命令可以被调用多次。 对键的监视从 WATCH 执行之后开始生效, 直到调用 EXEC 、DISCARD、UNWATCH 为止。
用户还可以在单个 WATCH 命令中监视任意多个键。
另外, 当客户端断开连接时, 该客户端对键的监视也会被取消。
使用无参数的 UNWATCH 命令可以手动取消对所有键的监视。 对于一些需要改动多个键的事务, 有时候程序需要同时对多个键进行加锁, 然后检查这些键的当前值是否符合程序的要求。 当值达不到要求时, 就可以使用 UNWATCH 命令来取消目前对键的监视, 中途放弃这个事务, 并等待事务的下次尝试。
redis> WATCH key1 key2 key3
OK
另外, 当客户端断开连接时, 该客户端对键的监视也会被取消。
当执行 DISCARD 命令时, 事务会被放弃, 事务队列会被清空, 并且客户端会从事务状态中退出,监视的Key也会取消。
使用无参数的 UNWATCH 命令可以手动取消对所有键的监视。 对于一些需要改动多个键的事务, 有时候程序需要同时对多个键进行加锁, 然后检查这些键的当前值是否符合程序的要求。 当值达不到要求时, 就可以使用 UNWATCH 命令来取消目前对键的监视, 中途放弃这个事务, 并等待事务的下次尝试。
OK,说了这么多理论,我来点示例来说明Redis事务。
Redis示例,【以银行信用卡场景进行模拟,总额度:Total_M,剩余额度:SY_M,账单金额:ZD_M】
首先进行各参数初始化:总额度10000元,账单金额0元,剩余额度10000元
127.0.0.1:6379> set Total_M 10000 OK 127.0.0.1:6379> set ZD_M 0 OK 127.0.0.1:6379> set SY_M 10000 OK 127.0.0.1:6379>
1、正常执行【带女票吃饭,花了500元,EXEC】
127.0.0.1:6379> MULTI OK 127.0.0.1:6379> set SY_M 9500 QUEUED 127.0.0.1:6379> set ZD_M 500 QUEUED 127.0.0.1:6379> EXEC 1) OK 2) OK 127.0.0.1:6379> get SY_M "9500" 127.0.0.1:6379> get ZD_M "500" 127.0.0.1:6379>
2、放弃事务【交易时,脑子一箱,这东西女友不喜欢,我不买了,DISCARD】
127.0.0.1:6379> MULTI OK 127.0.0.1:6379> set SY_M 9000 QUEUED 127.0.0.1:6379> set ZD_M 500 QUEUED 127.0.0.1:6379> discard OK 127.0.0.1:6379> get SY_M "9500" 127.0.0.1:6379> get ZD_M "500" 127.0.0.1:6379>
3、全体连坐【语法上有一个错误的,全部不执行】
127.0.0.1:6379> MULTI OK 127.0.0.1:6379> set k1 v1 QUEUED 127.0.0.1:6379> set k2 v2 QUEUED 127.0.0.1:6379> get k2 QUEUED 127.0.0.1:6379> set k3 v3 QUEUED 127.0.0.1:6379> getset k2 ---语法上系统直接报错了,因此会全部不执行。 (error) ERR wrong number of arguments for 'getset' command 127.0.0.1:6379> exec (error) EXECABORT Transaction discarded because of previous errors. 127.0.0.1:6379>
4、冤有头债有主【语法上系统不报错,但实际执行时行不通的】
127.0.0.1:6379> MULTI OK 127.0.0.1:6379> set K1 aa QUEUED 127.0.0.1:6379> incr K1 ----K1是字符串类型,针对字符串做加一的操作,是行不通的,因此,Redis会跳过此指令而执行其他指令, QUEUED 127.0.0.1:6379> set K2 22 QUEUED 127.0.0.1:6379> get K2 QUEUED 127.0.0.1:6379> exec 1) OK 2) (error) ERR value is not an integer or out of range 3) OK 4) "22" 127.0.0.1:6379>
5、WATCH 监控【监控一个或多个Key,当监控时,如果有外部线程更改了监控Key的值,则事务不会执行】
127.0.0.1:6379> WATCH Total_M 1、监控Total_M OK 127.0.0.1:6379> Multi 2、开启一个事务 OK 127.0.0.1:6379> set SY_M 8000 3、修改剩余额度为8000 QUEUED 127.0.0.1:6379> set ZD_M 2000 4、修改账单为2000 QUEUED 127.0.0.1:6379> get SY_M QUEUED 127.0.0.1:6379> get ZD_M QUEUED 127.0.0.1:6379> Exec 5、在最后执行之前,有外部线程修改了监控的Total_M的值,这一步相当于银行给你提升额度。 (nil) 6、由于外部进程修改了监控的Key的值,因此事务执行失败。 127.0.0.1:6379>
在最后执行之前,有外部线程修改了监控的Total_M的值,如下:
C:Userschenwolong>redis-cli 127.0.0.1:6379> ping PONG 127.0.0.1:6379> set Total_M 20000 OK 127.0.0.1:6379>
6、UnWATCH 放弃事务【使用无参数的 UNWATCH 命令可以手动取消对所有键的监视】
127.0.0.1:6379> WATCH Total_M OK 127.0.0.1:6379> Watch SY_M ZD_M OK 127.0.0.1:6379> UNWatch OK 127.0.0.1:6379>
以上便是Redsi事务,能看到这里小虎斑都是棒棒哒
@天才卧龙的博客