【Redis笔记】事务

介绍

redis对事务的支持目前还比较简单。不保证事务的一致性,即使中间有一条命令出错了,其他命令仍然可以正常执行,并且无法回滚。
和sql事务不同的是,Redis调用Exec只是将所有的命令变成一个单元一起执行,期间不会插入其他的命令。(隔离级别序列化)
redis只能保证一个client发起的事务中的命令可以连续的执行。一般情况下redis在接受到一个client发来的命令后会立即处理并 返回处理结果,但是当一个client在一个连接中发出multi命令后,这个连接会进入一个事务上下文,该连接后续的命令并不是立即执行,而是先放到一 个队列中。当从此连接受到exec命令后,redis会顺序的执行队列中的所有命令。并将所有命令的运行结果打包到一起返回给client.然后此连接就 结束事务上下文。

事务相关命令​

MULTI​:开启事务,后续命令入队但不立即执行
EXEC:执行事务队列中的所有命令,返回各命令的结果数组
DISCARD​:取消事务,清空队列
WATCH:监视键,若被监视键在事务执行前被修改,则事务中止(乐观锁机制)
UNWATCH:取消所有键的监视

案例

 multi
 incr a
 incr b
 exec

incr a ,incr b命令发出后并没执行而是被放到了队列中。调用exec后俩个命令被连续的执行,最后返回的是两条命令执行后的结果
可以调用discard命令来取消一个事务,discard命令其实就是清空事务的命令队列并退出事务上下文。

事务执行流程​

​* 开启事务​:MULTI命令标记事务开始。
​​* 命令入队​:后续命令(如SET、GET)被缓存在队列中,返回QUEUED状态
​​* 提交或取消​:

  • EXEC触发队列命令的原子执行。
  • DISCARD放弃事务

应用场景​

  • ​乐观锁​:通过WATCH实现CAS操作,例如库存扣减
  • ​批量操作​:如社交系统中用户关注与粉丝列表的同步更新

Watch(乐观锁)

前面说到通过multi命令只是保证一个事物中的所有命令可以在一起执行,显然只是实现这一点的话对于大部分的业务都是无法满足的。
所以Redis提供了Watch命令来监控一个key以达到乐观锁的效果。
下面展示一个乐观锁实例:

 watch money
 multi
 incr money 1
 decr money 2
 exec

client执行exec命令时,如果Redis检测到name的值已经被其他客户端改过了,事物的命令队列不会执行。
watch命令是对整个连接有效的,用完之后可以用discardunwatchexec命令清除监视

c#代码

// C# 使用StackExchange.Redis实现事务
var redis = ConnectionMultiplexer.Connect("localhost");
var db = redis.GetDatabase();

// WATCH监视键
var watchedKey = new RedisKey("balance");
db.KeyDelete(watchedKey);
db.StringSet(watchedKey, "100");

// 开启事务
var transaction = db.CreateTransaction();
transaction.AddCondition(Condition.KeyEqual(watchedKey, "100")); // 乐观锁条件
transaction.StringSetAsync(watchedKey, "90");
bool committed = transaction.Execute(); // 返回是否提交成功
Console.WriteLine($"事务提交结果: {committed}, 当前值: {db.StringGet(watchedKey)}");
posted @ 2020-07-04 18:36  .Neterr  阅读(266)  评论(0)    收藏  举报