美文网首页Redis
聊聊redis的事务操作

聊聊redis的事务操作

作者: go4it | 来源:发表于2018-09-19 15:27 被阅读12次

    本文主要研究一下redis的事务操作

    命令

    multi与exec

    • 命令行
    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379> incr total
    QUEUED
    127.0.0.1:6379> incr len
    QUEUED
    127.0.0.1:6379> exec
    1) (integer) 2
    2) (integer) 2
    127.0.0.1:6379> get total
    "2"
    127.0.0.1:6379> get len
    "2"
    
    • lettuce实例
        @Test
        public void testMultiExec(){
            RedisClient client = RedisClient.create("redis://192.168.99.100:6379/0");
            StatefulRedisConnection<String, String> connection = client.connect();
            RedisCommands<String, String> syncCommands = connection.sync();
    
            syncCommands.set("hello","1");
            syncCommands.set("world","2");
    
            syncCommands.multi();
            syncCommands.incr("hello");
            syncCommands.incr("world");
    
            //DefaultTransactionResult[wasRolledBack=false,result=[1, 2, 1, 3, 1]]
            TransactionResult transactionResult = syncCommands.exec();
            System.out.println(transactionResult);
            System.out.println(syncCommands.get("hello"));
            System.out.println(syncCommands.get("world"));
        }
    

    部分执行

    • 命令行
    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379> set a hello
    QUEUED
    127.0.0.1:6379> set b world
    QUEUED
    127.0.0.1:6379> incr a
    QUEUED
    127.0.0.1:6379> set c part
    QUEUED
    127.0.0.1:6379> exec
    1) OK
    2) OK
    3) (error) ERR value is not an integer or out of range
    4) OK
    127.0.0.1:6379> get a
    "hello"
    127.0.0.1:6379> get b
    "world"
    127.0.0.1:6379> get c
    "part"
    
    • lettuce实例
        @Test
        public void testMultiExecError(){
            RedisClient client = RedisClient.create("redis://192.168.99.100:6379/0");
            StatefulRedisConnection<String, String> connection = client.connect();
            RedisCommands<String, String> syncCommands = connection.sync();
    
            syncCommands.multi();
            syncCommands.set("a","hello");
            syncCommands.set("b","world");
            syncCommands.incr("a");
            syncCommands.set("c","part");
            //DefaultTransactionResult[wasRolledBack=false,result=[OK, OK, io.lettuce.core.RedisCommandExecutionException: ERR value is not an integer or out of range, OK, 1]]
            TransactionResult transactionResult = syncCommands.exec();
            System.out.println(transactionResult);
            System.out.println(syncCommands.get("a"));
            System.out.println(syncCommands.get("b"));
            System.out.println(syncCommands.get("c"));
        }
    

    multi与discard

    • 命令行
    127.0.0.1:6379> set sum 1
    OK
    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379> incr sum
    QUEUED
    127.0.0.1:6379> discard
    OK
    127.0.0.1:6379> get sum
    "1"
    
    • lettuce实例
        @Test
        public void testMultiDiscard(){
            RedisClient client = RedisClient.create("redis://192.168.99.100:6379/0");
            StatefulRedisConnection<String, String> connection = client.connect();
            RedisCommands<String, String> syncCommands = connection.sync();
            syncCommands.incr("key1");
            syncCommands.multi();
            syncCommands.incr("key1");
            //需要有multi才可以执行discard,成功返回OK
            String result = syncCommands.discard();
            System.out.println(result);
            System.out.println(syncCommands.get("key1"));
        }
    

    check and set

        @Test
        public void testWatch(){
            RedisClient client = RedisClient.create("redis://192.168.99.100:6379/0");
            StatefulRedisConnection<String, String> connection = client.connect();
            RedisCommands<String, String> syncCommands = connection.sync();
    
            String key = "key";
            syncCommands.watch(key);
    
            //another connection
            StatefulRedisConnection<String, String> conn2 = client.connect();
            RedisCommands<String, String> syncCommands2 = conn2.sync();
            syncCommands2.set(key, "a");
    
            syncCommands.multi();
            syncCommands.append(key, "b");
            //DefaultTransactionResult [wasRolledBack=true, responses=0]
            TransactionResult transactionResult = syncCommands.exec();
            System.out.println(transactionResult);
    
            System.out.println(syncCommands.get(key));
        }
    

    小结

    • reids提供multi exec/discard指令,类似open commit/rollback transaction,不过exec遇到类型操作等错误时不会滚,该成功执行的命令还是成功执行,该失败的还是失败
    • multi exec保证的是,只要exec命令有执行成功,则事务中一系列的命令都能执行,如果exec因为网络等问题,server端没有接收到,则事务中的一系列命令都不会被执行
    • discard需要在有调用multi的前提下才能使用,该命令会清空事务队列等待执行的命令
    • redis提供watch指令,可以配合multi exec来使用,可以实现类似数据库的乐观锁的机制,一旦watch的key被其他client有更新,则整个exec操作失败

    doc

    相关文章

      网友评论

        本文标题:聊聊redis的事务操作

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