Redis 事务允许将多个命令打包,然后一次性、按顺序地执行。Redis 事务的实现主要通过以下几个命令:
MULTI
、
EXEC
、
DISCARD
和
WATCH
。
Redis 事务特点:
- 原子性(Atomicity):事务中的所有命令都会被序列化并连续执行,事务在执行过程中不会被其他客户端发送来的命令请求所中断。
- 没有隔离级别的概念:在事务执行期间,事务中的命令不会看到其他客户端对数据库所作的变更。
- 不保证持久性和一致性:如果服务器在执行事务过程中崩溃,即使部分命令已经被执行,事务也不会被持久化;如果事务中的某个命令失败,其他命令仍然会被执行。
事务的工作流程:
- 开始事务:使用
MULTI
命令开始一个事务。 - 命令入队:在
MULTI
之后输入的所有命令不会立即执行,而是被放入一个队列,客户端会收到一个回复表示命令已成功入队。 - 执行事务:通过
EXEC
命令执行所有队列中的命令。如果事务中的任何命令执行失败,Redis 仍将继续执行事务队列中的剩余命令。事务执行完毕后,会一次性将事务产生的所有结果返回给客户端。 - 取消事务:使用
DISCARD
命令可以取消事务,这将清空事务队列并退出事务。 - 乐观锁:
WATCH
命令可以在事务开始之前监视一个或多个键,在执行EXEC
命令时,如果任何被监视的键被修改,那么整个事务都会被取消。
源码解析:
Redis的事务功能主要体现在
multi.c
文件中,该文件包含了处理事务命令的相关函数。Redis 使用一个叫做
multiState
的结构体来记录事务状态,包括命令队列和被
WATCH
命令监视的键。
当调用
MULTI
命令时,Redis会为当前客户端初始化一个
multiState
结构体,并将其标记为处于事务状态。在事务状态中,客户端发来的命令会被添加到
multiState
的命令队列中而不会被执行。
当调用
EXEC
命令时,Redis会按顺序执行
multiState
的命令队列中的所有命令,并将结果发送给客户端。如果之前有过
WATCH
,并且监视的键发生了变化,则事务会被打断,客户端收到空回复表示事务执行失败。
Java代码演示:
以下是使用 Jedis 客户端库在 Java 中操作 Redis 事务的示例:
importredis.clients.jedis.Jedis;importredis.clients.jedis.Transaction;publicclassRedisTransactionExample{publicstaticvoidmain(String[] args){Jedis jedis =newJedis("localhost",6379);// 乐观锁:监视一个key
jedis.watch("key");// 开始事务Transaction t = jedis.multi();try{// 事务中的操作
t.set("key","value");
t.incr("counter");// 提交事务
t.exec();}catch(Exception e){// 事务出错,取消事务
t.discard();}finally{
jedis.unwatch();// 移除监视
jedis.close();}}}
在这个例子中,我们首先通过
jedis.watch("key")
对 key 进行监视,然后我们通过
jedis.multi()
开始事务,并向事务中添加了一些命令。通过
t.exec()
提交事务,如果在执行
exec
前
key
的值被其他客户端修改了,则事务会被取消,
exec
返回
null
。如果事务中途出现异常,我们使用
t.discard()
取消事务。
注意事项:
- Redis事务不支持回滚,即使事务中的某些命令失败,事务也不会回滚之前已执行的命令。
- Redis 事务中,即使命令语法错误,也会在
EXEC
时全部执行其他命令,错误的命令会导致事务失败。 - 使用乐观锁时,如果其他客户端修改了被监视的键,事务将不会执行任何命令。
Redis事务虽然具有原子性,但它并不完全等同于传统关系型数据库中的事务。了解其工作原理和限制对于正确使用Redis事务至关重要。
版权归原作者 辞暮尔尔-烟火年年 所有, 如有侵权,请联系我们删除。