从示例揭开非关系型数据库Redis事务管理的面纱


  Redis也提供事务这样的概念,但是相对于关系型数据库而言,Redis目前对事务提供的是比较简单的,Redis只能保证一个Client发起的事务命令可以连续的执行,而中间不会插入其他的Client命令,在一个Redis事务中,Redis会将所有的命令放到一个队列中,当执行执行命令的时候Redis才会批量的处理,要么都成功,要么都失败,这样就保证了 Redis 事务的原子性。

一、Redis开启事务示例,关键字为multi和exec:
先来对Redis的事务进行一个操作,对其有个直观的感受。


如上图,我们先获取了db这样一个String类型的值,然后使用multi命令打开一个事务,我们先将db修改为mongodb,然后修改为redis,QUEUED表示此时命令被顺序的放到了一个队列当中并没有执行,而当我们执行exec命令的时候,事务才真的提交,并且两条命令都被执行,最后返回了redis这样的信息。

二、Redis取消事务示例,关键字为discard:
Redis能够保证在一个事务中的所有操作按照顺序执行,假如在此过程中想要取消这个事务的操作,应该如何处理呢?请看下面的示例,您将会比较清楚的了解到类似于事务回滚的功能。


先创建了一个事务,然后修改了db,最后发现不想对其进行修改,因此使用了discard命令,事务被清空了,此时执行exec命令将会报错。并且我们再次执行get db命令则返回没有修改前的键值。

三、与Redis事务相关的关键字watch
在Redis中还有一个事务的实现方式,类似于SVN的操作,使用了数据版本的概念,假设有A,B两个客户端,在拥有数据的时候同时拥有一个数据版本,当提交到服务端的时候,如果数据版本大于等于服务端的版本则表明此时数据是有效数据,也就是在此期间没有发生过其他的变化,如果数据版本小于服务端版本的时候则表明此时数据在此期间被篡改过,因此就会出现冲突,表明该数据已经失效了。

我们来做一个示范,打开两个 Redis 的客户端。


在执行A客户端exec命令之前,我执行了B客户端的set命令,然后再才执行的A客户端的exec命令,此时出现了nil的结果,表面db设置不成功,原因就是使用了Watch命令获得了db当前的一个数据版本,但是在事务执行的过程中B客户端已经给服务器提交了新的数据,也就是说此时服务端数据版本已经要比A客户端Watch时候新,因此提交的时候就会出现过期。

四、关于语义错误造成Redis事务的失败
在关系型数据库中,一个事务保证了事务上下文中所有操作的原子性,通俗一点讲就是要么都成功,要么都失败,我们已经尝试了在Redis中命令都成功的情况,事务的确能够保证原子性的操作,那么在有错误的时候呢?错误有两种类型,第一是语法错误,也就是说在事务上下文中,命令的格式书写出现了问题,第二是语义错误,也就是说语法没有问题,命令的逻辑出现了问题。
语法错误:


通过上面的演示,我们发现,事务并没有提交成功,出现了错误的情况,也就是说在一个事务中,当语法出现错误的时候就会导致事务上下文的失败,这很好的体现了事务的原子性。
语义错误:


从上图演示结果表明在事务的上下文中,并没有保证原子性,所以在编写程序的时候一定要注意,尽量避免语义错误,其实我们在编写关系型数据库的SQL或者PLSQL的时候语义错误也是百年难得一见,程序代码务必保证足够强大的容错性。

猜你喜欢

转载自blog.csdn.net/Apeopl/article/details/82732944