• redis-使用-事物


    什么是redis事物

    Redis的事务是下面4个命令来实现
    1.multi,开启Redis的事务,置客户端为事务态。
    2.exec,提交事务,执行从multi到此命令前的命令队列,置客户端为非事务态。
    3.discard,取消事务,置客户端为非事务态。
    4.watch,监视键值对,作用时如果事务提交exec时发现监视的监视对发生变化,事务将被取消。

    redis事物和数据库事物不一样,可以理解成是一串命令的集合 要么一起执行 要么都不执行

    执行图

    非cas事物使用案例

    正常执行

    本地:0>multi //标识连接为事物连接
    OK
    本地:
    0>get test //命令入队 QUEUED
    本地:
    0>set test2 1 //命令入队 QUEUED
    本地:
    0>set test 2 //命令入队 QUEUED 本地:0>get test //命令入队 QUEUED 本地:0>exec //执行命令 并重置连接状态为事物连接 1) 1 2) OK 3) OK 4) 2 本地:0>

    放弃事物 

    本地:0>get test //修改前test数据值
    3
    
    本地:0>get test2  //修改前test2数据值
    4
    
    本地:0>multi   //标识连接为事物连接
    OK
    
    本地:0>set test 30 //命令入队
    QUEUED
    
    本地:0>set test2 40 //命令入队
    QUEUED
    
    本地:0>discard  //丢失事物队列命令,并重置连接为非事物连接
    OK
    
    本地:0>get test  //test数据未发送改变
    3
    
    本地:0>get test2 //test2数据未发生改变
    4

    命令编辑错误提交事物

    本地:0>get test  //test修改前的值
    3
    
    本地:0>get test2  //test修改前的值
    4
    
    本地:0>multi   //表示连接为事物连接
    OK
    
    本地:0>set test 3333  //修改test
    QUEUED
    
    本地:0>sett tset2 2 //编译错误,不是正确的命令格式
    ERR unknown command `sett`, with args beginning with: `tset2`, `2`, 
    
    本地:0>set test2 4444  //修改test2
    QUEUED
    
    本地:0>exec  //提交报错 并重置事物连接为非事物
    EXECABORT Transaction discarded because of previous errors.
    
    本地:0>get test  //test数据未修改
    3
    
    本地:0>get test2 //test2数据未修改
    4

    命令运行时错误 

    本地:0>get test 
    f
    
    本地:0>get  test2
    5
    
    本地:0>get test3
    2
    
    本地:0>multi //开启事物
    OK
    
    本地:0>set  test2 6 //修改test2
    QUEUED
    
    本地:0>incr test //对值为f的执行+1操作
    QUEUED
    
    本地:0>set test3 8 //修改test3
    QUEUED
    
    本地:0>exec  
    1) OK
    2) ERR value is not an integer or out of range //除了修改test失败其他都修改成功
    3) OK
    本地:0>get test
    f
    
    本地:0>get test2
    6
    
    本地:0>get  test3
    8

    CAS事物案例

    什么是CAS

    参考:点击跳转

    正常执行

    本地:0>get test //监控的key值
    f
    
    本地:0>watch test //监控test key的值 也可以监控多个
    OK
    
    本地:0>multi //开启事物
    OK
    
    本地:0>set test2 1 //修改test2
    QUEUED
    
    本地:0>set test 1 //修改test1
    QUEUED
    
    本地:0>exec //提交事物 并自动取消watch监控
    1) OK
    2) OK
    本地:0>get test //修改成功
    1
    
    本地:0>get test2 //成功
    1

    异常提交

    本地:0>get test //test修改前的值
    1
    
    本地:0>get test2 //test2修改前的值
    1
    
    本地:0>watch test //监控test 也可以监控多个
    OK
    
    本地:0>multi //开启事物
    OK
    
    本地:0>set test 33 //修改test的值
    QUEUED
    
    本地:0>set test2 33 //修改test2的值
    QUEUED
    
    本地:0>exec //提交事物,提交之前我使用另外一个连接改成了555  所以返回null修改失败 并取消test监控
    
    
    本地:0>get test  //另外一个连接 改的值
    555
    
    本地:0>get test2 //未修改成功
    1

    银行转账例子

       public static void main(String[] args)
                throws Exception {
            Jedis conn = new Jedis("127.0.0.1", 6379);
            //=====================删除历史测试数据======================
            //转入方
            String inputUserIdKey=String.format("user:%s", "1");
            //转出方
            String outputUserIdKey=String.format("user:%s", "2");
            conn.del(inputUserIdKey);
            conn.del(outputUserIdKey);
            //设置默认值
            conn.hset(outputUserIdKey,"money","100");
            conn.hset(inputUserIdKey,"money","50");
            boolean processStatus=false;
            int index=0;
            do {
                index++;//重试3次
                processStatus= transaction(conn, "1", "2", 100);
            }while (!processStatus&&index<=3);//cas重试
            //打印转出后金额
            System.out.println(processStatus?"转账成功!":"转账失败!");
            System.out.println("转出方余额:"+conn.hget(outputUserIdKey,"money"));
            System.out.println("转入方余额:"+conn.hget(inputUserIdKey,"money"));
        }
    
        public static boolean transaction(Jedis conn, String inputUserId, String outUserId, Integer tranMoney) {
            String outUserKey = String.format("user:%s", outUserId);
            String inputUserKey = String.format("user:%s", inputUserId);
            //监控转出方金额 防止金额变化 不足以扣除
            conn.watch(String.format("user:%s", outUserId));
            //分为单位
            Long money = Long.valueOf(conn.hget(outUserKey, "money"));
            if (money < tranMoney) {
                System.out.println("余额不足");
                return false;
            }
            Transaction transaction= conn.multi();
            transaction.hincrBy(outUserKey, "money", -money);
            transaction.hincrBy(inputUserKey, "money", money);
            List<Object> result=  transaction.exec();
            //如果监控值改变返回的是空集合
            return  result!=null&&result.size()>0;
        }
  • 相关阅读:
    linux防火墙关闭与中文显示乱码排错
    linux基础命令
    盒子模块
    表的数据类型
    pymysql模块
    sql综合练习题
    pymysql内置功能
    数据操作
    vue 左侧菜单展示,以及对应的路由配置
    vue 左侧菜单路由实现
  • 原文地址:https://www.cnblogs.com/LQBlog/p/13321449.html
Copyright © 2020-2023  润新知