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;
}
}