最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java使用Redis實(shí)現(xiàn)秒殺功能

 更新時(shí)間:2020年09月29日 14:25:53   作者:楚瑞濤  
這篇文章主要為大家詳細(xì)介紹了Java使用Redis實(shí)現(xiàn)秒殺功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

秒殺功能

秒殺場景現(xiàn)在已經(jīng)非常常見了,各種電商平臺(tái)都有秒殺的產(chǎn)品,接下來我們模擬一個(gè)秒殺的項(xiàng)目,最終能夠確保高并發(fā)下的線程安全。界面比較簡單,但是功能基本實(shí)現(xiàn)。

界面

點(diǎn)擊“秒殺點(diǎn)我”按鈕后臺(tái)就會(huì)輸出秒殺結(jié)果。

第一版

使用Redis緩存數(shù)據(jù)庫,使用一個(gè)key-value存儲(chǔ)秒殺商品數(shù)量,使用set集合存儲(chǔ)秒殺成功的用戶。我們以商品0101為示例,設(shè)置商品的初始數(shù)量為200件。不考慮并發(fā)問題,實(shí)現(xiàn)功能。

html、jsp、servlet文件不重要省略。

package com.redis.secondskill;
 
import java.util.List;
 
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Transaction;
 
public class SS0 {
 public static boolean doSecKill(String uid,String prodid) {
 JedisPool jedisPool = JedisPollTool.getInstance();
 Jedis jedis = jedisPool.getResource();
 String productCountStr = "sec:"+prodid+":count";
 String productUserStr = "sec:"+prodid+":user";
 String productCount = jedis.get(productCountStr);
 if(null == productCount) {
 System.out.println("秒殺還沒有開始");
 JedisPollTool.distroy(jedisPool, jedis);
 return false;
 }
 if(jedis.sismember(productUserStr, uid)) {
 System.out.println(uid + "用戶已經(jīng)秒殺成功");
 JedisPollTool.distroy(jedisPool, jedis);
 return false;
 }
 int prodCount = Integer.parseInt(productCount);
 if(prodCount <= 0) {
 System.out.println("秒殺結(jié)束");
 JedisPollTool.distroy(jedisPool, jedis);
 return false;
 }
 jedis.decr(productCountStr);
 jedis.sadd(productUserStr, uid);
 
 JedisPollTool.distroy(jedisPool, jedis);
 System.out.println(uid + "秒殺成功");
 return true;
 }
}

使用linux httpd-tools工具進(jìn)行并發(fā)測(cè)試。

ab -n 1000 -c 200 -p /test/file.txt -T "application/x-www-form-urlencoded" 192.168.0.101:8080/redis-demo/ss

結(jié)果

從結(jié)果大致來看,沒有什么問題,來查看一個(gè)后臺(tái)Redis的數(shù)據(jù)

秒殺的結(jié)果里面居然有負(fù)數(shù),證明賣超了。

第二版

使用Redis的事務(wù),保證沒有超賣的情況發(fā)生。

package com.redis.secondskill;
 
import java.util.List;
 
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Transaction;
 
public class SS1 {
 public static boolean doSecKill(String uid,String prodid) {
 JedisPool jedisPool = JedisPollTool.getInstance();
 Jedis jedis = jedisPool.getResource();
 String productCountStr = "sec:"+prodid+":count";
 String productUserStr = "sec:"+prodid+":user";
 jedis.watch(productCountStr); //開始監(jiān)視
 String productCount = jedis.get(productCountStr);
 if(null == productCount) {
 System.out.println("秒殺還沒有開始");
 JedisPollTool.distroy(jedisPool, jedis);
 return false;
 }
 if(jedis.sismember(productUserStr, uid)) {
 System.out.println(uid + "用戶已經(jīng)秒殺成功");
 JedisPollTool.distroy(jedisPool, jedis);
 return false;
 }
 int prodCount = Integer.parseInt(productCount);
 if(prodCount <= 0) {
 System.out.println("秒殺結(jié)束");
 JedisPollTool.distroy(jedisPool, jedis);
 return false;
 }
 Transaction transaction = jedis.multi();
 transaction.decr(productCountStr);
 transaction.sadd(productUserStr, uid);
 List<Object> exec = transaction.exec();
 
 
 if(exec == null || exec.size() == 0) {
 System.out.println("秒殺失敗,稍后重試");
 JedisPollTool.distroy(jedisPool, jedis);
 return false;
 }
 JedisPollTool.distroy(jedisPool, jedis);
 System.out.println(uid + "秒殺成功");
 return true;
 }
}

結(jié)果

由于使用了watch和事務(wù),每次的并發(fā)線程訪問中只有一個(gè)線程能夠提交成功,可以保證不出現(xiàn)超賣的現(xiàn)象,但是對(duì)于一些用戶來說是極其不公平的。

第三版

使用Lua腳本來實(shí)現(xiàn),因?yàn)镽edis是單線程的,又是C語言編寫的,可以使用Lua調(diào)用Redis的命令,Lua會(huì)具有排他性,所以能夠保證安全。

package com.redis.secondskill;
 
import java.util.HashSet;
import java.util.Set;
 
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
 
public class SS2 {
 
 static String luaScript ="local userid=KEYS[1];\r\n" + 
 "local prodid=KEYS[2];\r\n" + 
 "local qtkey='sec:'..prodid..\":count\";\r\n" + 
 "local usersKey='sec:'..prodid..\":user\";\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" ;
 
 public static boolean doSecKill(String uid,String prodid) {
 JedisPool jedisPool = JedisPollTool.getInstance();
 Jedis jedis = jedisPool.getResource();
 String sha1 = jedis.scriptLoad(luaScript);
 
 Object result= jedis.evalsha(sha1, 2, uid,prodid);
 
 String reString=String.valueOf(result);
 if ("0".equals( reString ) ) {
 System.err.println("已搶空??!");
 }else if("1".equals( reString ) ) {
 System.out.println(uid + "搶購成功?。。?!");
 }else if("2".equals( reString ) ) {
 System.err.println("該用戶已搶過??!");
 }else{
 System.err.println("搶購異常!!");
 }
 JedisPollTool.distroy(jedisPool, jedis);
 return true;
 
 }
}

結(jié)果

這才是我們最希望看到的結(jié)果!

以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Scala方法與函數(shù)使用和定義詳解

    Scala方法與函數(shù)使用和定義詳解

    這個(gè)章節(jié)會(huì)很燒腦,需要認(rèn)真研讀,我會(huì)盡量寫的詳細(xì)一些。 方法和函數(shù),看似是兩個(gè)概念,其實(shí)他嚴(yán)格來說也是兩個(gè)概念,但我們大可以理解成是同一個(gè)概念,在使用時(shí)只有語法上的細(xì)微差別,是很類似的,都理解為function即可
    2022-12-12
  • 關(guān)于druid連接池的使用詳解

    關(guān)于druid連接池的使用詳解

    文章介紹了Druid連接池的兩種使用方式:直接在代碼中配置和通過配置文件配置,同時(shí),文章詳細(xì)講解了如何在Web項(xiàng)目中啟用Druid的監(jiān)控功能,包括配置web.xml文件、設(shè)置過濾器等步驟,最后,文章還提到了Druid提供的加密解密工具,使數(shù)據(jù)庫密碼更安全
    2025-02-02
  • 詳解java代碼中init method和destroy method的三種使用方式

    詳解java代碼中init method和destroy method的三種使用方式

    這篇文章主要介紹了詳解java代碼中init method和destroy method的三種使用方式,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03
  • springboot項(xiàng)目docker分層構(gòu)建的配置方式

    springboot項(xiàng)目docker分層構(gòu)建的配置方式

    在使用dockerfile構(gòu)建springboot項(xiàng)目時(shí),速度較慢,用時(shí)比較長,為了加快構(gòu)建docker鏡像的速度,采用分層構(gòu)建的方式,這篇文章主要介紹了springboot項(xiàng)目docker分層構(gòu)建,需要的朋友可以參考下
    2024-03-03
  • MyBatis-Plus之邏輯刪除的實(shí)現(xiàn)

    MyBatis-Plus之邏輯刪除的實(shí)現(xiàn)

    這篇文章主要介紹了MyBatis-Plus之邏輯刪除的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • springboot連接sqllite遇到的坑及解決

    springboot連接sqllite遇到的坑及解決

    這篇文章主要介紹了springboot連接sqllite遇到的坑及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • 淺析java中String類型中“==”與“equal”的區(qū)別

    淺析java中String類型中“==”與“equal”的區(qū)別

    這篇文章主要介紹了淺析java中String類型中“==”與“equal”的區(qū)別,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-08-08
  • java微信企業(yè)號(hào)開發(fā)之開發(fā)模式的開啟

    java微信企業(yè)號(hào)開發(fā)之開發(fā)模式的開啟

    這篇文章主要為大家詳細(xì)介紹了java微信企業(yè)號(hào)開發(fā)之開發(fā)模式的開啟方法,感興趣的小伙伴們可以參考一下
    2016-06-06
  • java查找文件夾下最新生成的文件的方法

    java查找文件夾下最新生成的文件的方法

    在本篇文章中我們給大家分享了關(guān)于java怎么查找文件夾下最新生成的文件的相關(guān)方法和知識(shí)點(diǎn),有需要的朋友們參考下。
    2019-07-07
  • Java Swing JProgressBar進(jìn)度條的實(shí)現(xiàn)示例

    Java Swing JProgressBar進(jìn)度條的實(shí)現(xiàn)示例

    這篇文章主要介紹了Java Swing JProgressBar進(jìn)度條的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12

最新評(píng)論

桑植县| 潜江市| 青浦区| 凤城市| 泸州市| 峨眉山市| 安平县| 定南县| 荣成市| 乌兰浩特市| 阿坝| 闽清县| 穆棱市| 富蕴县| 铜山县| 昭平县| 兴文县| 文成县| 白朗县| 墨竹工卡县| 扎鲁特旗| 股票| 北宁市| 南澳县| 昌平区| 衡阳市| 龙南县| 仲巴县| 昌宁县| 年辖:市辖区| 喀喇沁旗| 香港 | 工布江达县| 香格里拉县| 汝南县| 兴文县| 香港 | 额尔古纳市| 筠连县| 贺兰县| 桃源县|