redis事务:

redis的事务和mysql等关系型数据库的事务不太一样,redis中的事务不会回滚,只能手动收拾事务失败后的烂摊子。

在命令行中,MULTI是事务的开始命令。EXEC是事务的执行命令。并且会按顺序执行事务中的命令,不会被其他事务的命令打扰。在java操作redis中,是通过.multi()和.exec()开始和执行事务。

MULTI会将之后加入的所有命令按顺序的加入到命令队列中,调用EXEC会依次的执行这些命令。

EXEC命令的返回值是一个数组,其中的每个元素分别是原子化事务中的每个命令的返回值,返回值的顺序和命令的发出顺序是相同的。 

如果是因为语法错误,如没有相应命令或者命令参数传递不匹配,则事务中的命令会全部不执行。因为这个错误命令是在被放入队列时失败。命令还没有执行。

如果是其他原因导致事务失败,那么正确的命令将被执行,错误的不会被执行,整个过程也不会回滚。

 

WATCH命令:

watch是对一个或几个key对于的值进行监控,如果在事务执行之前,监控的值与开始监控时的值不一样,那么有关该值的事务将不会被执行,exec的执行结果在java中会返回null,在命令行中会返回(nil)。类似于AQS机制。

DISCARD会清除所有先前在一个事务中放入队列的命令,然后恢复正常的连接状态。 如果使用了WATCH命令,那么DISCARD命令就会将当前连接监控的所有键取消监控。 这个命令的运行格式如下所示: DISCARD 这个命令的返回值是一个简单的字符串,总是OK。

UNWATCH 清除所有先前为一个事务监控的键。 如果你调用了EXEC或DISCARD命令,那么就不需要手动调用UNWATCH命令。 这个命令的运行格式如下所示: UNWATCH 这个命令的返回值是一个简单的字符串,总是OK。 时间复杂度总是O(1)。

所以,exec,discard,unwatch命令都会清除所有监视。

jedis.watch(productStockCacheKey);
        //开启Redis事务
        Transaction tx = jedis.multi();
        //库存减一
        tx.decrBy(productStockCacheKey,1);
        //执行事务
        List<Object> resultList = tx.exec();
        if (resultList == null || resultList.isEmpty()) {
            jedis.unwatch();//也可以不调用,因为exec有同样效果
            //watch监控被更改过----物品抢购失败;
            System.out.println("商品:"+product.getProductName()+",watch监控被更改,物品抢购失败");
            throw new SecKillException(SecKillEnum.FAIL);
        }