核心知识点:
1.事务出错的类型有两种:
a.语法错误,事务不会被执行;
b.运行时报错,可能有部分事务会被执行成功。
2.watch可以监测在执行事务的过程中,如果目标被改变,将会导致事务无法执行。
熟悉关系型数据库的读者应该对事务比较了解,简单的说,事务表示一组动作,要么全部执行,要么全部不执行。
Redis提供了简单的事务功能,将一组需要执行的命令放到multi和exec两个命令之间。
multi命令代表事务开始,exec命令代表事务结束,它们之间的命令是原子顺序执行的。
例如,如果两个人需要成为好友,需要各自在自己的好友列表中加上对方的命令,如果只完成了一方,那么这组命令应该视作无效。
127.0.0.1:6379> multi OK 127.0.0.1:6379> sadd kebi:friend maoxian QUEUED 127.0.0.1:6379> sadd maoxian:friend kebi QUEUED
可以看到sadd命令此时的返回结果是QUEUED,代表命令并没有真正执行,而是暂时保存在Redis中。
在另外一个客户端查看刚才的添加操作,应该没有结果:
127.0.0.1:6379> sismember maoxian:friend kebi (integer) 0
只有执行了exec之后,写入操作才算完成。
127.0.0.1:6379> exec 1) (integer) 1 2) (integer) 1
再次在另外一个客户端查询,有结果:
127.0.0.1:6379> sismember maoxian:friend kebi (integer) 1
如果事务中命令出现错误,Redis的处理机制也不尽相同,一般主要有两种情况。
1.命令错误
如果事务的执行过程中,出现语法错误,会造成整个事务无法执行:
127.0.0.1:6379> multi OK 127.0.0.1:6379> sadd kebi:friend maoxian QUEUED 127.0.0.1:6379> saddd maoxian:friend kebi (error) ERR unknown command 'saddd' 127.0.0.1:6379> exec (error) EXECABORT Transaction discarded because of previous errors. 127.0.0.1:6379> sismember kebi:friend maoxian (integer) 0 #并没有添加成功
2.运行时错误
也许语法不存在问题,但是执行过程中出现了错误,这种情况可能导致部分操作被执行成功。
(integer) 1 127.0.0.1:6379> multi OK 127.0.0.1:6379> sadd kebi:friend xiaoniao QUEUED 127.0.0.1:6379> zadd maoxian:friend 1 xiaoniao QUEUED #并没有语法错误,可maoxian:friend是集合,不是有序集合 127.0.0.1:6379> exec 1) (integer) 1 2) (error) WRONGTYPE Operation against a key holding the wrong kind of value 127.0.0.1:6379> sismember kebi:friend xiaoniao (integer) 1 127.0.0.1:6379> sismember maoxian:friend xiaoniao (integer) 0
可以看到错误只是部分,但是并不是所有结果都没有执行,这就会导致问题。
Redis并不支持回滚功能,开发人员需要自己修复这类问题。
有些应用场景在事务之前,确保事务中的key没有被其他客户端修改过,才执行事务,否则不执行。Redis提供了watch命令来解决这类问题。
#客户端1 127.0.0.1:6379> set key java OK #客户端1 127.0.0.1:6379> watch key OK #客户端1 127.0.0.1:6379> multi OK #客户端2 127.0.0.1:6379> append key python (integer) 10 #客户端1 127.0.0.1:6379> append key linux QUEUED #客户端1 127.0.0.1:6379> exec (nil) #客户端1 127.0.0.1:6379> get key "javapython"
可以看到,如果在执行exec之前,所需的数据被修改了将会导致事务不能被执行。
Redis提供了简单的事务功能,之所说它简单,主要是因为它不支持事务中的回滚特性,
同时无法实现命令之间的逻辑关系计算,当然也体现了Redis的“keep it simple”的特性。