redis-事務解決高並發問題


1,Redis事務是一個單獨的隔離操作:事務中的所有命令都會序列化、按順序地執行。事務在執行的過程中,不會被其他客戶端發送來的命令請求所打斷。

2,Redis事務的主要作用就是串聯多個命令防止別的命令插隊

3,從輸入Multi命令開始,Exec開始執行,discard結束

 

4,關於高並發問題事務時如何解決的

       例如秒殺20個商品,會出現的問題,1,庫存會出現復數,為何會這樣呢?因為如30個用戶同時拿到數據,都會進行減1操作,庫存就會出現-10;

                                                                 2, 庫存剩余問題

       那如何解決呢?

             解決超賣問題?思路是 利用redis   watch監聽商品變化,把需要減商品的步驟放入multi中,當watch(key) 發生變化時,會自動取消事務,但是這樣

        會出現問題2,商品庫存遺留問題,因為比如我們設置並發量為200,其中只有1個人能夠成功,這樣就會出現遺留問題,

       解決庫存剩余問題 我是利用lua腳本解決的,LUA腳本是類似redis事務,有一定的原子性,不會被其他命令插隊,可以完成一些redis事務性的操作。

詳情見下面代碼:

         


public class SecKill_redisByScript {

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

public static void main(String[] args) {


JedisPool jedispool = JedisPoolUtil.getJedisPoolInstance();

Jedis jedis=jedispool.getResource();
System.out.println(jedis.ping());

Set<HostAndPort> set=new HashSet<HostAndPort>();


// doSecKill("201","sk:0101");


}

static String secKillScript ="local userid=KEYS[1];\r\n" +
"local prodid=KEYS[2];\r\n" +
"local qtkey='Seckill:'..prodid..\":kc\";\r\n" +
"local usersKey='Seckill:'..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" ;

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


public static boolean doSecKill(String uid,String prodid) throws IOException {

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.err.println("已搶空!!");
}else if("1".equals( reString ) ) {
System.out.println("搶購成功!!!!");
}else if("2".equals( reString ) ) {
System.err.println("該用戶已搶過!!");
}else{
System.err.println("搶購異常!!");
}



jedis.close();

return true;

}



}

               

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM