事务是数据库中的一个非常重要的问题,无论在学习关系型数据库还是菲关系型数据库,事务都会是一个学习的重点
一,Redis中事务的特点
-
隔离,事务是一个隔离的操作,事务中的所有命令都会被序列化,然后按顺序之心,在执行过程中不会被其他客户端发送过来的命令请求所打断,会在事务中的命令全部被执行完后再去执行其他请求
-
原子,事务中的命令要么全部被执行,要么全部不执行
-
redis中事务和关系型数据库中事务的不同点就是,redis事务命令中有一条执行出错,其他命令还是会正常执行
二,redis事务的执行
-
multi :开启事务,语句后的命令将会进入执行队列,直到exec才会被执行原子操作
-
exec :执行事务
-
discard : 回滚事务
> MULTI OK
> INCR foo QUEUED
> INCR bar QUEUED
> EXEC
1) (integer) 1
2) (integer) 1
EXEC 命令的回复是一个数组, 数组中的每个元素都是执行事务中的命令所产生的回复。 其 中, 回复元素的先后顺序和命令发送的先后顺序一致。
当客户端处于事务状态时, 所有传入的命令都会返回一个内容为 QUEUED 的状态回复 (status reply), 这些被入队的命令将在 EXEC 命令被调用时执行。
三,redis中事务的注意问题
1.事务在exec前命令入队时出错
对于发生在 EXEC 执行之前的错误,客户端以前的做法是检查命令入队所得的返回值:如果 命令入队时返回 QUEUED ,那么入队成功;否则,就是入队失败。如果有命令在入队时失 败,那么大部分客户端都会停止并取消这个事务。
不过,从 Redis 2.6.5 开始,服务器会对命令入队失败的情况进行记录,并在客户端调用 EXEC 命令时,拒绝执行并自动放弃这个事务。 在 Redis 2.6.5 以前, Redis 只执行事务中那些入队成功的命令,而忽略那些入队失败的命 令。
2.事务在exec后命令出错
至于那些在 EXEC 命令执行之后所产生的错误, 并没有对它们进行特别处理: 即使事务中有 某个/某些命令在执行时产生了错误, 事务中的其他命令仍然会继续执行。
3.redis事务不支持回滚,为什么?
Redis 命令只会因为错误的语法而失败(并且这些问题不能在入队时发现),或是命令用 在了错误类型的键上面:这也就是说,从实用性的角度来说,失败的命令是由编程错误 造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中。 鉴于没有任何机制能避免程序员自己造成的错误, 并且这类错误通常不会在生产环境中出 现, 所以 Redis 选择了更简单、更快速的无回滚方式来处理事务。
所以,当执行 DISCARD 命令时, 事务会被放弃, 事务队列会被清空, 并且客户端会从事务状态中 退出:
redis> SET foo 1 OK
redis> MULTI OK
redis> INCR foo QUEUED
redis> DISCARD OK
redis> GET foo "1"
2.redis中watch作用
watch可以为redis事务提供监视作用
即,被watch监视的键如果在调用exec前被修改,则该整个事务会被取消,exec返回多条空回复(null)
为什么这样做?
举个例子, 假设我们需要原子性地为某个值进行增 1 操作(假设 INCR 不存在)。
首先我们可能会这样做:
val = GET mykey
val = val + 1
SET mykey $val
上面的这个实现在只有一个客户端的时候可以执行得很好。 但是, 当多个客户端同时对同一 个键进行这样的操作时, 就会产生竞争条件
所以使用watch可以很好地解决该问题
WATCH mykey
val = GET mykey
val = val + 1
MULTI
SET mykey $val
EXEC
如果你使用 WATCH 监视了一个带过期时间的键, 那么即使这个键过期了, 事务仍然可以正 常执行