美文网首页
同舟共济 —— 事务

同舟共济 —— 事务

作者: DreamsonMa | 来源:发表于2019-04-02 14:58 被阅读0次

    如果对redis事务不熟悉,建议避免使用redis事务

    Redis 的事务使用非常简单,不同于关系数据库,它的事务模型很不严格。Redis 的事务根本不能算「原子性」,而仅仅是满足了事务的「隔离性」,隔离性中的串行化——当前执行的事务有着不被其它事务打断的权利。

    Redis 事务命令分别是 multi/exec/discard。multi 指示事务的开始,exec 指示事务的执行,discard 指示事务的丢弃。但是,Redis的事务是不支持回滚的

    优化

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

    Watch

    考虑到一个业务场景,Redis 存储了我们的账户余额数据,它是一个整数。现在有两个并发的客户端要对账户余额进行修改操作,这个修改不是一个简单的 incrby 指令,而是要对余额乘以一个倍数。Redis 可没有提供 multiplyby 这样的指令。我们需要先取出余额然后在内存里乘以倍数,再将结果写回 Redis。这就会出现并发问题,因为有多个客户端会并发进行操作。

    我们可以通过 Redis 的分布式锁来避免冲突,这是一个很好的解决方案。分布式锁是一种悲观锁,那是不是可以使用乐观锁的方式来解决冲突呢?Redis 提供了这种 watch 的机制,它就是一种乐观锁。有了 watch 我们又多了一种可以用来解决并发修改的方法。

    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.Transaction;
    
    import java.text.MessageFormat;
    import java.util.List;
    
    /**
     * @Auther: majx2
     * @Date: 2019-3-23 20:29
     * @Description:
     */
    public class TransactionDemo {
    
        public static void main(String[] args) {
            Jedis jedis = RedisDS.create().getJedis();
            String userId = "abc";
            String key = keyFor(userId);
            jedis.setnx(key, String.valueOf(5));
            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 MessageFormat.format("account_{0}", userId);
        }
    
    }
    

    相关文章

      网友评论

          本文标题:同舟共济 —— 事务

          本文链接:https://www.haomeiwen.com/subject/vphgbqtx.html