MySQL
事务:
相比于 MySQL
来说,Redis
的事务就是个弟弟:
Redis
的事务,到底有没有原子性?存在争议 Redis
做到了上述的含义,但是 MySQL
这里的原子性走的更远 MySQL
也是把多个操作打包到一起,要么全都执行成功,要么都不执行。如果事务中有操作执行失败的,就要进行回滚,把中间已经执行的操作,全部回退Redis
事务中的如干操作,要是有失败的,无所谓。Redis
把多个操作打包到一起执行,已经可以称为是原子性了,只是 MySQL
标杆,提高了“原子性”门槛,这就使人们谈到原子性的时候,更多的想到的是 MySQL
这样带回滚的原子性
所以,一般说到 Redis
的事务有没有原子性,更多的倾向于没有(或者弱化的原子性)
Redis
没有约束,也没有回滚机制,事务执行过程中如果某个修改操作出现失败,就可能引起不一致的情况
Redis
事务不具备一致性reids
本身就是内存数据库,数据是存储在内存中的,虽然 Redis
也有持久化机制(AOF
),但这里的持久化机制和事务没有什么关系
MySQL
那边,事务百分百有持久性,Redis
这边把持久化机制关了。这是不一样的Redis
事务不具备持久性Redis
是一个单线程模型的服务器程序,所有的请求/事务都是“串行”执行的。而谈到隔离性,都是并发执行才会涉及到的
Redis
事务不涉及隔离性Redis
事务,主要的意义就是为了“打包”,避免其他客户端的命令,插队插到中间
Redis
中实现事务,是引入了一个队列(每个客户端都有一个)Redis
主线程中完成的,主线程会把事务中的操作都执行完,再处理别的客户端Redis
的事务为什么就设计的这么简单,而不设计成和 MySQL
一样强大呢?
MySQL
的事务,在背后付出了很大的代价 正是因为 MySQL
上述的问题,才有 Redis
上场的机会(简单高效的优势)
什么时候需要用到 Redis
事务呢?
比如一个商品秒杀出售场景:
一个货品 A,进行秒杀出售,市场火爆。此时最重要的就是不能出现“超卖”的情况(超卖:放货 5000 台,卖出了 5001 台)
一个典型的程序写法:
获取仓库中剩余的商品个数
if(个数 > 0) {
下单成功;
个数--;
}
下单成功
和 个数--
这两个操作是原子的 Redis
中,就直接使用事务即可使用事务之后的写法:
开启事务
get count
if count > 0
decr count
执行事务
redis
接收到命令的时候,不会立即执行,只会将其按顺序放在队列中。当收到“执行事务”操作的时候,才会开始按顺序执行命令get
到的 count
就已经是第一个事务自减之后的结果了这个场景中,没加锁,也能解决上述“超卖”问题
redis
命令里能进行条件判定吗?
redis
原生命令中确实没有这种条件判断定,但是 redis
支持 lua
脚本 lua
是另外一种编程语言,特点是小巧,很多程序都可以内嵌 lua
语言,从而去执行其他的语言lua
脚本,就能实现上述的“条件判定”,并且也和事务一样是打包批量执行的lua
脚本的实现方式,是 redis
事务的进阶版本确实,redis
的事务的应用场景,没有 MySQL
的事务那么多(有点鸡肋的感觉)。redis
如果是按照集群模式部署,就不支持事务
(猫体,不是马体)
开启一个事务,执行成功返回 OK
key
,是查询不到的真正执行事务
key
的值了放弃当前事务,此时直接清空事务队列,之前的操作都不会真正执行到
当我们开启事务,并且给服务器发送若干命令之后,此时重启服务器,会怎么样?
discard
在执行事务的时候,如果某个事务中修改的值,被别的客户端修改了,此时就容易出现数据不一致的问题
从时间上来看,客户端 1 是先发送了 set key 222
,客户端 2 是后发送了 set key 333
exec
执行了,才会真正执行 set key 222
。这个操作变成了实际上更晚执行的操作,最终 key
的值就是 222
在刚才的场景中,就可以使用 watch
命令来监控这个 key
,看看这个 key
在事务的 multi
和 exec
之间,set key
之后,是否在外部被其他客户端修改了
key
被修改之后,exec
之后返回值为 nil
watch
的实现,类似与一个“乐观锁”
乐观锁在 https://cloud.tencent.com/developer/article/2457981 这篇文章中有详细解释
redis
的 watch
就相当于是基于版本号这样的机制,来实现了“乐观锁”(就是 CAS
中的 ABA
问题的解决方法)
watch
必须搭配事务使用,并且必须在 multi
之前使用watch
的版本号和 exec
的版本号 key
在事务开启到最终执行这个过程中,没有被别的客户端修改,于是才能真正进行设置key
在其他客户端中改过了,因此此处就直接丢弃事务中的操作,exec
返回 nil
所以,watch
本质上就是给 exec
加了一个判定条件
Redis
的事务,要比 MySQL
的事务,简单很多
Redis
的事务,并不支持回滚Redis
并不会保证事务执行前后的内容统一Redis
主要通过内存来存储数据Redis
自身作为一个单线程的服务器模型,上面处理的请求本质上都是串行执行的四个关于事务的命令:
nulti
exec
discard
key
是否被修改—— watch