是的,Redis也有事务管理,但是功能很简单,官方开发中不推荐使用。但是面试的时候可能会被问到,所以本文简单说一下Redis事务。通过这篇文章,你会明白Redis为什么提供事务?Redis事务的基本使用说明和使用方法有哪些?什么是CAS乐观锁?为什么Redis事务不支持回滚?1、为什么要使用事务我们知道Redis的单个命令是原子的,比如get、set、mget、mset等指令。原子性意味着操作是不可分割的,在执行完成之前不会被任何其他任务或事件打断,因此不会存在并发安全问题。当涉及多个命令时,如果需要设置多个命令为不可分割的处理序列,则需要事务。比如幸运和陀螺各有100元,幸运转10元给陀螺。此时需要在Redis中将幸运充电总量减-10,同时需要将陀螺总量+10。这两个操作要么同时成功,要么同时失败,这时候就需要事务。事实上,Redis连这个简单的需求都不能完美满足。至于为什么,我们继续往下看2.事务使用2.15条基本指令Redis提供了以下5条基本指令,先熟悉一下即可。接下来结合案例进行实际操作。很难忘记。MULTIEXECDISCARDWATCHUNWATCH2.2案例演示案例场景:幸运儿和陀螺各有100元,幸运转陀螺10元。这时候就需要把运势转移到Redis中的陀螺上。同时,top的金额需要+10。2.2.1交易提交我们首先为top和fortune初始化自己的amount;然后使用MULTI命令显式打开Redis事务。此命令总是直接返回OK。此时用户可以发送多个命令,Redis不会立即执行这些命令,而是依次将这些命令放入当前事务的命令队列中;调用EXEC后,所有命令将按顺序执行。#为陀螺初始化100元127.0.0.1:6379>settuoluo100OK#为兆彩初始化100元127.0.0.1:6379>setzhaocai100OK#显式开启交易127.0.0.1:6379>MULTIOK#为陀螺添加10元127.0.0.1:6379(TX)>INCRBYtuoluo10QUEUED#减少招财10元127.0.0.1:6379(TX)>DECRBYzhaocai10QUEUED#执行交易中的所有指令(committransaction)127.0.0.1:6379(TX)>EXEC1)(integer)1102)(integer)902.2.2嵌套事务Redis不支持嵌套事务,多个MULTI命令与单个MULTI命令效果相同。#第一次开启事务127.0.0.1:6379>MULTIOK#尝试嵌套事务127.0.0.1:6379(TX)>MULTI(error)ERRMULTIcallscannotbenested#还是在第一个事务中127.0.0.1:6379(TX)>2.2.3放弃交易开始交易后中途后悔怎么办?调用DISCARD可以清空事务中的命令队列,退出事务。127.0.0.1:6379>MULTIOK#在事务中调用DISCARD命令127.0.0.1:6379(TX)>DISCARDOK#会退出当前事务127.0.0.1:6379>2.2.4watch命令事务,另一个客户端连接修改这个交易涉及变量值,会发生什么?client1开始一笔转账交易,交易开始时,招财和陀螺各有100元,在执行EXEC命令之前,client2转给陀螺的余额已经增加了10元。此时执行EXEC后,陀螺最终金额为120元,发财为90元。显然,这种情况下存在数据安全问题。为此,Redis提供了WATCH指令,可以为Redis事务提供CAS乐观锁行为,即多个连接同时更新变量时,会与变量的初始值进行比较,只有当值这个变量没有被修改。只有这样它才会更新为新值。2.2.4.1WATCH的使用对应我们的案例,我们可以使用WATCH来监控一个或多个key。如果在开始事务之前执行EXEC之前至少修改了一个被监控的key,则整个事务将被取消并直接返回nil(见下例)。UNWATCH是WATCH的逆操作。2.2.4.2CAS机制CAS(CompareAndSwap)比较和替换是多并发中常用的乐观锁技术。CAS需要三个变量信息,分别是内存位置(JAVA中的内存地址,V)、旧期望值(A)和新值(B)。执行CAS时,当且仅当V等于期望值A时,将V的值更新为新值B,否则不进行更新。3、交易执行出错怎么办?事务执行过程中可能会遇到问题。根据出现的时机,可以分为执行EXEC之前和执行EXEC之后两种。3.1执行EXEC前出现错误。错)导致无法进入命令队列,这一步主要是编译错误,还没到运行时。127.0.0.1:6379>MULTIOK127.0.0.1:6379(TX)>SETtuoluo(error)ERRwrongnumberofargumentsfor'set'command127.0.0.1:6379(TX)>EXEC(error)EXECABORT事务被丢弃,因为以前的错误。在这种情况下,事务将无法执行,队列中的所有指令都不会被执行。3.2执行EXEC后出现错误这种错误往往是类型错误,比如对String使用Hash命令,属于运行时错误,编译时不会报错127.0.0.1:6379>MULTIOK127.0.0。1:6379(TX)>SETtuoluo100QUEUED127.0.0.1:6379(TX)>LPOPtuoluoQUEUED127.0.0.1:6379(TX)>EXEC1)OK2)(error)WRONGTYPE对持有错误类型值的键的操作我们发现SETtuoluo100命令实际上执行成功了,也就是说,在异常运行的情况下,不会执行错误的命令,但不会影响其他命令。这种方式显然不符合我们对原子性的定义,即Redis事务无法实现原子性,无法保证数据的一致性。针对这个缺陷,Redis官方也做了说明。4、为什么Redis事务不支持回滚引用自Redis官方文档。为了让大家更容易理解,我翻译成:各位程序员,把我们的Redis业务关掉吧!Redis官方认为,只有当命令语法或类型错误时,Redis命令才会执行失败。而且他们认为有这种错误的语法一般不会进入生产环境。而且不支持回滚可以让他们有更多的时间去玩Redis运行起来更轻松更快。这种论证厉害了!如果问题是程序员的问题,代码写错了放到生产环境,那就加罪了,永远不要依赖Redis官方。这可能是不推荐使用Redis事务的原因。一方面,它是无味的。被官方打脸怎么办?所以稍微了解一下Redis事务的知识还是不错的,面试问的时候再回来。
