redis事务
概述
mysql 原子性,一致性,持久性,隔离性
特点 | mysql | redis |
---|---|---|
原子性 | 通过回滚日志日志来保证事务的原子性 | 单条命令是保存原子性,但是事务不保证原子性 |
一致性 | 通过执行重做日志来保证数据的一致性 | |
隔离性 | Mysql通过锁实现隔离性 | |
持久性 | 数据保存在磁盘 | 需要开启持久化,EDB模式需要特定条件下才能将数据保存在磁盘 |
redis事务本质:一组命令的集合。一个事务中的所有命令都会被序列化,在事务执行过程中,会按照顺序执行。其他客户端提交的命令请求会等到事务执行完毕再执行。
redis事务没有隔离级别的概念!
所有命令在事务中,并没有直接被执行!只有发起执行命令的时候才会执行!(本质是一组命令的集合)
redis在什么情况下会回滚?
redis在命令加入事务命令队列的时候,如果检测到错误,会回滚,一旦输入执行指令exec
,即使有命令执行出错也不会回滚
MULTI、EXEC、DISCARD和WATCH命令是Redis事务功能的基础。Redis事务允许在一次单独的步骤中执行一组命令,并且可以保证如下两个重要事项:
Redis会将一个事务中的所有命令序列化,然后按顺序执行。Redis不可能在一个Redis事务的执行过程中插入执行另一个客户端发出的请求。这样便能保证Redis将这些命令作为一个单独的隔离操作执行。
在一个Redis事务中,Redis要么执行其中的所有命令,要么什么都不执行。因此,Redis事务能够保证原子性。
EXEC命令会触发执行事务中的所有命令。因此,当某个客户端正在执行一次事务时,如果它在调用MULTI命令之前就从Redis服务端断开连接,那么就不会执行事务中的任何操作;
相反,如果它在调用EXEC命令之后才从Redis服务端断开连接,那么就会执行事务中的所有操作。当Redis使用只增文件(AOF:Append-only File)时,Redis能够确保使用一个单独的write(2)系统调用,这样便能将事务写入磁盘。
然而,如果Redis服务器宕机,或者系统管理员以某种方式停止Redis服务进程的运行,那么Redis很有可能只执行了事务中的一部分操作。
Redis将会在重新启动时检查上述状态,然后退出运行,并且输出报错信息。
使用redis-check-aof工具可以修复上述的只增文件,这个工具将会从上述文件中删除执行不完全的事务,这样Redis服务器才能再次启动。
从2.2版本开始,除了上述两项保证之外,Redis还能够以乐观锁的形式提供更多的保证,这种形式非常类似于“检查再设置”(CAS:Check And Set)操作。本文稍后会对Redis的乐观锁进行描述。
相关命令
MULTI
用于标记事务块的开始。Redis会将后续的命令逐个放入队列中,然后才能使用EXEC命令原子化地执行这个命令序列。
这个命令的运行格式如下所示:MULTI
这个命令的返回值是一个简单的字符串,总是OK。
EXEC
在一个事务中执行所有先前放入队列的命令,然后恢复正常的连接状态。
当使用WATCH命令时,只有当受监控的键没有被修改时,EXEC命令才会执行事务中的命令,这种方式利用了检查再设置(CAS)的机制。
这个命令的运行格式如下所示:EXEC
这个命令的返回值是一个数组,其中的每个元素分别是原子化事务中的每个命令的返回值。 当使用WATCH命令时,如果事务执行中止,那么EXEC命令就会返回一个Null值。
DISCARD
清除所有先前在一个事务中放入队列的命令,然后恢复正常的连接状态。
如果使用了WATCH命令,那么DISCARD命令就会将当前连接监控的所有键取消监控。
这个命令的运行格式如下所示:DISCARD
这个命令的返回值是一个简单的字符串,总是OK。
WATCH
当某个事务需要按条件执行时,就要使用这个命令将给定的键设置为受监控的。
这个命令的运行格式如下所示:WATCH key [key ...]
这个命令的返回值是一个简单的字符串,总是OK。
对于每个键来说,时间复杂度总是O(1)。
UNWATCH
清除所有先前为一个事务监控的键。
如果你调用了EXEC或DISCARD命令,那么就不需要手动调用UNWATCH命令。
这个命令的运行格式如下所示:UNWATCH
这个命令的返回值是一个简单的字符串,总是OK。
时间复杂度总是O(1)。
案例
开启事务
|
|
取消事务
|
|
编译型异常(代码有问题!命令有错!)事务中所有的命令都不会被执行!
|
|
运行时异常(1/0),如果事务队列中存在语法型错误,那么执行命令的时候,其他命令是可以正常执行的,错误命令抛出异常!
|
|
通过CAS操作实现乐观锁
那么WATCH命令实际做了些什么呢?
WATCH用于监控一个或多个key,如果在事务执行之前这个key被其他命令所改动,那么事务会被打断
WATCH命令可以被调用多次。简单说来,所有的WATCH命令都会在被调用之时立刻对相应的键进行监控,直到EXEC命令被调用之时为止。你可以在单条的WATCH命令之中,使用任意数量的键作为命令参数。
当调用EXEC命令时,所有的键都会变为未受监控的状态,Redis不会管事务是否被中止。当一个客户单连接被关闭时,所有的键也都会变为未受监控的状态。
如何使用WATCH命令实现ZPOP操作呢?
|
|
测试多线程修改值,使用watch可以当做redis的乐观锁操作
|
|
可以使用UNWATCH命令(不需要任何参数),这样便能清除所有的受监控键。当我们对某些键施加乐观锁之后,这个命令有时会非常有用。因为,我们可能需要运行一个用来修改这些键的事务,但是在读取这些键的当前内容之后,我们可能不打算继续进行操作,此时便可以使用UNWATCH命令,清除所有受监控的键。在运行UNWATCH命令之后,Redis连接便可以再次自由地用于运行新事务。