04----------redis事务

首先说明,redis事务只满足了隔离性,隔离性中的串行化——当前执行的事务有着不被其它事务打断的权利。

1. 命令无法排队(外表错误;): 命令参数数量错误,或者命令不存在等,导致无法排队。2.6.5 之前版本会导致其余有效命令正常执行,2.6.5之后的版本一旦遇到无法排队错误,会拒绝执行整个事务的所有语句;

2. 调用Esec后发现的错误(执行期间错误): 一般由于对错误的Key或Val执行了不符合场景的操作,例如:对字符串执行incr操作;或文档中介绍的对字符串执行列表才支持的操作; Exec执行命令执行后出现的错误的命令外,其余事务中的语句仍然会正常执行,即所谓“部分”语句执行成功了

除了不能回滚外,一旦进程挂了,会造成事务丢失。一般解决这两个问题,会采用预写日志策略。比如,undo log实现事务回滚,redo实现事务重做

Redis 在形式上看起来也差不多,分别是 multi/exec/discard。multi 指示事务的开始,exec 指示事务的执行,discard 指示事务的丢弃。

> multi

OK

> incr books

QUEUED

> incr books Q

UEUED

> exec

(integer) 1

(integer) 2

优化:使用pipeline进行压缩

上面的 Redis 事务在发送每个指令到事务缓存队列时都要经过一次网络读写,当一个事务内部的指令较多时,需要的网络 IO 时间也会线性增长。所以通常 Redis 的客户端在执行事务时都会结合 pipeline 一起使用,这样可以将多次 IO 操作压缩为单次 IO 操作。比如我们在使用 Python 的 Redis 客户端时执行事务时是要强制使用 pipeline 的。

pipe = redis.pipeline(transaction=true)

pipe.multi()

pipe.incr("books")

pipe.incr("books")

values = pipe.execute()

watch:乐观锁,解决并发修改的问题(分布式锁是一种悲观锁

> watch books

OK

> incr books # 被修改了

(integer) 1

> multi

OK

> incr books

QUEUED

> exec # 事务执行失败 (nil)

注意事项

Redis 禁止在 multi 和 exec 之间执行 watch 指令,而必须在 multi 之前做好盯住关键变量,否则会出错。

 

import java.util.List;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

public class TransactionDemo {

  public static void main(String[] args) {
    Jedis jedis = new Jedis();
    String userId = "abc";
    String key = keyFor(userId);
    jedis.setnx(key, String.valueOf(5));  # setnx 做初始化
    System.out.println(doubleAccount(jedis, userId));
    jedis.close();
  }

  public static int doubleAccount(Jedis jedis, String userId) {
    String key = keyFor(userId);
    while (true) {
      jedis.watch(key);
      int value = Integer.parseInt(jedis.get(key));
      value *= 2; // 加倍
      Transaction tx = jedis.multi();
      tx.set(key, String.valueOf(value));
      List<Object> res = tx.exec();
      if (res != null) {
        break; // 成功了
      }
    }
    return Integer.parseInt(jedis.get(key)); // 重新获取余额
  }

  public static String keyFor(String userId) {
    return String.format("account_%s", userId);
  }

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值