模拟秒杀并发状态(redis)

一个模拟秒杀的页面

image-20210926162204226

失败情况:

image-20210926162632037

image-20210926162650624

成功情况:

image-20210926162734674

页面代码:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<%
    String basePath = request.getScheme()
            + "://"
            + request.getServerName()
            + ":"
            + request.getServerPort()
            + request.getContextPath()
            + "/";
    pageContext.setAttribute("basePath",basePath);
%>

<base href="<%=basePath%>"/>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="jquery/jquery-3.1.0.js"></script>
<script type="text/javascript">
    $(function () {
        $("#btn_ms").click(function () {
            $.getJSON("${pageScope.basePath}SecKillServlet", "action=dosecKill&prodid=0101", function (data) {
                if (data.isSuccess) {
                    alert("抢购成功");
                }
               else{
                    alert("抢购失败");
                    $("#btn_ms").attr("disabled", true);

                }
            });
        });
    })
</script>
<head>
    <title>秒杀界面</title>
</head>
<body>
<h1 >商品秒杀</h1>
    <input type="hidden" name="action" value="dosecKill"/>--%>
   
    <input  align="center" type="button" id="btn_ms" name="btn_seckillms" value="点击秒杀"/>
</body>
</html>

redis连接池设置:

public class JedisPoolUtil {
    private static volatile JedisPool jedisPool = null;

    private JedisPoolUtil() {
    }

    public static JedisPool getJedisPoolInstance() {
        if (null == jedisPool) {
            synchronized (JedisPoolUtil.class) {
                if (null == jedisPool) {
                    JedisPoolConfig poolConfig = new JedisPoolConfig();
                    poolConfig.setMaxTotal(200);
                    poolConfig.setMaxIdle(32);
                    poolConfig.setMaxWaitMillis(10000);
                    poolConfig.setBlockWhenExhausted(true);
                    poolConfig.setTestOnBorrow(true);  // ping  PONG

                    jedisPool = new JedisPool(poolConfig, "192.168.233.128", 6379, 60000,"password" );
                }
            }
        }
        return jedisPool;
    }

}

这里使用懒汉式单例模式是,保证线程安全,仅构造一个连接池

service层调用lua脚本,解决库存遗留问题

public class SecKillService {

    private static final  org.slf4j.Logger logger =LoggerFactory.getLogger(SecKillService.class) ;

    static String secKillScript ="local userid=KEYS[1];\r\n" +
            "local prodid=KEYS[2];\r\n" +
            "local qtkey='sk:'..prodid..\":qt\";\r\n" +
            "local usersKey='sk:'..prodid..\":usr\";\r\n" +
            "local userExists=redis.call(\"sismember\",usersKey,userid);\r\n" +
            "if tonumber(userExists)==1 then \r\n" +
            "   return 2;\r\n" +
            "end\r\n" +
            "local num= redis.call(\"get\" ,qtkey);\r\n" +
            "if tonumber(num)<=0 then \r\n" +
            "   return 0;\r\n" +
            "else \r\n" +
            "   redis.call(\"decr\",qtkey);\r\n" +
            "   redis.call(\"sadd\",usersKey,userid);\r\n" +
            "end\r\n" +
            "return 1" ;

    static String secKillScript2 =
            "local userExists=redis.call(\"sismember\",\"{sk}:0101:usr\",userid);\r\n" +
                    " return 1";

    public static boolean doSeckill(String uid, String prodid) {
        JedisPool jedisPool = JedisPoolUtil.getJedisPoolInstance();
        Jedis jedis = jedisPool.getResource();

        String sha1 = jedis.scriptLoad(secKillScript);


        Object result = jedis.evalsha(sha1, 2, uid, prodid);


        String reString = String.valueOf(result);

        if ("0".equals(reString)) {
            System.out.println("已抢空");
            jedis.close();
            return false;
        } else if ("1".equals(reString)) {
            System.out.println("抢购成功");
            jedis.close();
            return true;
        } else if ("2".equals(reString)) {
            System.out.println("该用户已抢过");
            jedis.close();
            return false;
        } else {
            System.out.println("抢购异常");
            jedis.close();
            return false;
        }

    }
}

web层使用反射调用需要调用的方法

public class BaseServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html; charset=UTF-8");

        String action = req.getParameter("action");

        try{
            Method method = this.getClass().getDeclaredMethod(action,HttpServletRequest.class,HttpServletResponse.class);
            method.invoke(this,req,resp);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

真正需要被调用的方法:

public class SecKillServlet extends BaseServlet {
    private static final long serialVersionUID = 1L;



    public void dosecKill(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        String userid = new Random().nextInt(50000) + "";
        String prodid = req.getParameter("prodid");
        boolean isSuccess = false;
//        try {
            isSuccess = SecKillService.doSeckill(userid, prodid);
//        }catch(Exception e){

//        }
        Map<String,Object> resultMap = new HashMap();
        resultMap.put("isSuccess",isSuccess);
        Gson gson = new Gson();
        String json = gson.toJson(resultMap);
        resp.getWriter().write(json);
    }

}

使用ajax处理请求,免去页面刷新

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Best-Wishes

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值