redis 事务

1 概念和使用

熟悉关系型数据库的读者应该对事务比较了解,简单说,事务表示一组动作或者命令,要么全部执行完成,要么全部不执行。例如在社交网站上用户A关注了用户B,那么需要在用户A的关注表中加入用户B,并且在用户B的粉丝表中 添加用户A,这两个行为要么全部执行,要么全部不执行,否则会出现数据不一致的情况。

Redis提供了简单的事务功能,将一组需要执行的命令放在multi和exec两个命令之间。multi代表事务开始,exec代表事务结束,他们之间的命令是原子性执行的

127.0.0.1:6379> multi
OK
127.0.0.1:6379> sadd  user:a:follow user:b
QUEUED
127.0.0.1:6379> sadd user:b:fans user:a
QUEUED
127.0.0.1:6379> exec
1) (integer) 1
2) (integer) 1

上述操作可以看到sadd命令返回结果是QUEUE,代表命令没有真正执行,而是暂时保存在Redis中。如果在执行exec之前,在另外一个客户端执行sismember user:🅰️:follow user:b 返回的结果应该是0

如果想要停止事务的执行,可以使用discard命令代替exec

127.0.0.1:6379> multi
OK
127.0.0.1:6379> sadd user:a:follow user:c
QUEUED
127.0.0.1:6379> discard
OK

如果执行事务过程中出现问题,那么有两种处理机制

  1. 命令错误,整个事务无法进行

    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379> set count 1
    QUEUED
    127.0.0.1:6379> incrr count 1
    (error) ERR unknown command `incrr`, with args beginning with: `count`, `1`,
    127.0.0.1:6379> exec
    (error) EXECABORT Transaction discarded because of previous errors.
    127.0.0.1:6379>
    
  2. 运行时错误, 例如在添加用户粉丝数时,误把sadd写成zadd,这种会出现运行时错误,因为语法时没错的

    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379> sadd user:a:follow user:b
    QUEUED
    127.0.0.1:6379> zadd user:b:fans 1 user:a
    QUEUED
    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>
    

    可以看到Redis并不支持回滚功能,sadd user:a:follow user:b命令已经执行成功,开发人员需要自己修复这类问题

有些应用需要在事务开始前保证key没有被其他客户端修改过,才执行事务,否则不执行,Redis提供了watch命令来实现这样的功能,如下

客户端1客户端2
set key java
watch key
multi
append key pytoon
append key jedis
exec
get key
# 客户端 1
127.0.0.1:6379> set key java
OK
127.0.0.1:6379> watch key
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> append key jedis
QUEUED
127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> get key
"javapytoon"
127.0.0.1:6379>

# 客户端2
127.0.0.1:6379> append key pytoon
(integer) 10

可以看到客户端1在执行multi之前执行了watch key操作,客户端2在客户端1执行exec之前修改了key的value值,导致事务没有进行,返回nil

Jedis客户端操作
  void transactionProccess(String key){
    Jedis jedis = null;
    try {
      jedis = jedisSentinelPool.getResource();
      // watch
      jedis.watch(key);
      // 开启事务
      Transaction tx = jedis.multi();
      // 处理
      List<Object> response = tx.exec();
      System.out.println("response: "+ response);

    }finally {
      if(jedis != null){
        jedis.close();
      }
    }
  }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值