redis實現秒殺功能例子(採用lua的原子性保證資料的一致性)
阿新 • • 發佈:2018-12-25
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import redis.clients.jedis.Jedis; @Service public class RedisServiceImpl { @Autowired private RedisTemplate template; //lua指令碼 private String script = "local number = ARGV[1] \n" + "local gsave = redis.call('hget','goods_'..KEYS[1],'gsave') \n" + "if gsave < number then \n" + "return 2 \n" + "end\n" + "gsave = gsave - number \n" + "redis.call('hset','goods_'..KEYS[1],'gsave',gsave)\n" + "redis.call('rpush','orders_'..KEYS[1],ARGV[2])\n" + "if gsave <= 0 then\n" + "return 0\n"+ "else \n" + "return 1\n" + "end"; private String sha1 = null; //lua指令碼-原子性保證了資料的一致性 public int miaosha(Integer gid, Integer number, Integer uid){ Jedis jedis = (Jedis)template.getConnectionFactory().getConnection().getNativeConnection(); //載入指令碼 if(sha1 == null){ sha1 = jedis.scriptLoad(script); } //執行指令碼 String orderinfo = uid + "-" +number + "-" +System.currentTimeMillis();//訂單資訊 Long result = (Long)jedis.evalsha(sha1, 1,gid+"",number+"",orderinfo); //搶購結束 if(result == 0){ // 非同步去執行插入資料庫的方法 // 注入IGoodsService,(<!-- // 配置這個後在方法前加註解@Async該方法就會變成非同步的方法 // --> // <task:executor id="executor" pool-size="5"/> // <task:annotation-driven executor="executor"/>) // 再呼叫代理會幫我們實現非同步 // goodsService.synDataBase(gid) // 從redis中獲得訂單詳情及賣出數量再批量插入 } return Integer.parseInt(result.toString()); } }