• Redis(五)


    Redis事务-秒杀案例

    讲解了之前的知识,我们来做一个秒杀实例

    本文只提供后台jedis操作代码

    基础代码:

    设置Redis库存: set SecKill:0101:kc 10

     public static boolean doSecKill(String uid,String prodid) throws IOException{
    
            //拼接key
            String kcKey="SecKill:"+prodid+":kc";
            String userKey="SecKill:"+prodid+":user";
            Jedis jedis=new Jedis("127.0.0.1",6379);
            //获取库存
            String kc = jedis.get(kcKey);
            //秒杀还没开始,表示库存为null
            if (kc==null)
            {
                System.out.println("秒杀还未开始");
                jedis.close();
                return false;
            }
            //已经秒杀成功,表示为存储uid的set中已经有该用户uid
            if (jedis.sismember(userKey,uid)) {
                System.out.println("已经秒杀成功,不可重复秒杀");
                jedis.close();
                return false;
            }
            //判断库存,若大于0,则减库存加人,若小于等于0,秒杀失败
            if (Integer.parseInt(kc)<=0)
            {
                System.out.println("秒杀已结束");
                jedis.close();
                return false;
            }
            //库存大于0,减库存,加人
            jedis.decr(kcKey);
            jedis.sadd(userKey,uid);
            System.out.println("秒杀成功");
            jedis.close();
            return true;
        }

    可以使用ab工具模拟并发秒杀场景

    ab工具在CentOS6可默认安装,CentOS7手动安装

    联网 yum install httpd-tools

    无网络:

    (1) 进入 cd/run/media/root/CentOS 7/x86_64/Packages(路径跟CentOS6不同,镜像文件放安装包的文件夹)

    (2) 顺序安装

    安装命名 rpm-ivh

    apr-1.4.8-3.el7.x86_64.rpm

    apr-util-1.5.2-6-el7.x86_64.rpm

    httpd-tools-2.4.6-67.el7.centos.x86_64.rpm

    ab工具使用简介

    ab -n 请求数 -c并发数 -p 指定请求数据文件 -T “application/x-www-form-urlencoded” 测试的请求

    例如:

    使用ab工具检验并发环境时,会出现以下问题:

    并发下的超卖问题

     解决办法:使用redis的watch进行监视,加入Redis的事务

    public static boolean doSecKill(String uid,String prodid) throws IOException{
    
            //拼接key
            String kcKey="SecKill:"+prodid+":kc";
            String userKey="SecKill:"+prodid+":user";
            Jedis jedis=new Jedis("127.0.0.1",6379);
            //监视库存,以解决超卖问题
            jedis.watch(kcKey);
            //获取库存
            String kc = jedis.get(kcKey);
            //秒杀还没开始,表示库存为null
            if (kc==null)
            {
                System.out.println("秒杀还未开始");
                jedis.close();
                return false;
            }
            //已经秒杀成功,表示为存储uid的set中已经有该用户uid
            if (jedis.sismember(userKey,uid)) {
                System.out.println("已经秒杀成功,不可重复秒杀");
                jedis.close();
                return false;
            }
            //判断库存,若大于0,则减库存加人,若小于等于0,秒杀失败
            if (Integer.parseInt(kc)<=0)
            {
                System.out.println("秒杀已结束");
                jedis.close();
                return false;
            }
            //库存大于0,减库存,加人
            Transaction multi = jedis.multi();
            jedis.decr(kcKey);
            jedis.sadd(userKey,uid);
            List<Object> list = multi.exec();
            if (list==null||list.size()==0)
            {
                System.out.println("秒杀失败");
                jedis.close();
                return false;
            }
            System.out.println("秒杀成功");
            jedis.close();
            return true;
        }

    执行代码后,我们发现,会产生库存遗留问题,因为在同一并发下,只有一个用户才能秒杀成功

    因为watch会监视key,只要key里面的value发生变化,事务里的其他操作便都不执行了

    可以使用Lua脚本解决

    Lua简介

    Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。(不了解者可自行google学习,这里不再叙述)

     

    有时,并发环境会出现连接超时问题,这时候,我们就需要引入jedis连接池来处理

    public Jedis getJedis()
        {
            JedisPool jedisPool;
            JedisPoolConfig poolConfig=new JedisPoolConfig();
            poolConfig.setMaxTotal(200);// 可用连接实例的最大数目,如果赋值为-1,表示不限制.默认值为8
            poolConfig.setMaxIdle(32); //jedis最大保存idel(空闲的)状态的对象,默认值也是8
            poolConfig.setMaxWaitMillis(100*1000); //jedis池没有对象返回时,最大等待时间
            poolConfig.setBlockWhenExhausted(true);//连接耗尽时是否阻塞, false报异常,true阻塞直到超时, 默认true
            poolConfig.setTestOnBorrow(true);// 在borrow一个jedis实例时,是否提前进行validate操作,如果为true,则得到的jedis实例均是可用的
            jedisPool=new JedisPool(poolConfig,"127.0.0.1",6379,10000);
            Jedis jedis = jedisPool.getResource();
            return jedis;
    
        }
  • 相关阅读:
    PhoneGap源码分析8——cordova
    PhoneGap源码分析9——引导程序与channel.join
    JavaScript高级程序设计(第3版)学习笔记9——函数(下)
    PhoneGap源码分析7——cordova/channel
    JavaScript高级程序设计(第3版)学习笔记13——ECMAScript5新特性
    JavaScript高级程序设计(第3版)学习笔记1——概述
    JavaScript高级程序设计(第3版)学习笔记4——运算符和操作符
    JavaScript高级程序设计(第3版)学习笔记7——函数(上)
    JavaScript高级程序设计(第3版)学习笔记3——简单数据类型
    JavaScript高级程序设计(第3版)学习笔记2——基础语法
  • 原文地址:https://www.cnblogs.com/qyx66/p/12203573.html
Copyright © 2020-2023  润新知