跟我一块儿学Redis之Redis事务简单了解一下

前言

关系数据库中的事务,小伙伴们应该是不陌生了,不论是在开发仍是在面试过程当中,总有两个问题逃不掉:面试

•说说事务的特性;•事务隔离级别是怎么一回事?数据库

事务处理很差,数据就可能不许确,最终就会致使业务出问题;借此机会简单回顾一下事务特性及其隔离级别,就当是复习了;编程

事务特性(ACID)

•原子性(Atomicity)指事务内全部操做要么一块儿执行成功,要么都一块儿失败(或者说是回滚);如事务经典转帐案例:A给B转帐,A把钱扣了,但B没有收到;可见这种错误是不能接受的,最终会回滚,这也是原子性的重要性。•一致性(Consistency)指事务执行先后的状态一致,如事务经典转帐案例:A给B互相转帐,无论怎么转,最终二者钱的总和仍是不变;•持久性(Durability)指事务一旦提交,数据就已经永久保存了,不能再回滚;•隔离性(Isolation)指多个并发事务之间的操做互不干扰,可是事务的并发可能会致使数据脏读、不可重复读、幻读问题,根据业务状况,采用事务隔离级别进行对应数据读问题处理。服务器

事务隔离级别

•读未提交(Read uncommitted)指一个事务读取到其余未提交事务的数据。可能致使数据脏读。转帐案例:A正在给B转帐,原本转的1000,A多输入了个0,变成10000,但此事务还未提交,但此时B查询到转入的是10000,但A取消事务回滚以后,B又查询不到转入的数据。这种状况就是脏读•读已提交(Read committed)指一个事务只能读取到其余事务已提交的数据,从而解决了脏读的问题。但可能致使数据不可重复读;转帐案例:A要给B转帐1000,A先查看了一下余额,有1000,而后开始给B转钱,但此时A家里电费经过开启的自动缴费功能,自动从A帐户扣除200缴纳电费,并提交;当A转帐准备提交,再次确认余额时,钱少了200。这样就致使同一个事务中屡次查询的结果不一致,这种状况就是不可重复读;•可重复读(Repeatable read)指事务只要一开启,就不容许其余事务进行修改操做,从而解决了不可重复读问题。但可能致使数据幻读;转帐案例:A常常给B转帐,到年末了,须要查帐,而后开启了一个事务进行查询统计,刚开始查询只是10条转帐记录,正准备统计时,由于紧急状况A须要给B转一笔钱应急,从而新增了一条新记录,并提交;而查帐事务正在统计中,最后发现转帐额和看到的10条转帐记录不匹配。这种状况就是幻读•序列化(Serializable )指事务之间只能串行话执行,就像队列同样,排队进行,这样就解决了幻读的问题,可是这种级别的并发性能不高,非特殊需求,这种级别通常不用。并发

正文

转入正题,结合关系型数据库的事务来看看Redis中事务有什么不一样;性能

Redis事务是指将多条命令加入队列,一次批量执行多条命令,每条命令会按顺序执行,事务执行过程当中不会受客户端传入的命令请求影响。学习

Redis事务的相关命令以下:spa

•MULTI:标识一个事务的开启,即开启事务;•EXEC:执行事务中的全部命令,即提交;•DISCARD:放弃事务;和回滚不同,Redis事务不支持回滚。•WATCH:监视Key改变,用于实现乐观锁。若是监视的Key的值改变,事务最终会执行失败。•UNWATCH:放弃监视。队列

Redis事务和关系型数据库的事务不太同样,它不保证原子性,也没有隔离级别的概念。来,结合命令演示,实战说明一切:事务

没有隔离级别

image-20201112153132140

如上图所示,当事务开启时,事务期间的命令并无执行,而是加入队列,只有执行EXEC命令时,事务中的命令才会按照顺序一一执行,从而事务间就不会致使数据脏读、不可重复读、幻读的问题,所以就没有隔离级别

不保证原子性

image-20201112154524168

如上图所示,在经过EXEC执行事务时,其中命令执行失败不会影响到其余命令的执行,并无保证同时成功和同时失败的原子操做,尽管这样,Redis事务中也没有提供回滚的支持,官方提供了两个理由:

image-20201112160255544

大概的意思就是:

•使用Redis命令语法错误,或是将命令运用在错误的数据类型键上(如对字符串进行加减乘除等),从而致使业务数据有问题,这种状况认为是编程致使的错误,应该在开发过程当中解决,避免在生产环境中发生;•因为不用支持回滚功能,Redis内部简单化,并且还比较快;

在事务命令入队过程当中,发现相关命令逻辑使用错误,能够进行放弃该事务;若是使用错误的Redis命令,且没有放弃事务,最终也会致使事务总体执行失败,这也算是为原子性扳回一局,以下:

放弃事务

image-20201112223050653

命令语法错误致使事务执行失败

image-20201112223821761

使用WATCH实现乐观锁

说到乐观锁,就和悲观锁一块儿简单说说对其的理解:

乐观锁:就是很是乐观,作什么事都往好处想;对于数据库操做,就认为每次操做数据的时候都认为别的操做不会修改,因此不会加锁,而是经过一个相似于版本的字段来标识该数据是否修改过,在执行本次操做前先判断是否修改过,若是修改过就放弃本次操做从新再来;

悲观锁:就是很是悲观,作什么事都以为很差;对于数据库操做,每次操做数据数据都会认为别的操做会修改当前数据,因此都要对其进行加锁,相似于表锁和行锁。

WATCH经过监视指定Redis Key,若是没有改变,就执行成功,若是发现对应值发生改变,事务就会执行失败,以下图;

image-20201112232612965

那会一直监视指定的Key吗?,答案固然是不会的,如下三种方式能够取消监视:

•事务执行以后,不论是否执行成功还好是失败,都会取消对应的监视;•当监视的客户端断开链接时,也会取消监视;•能够手动UNWATCH取消全部Key的监视;

Redis事务优缺点

优势

•一次性按顺序执行多个Redis命令,不受其余客户端命令请求影响;•事务中的命令要么都执行(命令间执行失败互相不影响),要么都不执行(好比中间有命令语法错误);

缺点

•事务执行时,不能保证原子性;•命令入队每次都须要和服务器进行交互,增长带宽;

注意

•当事务中命令语法使用错误时,最终会致使事务执行不成功,即事务内全部命令都不执行;•当事务中命令知识逻辑错误,就好比给字符串作加减乘除操做时,只能在执行过程当中发现错误,这种事务执行中失败的命令不影响其余命令的执行。

总结

对于Redis事务,其实用的不是不少,大部分喜欢使用Lua脚本进行批量命令的执行,同时还能保证命令执行的原子性。

那为何要说Redis事务呢?

在以前计划写这篇文章的时候,和一些朋友简单沟经过,你们的确用的很少,基本上都是用Lua脚本;但面试会时不时遇到过Redis事务的问题,最多见的是Redis中的事务和关系型数据库中的事务有什么区别,这是从面试角度出发有这篇文章;

其实Redis 2.6版本以前,还不支持Lua脚本时,Redis事务对于批量按序执行命令的场景也是很用的;就拿当下来讲,若是一些业务需批量按序执行命令的,一样可使用,并不是必定要Lua脚本。这是从使用角度来讲;

最后从学习角度来讲,既然学Redis,就应该尽量的了解的多一点。下一篇说说持久化。

一个被程序搞丑的帅小伙,关注"Code综艺圈",跟我一块儿学~ 

相关文章
相关标签/搜索