redis实现分布式锁 商品秒杀lua脚本

redis.clients jedis 2.9.0 @Component public class RedisTest {
private static final String LOCK_SUCCESS = "OK";
private static final String SET_IF_NOT_EXIST = "NX";
private static final String SET_WITH_EXPIRE_TIME = "PX";
private static final Long RELEASE_SUCCESS = 1L;
private static final String UUIDREDIS = UUID.randomUUID().toString();

// private static ShardedJedisPool pool;
// static {
// JedisPoolConfig config = new JedisPoolConfig();
// config.setMaxTotal(100);
// config.setMaxIdle(50);
// config.setMaxWaitMillis(3000);
// config.setTestOnBorrow(true);
// config.setTestOnReturn(true);
// // 集群
// JedisShardInfo jedisShardInfo1 = new JedisShardInfo(“192.168.31.30”, 6379);
// jedisShardInfo1.setPassword(“pg@123321”);
// List list = new LinkedList();
// list.add(jedisShardInfo1);
// pool = new ShardedJedisPool(config,list);
// }

//如果不是一步操作原子性 中间断掉无过期时间就可能死锁
public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {
    String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
    if (LOCK_SUCCESS.equals(result)) {
        return true;
    }
    return false;
}

//不校验value锁的拥有者 会导致客户端都可以删除
public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {
    String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
    Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));

    if (RELEASE_SUCCESS.equals(result)) {
        return true;
    }
    return false;
}

@PostConstruct
public static void test(){
    Jedis jedis = new Jedis("192.168.31.30", 6379);
    jedis.auth("pg@123321");
    if(tryGetDistributedLock(jedis,"RedisTest-test",UUIDREDIS,20*1000)){
        System.out.println("加锁成功");
        //数据库操作
        if(releaseDistributedLock(jedis,"RedisTest-test",UUIDREDIS)){
            System.out.println("解锁成功");
        }else {
            System.out.println("解锁失败");
        }
    }else{
        System.out.println("加锁失败");
    }
}


//set命令 sismember是否包含集合中
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" ;



@PostConstruct
public void test2(){
    Jedis jedis = new Jedis("192.168.31.30", 6379);
    jedis.auth("pg@123321");
    jedis.set("sec:2:count", "100");

    AtomicInteger atomicInteger = new AtomicInteger(0);
    while(true){
        boolean result = doSecKill(jedis,UUID.randomUUID().toString(),"2");
        if(result == false){
            break;
        }else{
            atomicInteger.incrementAndGet();
        }
    }
    System.out.println("result:"+atomicInteger.get());

}
public boolean doSecKill(Jedis jedis,String uid,String prodid) {

    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("已抢空!!");
        return false;
    }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;

}

}

上一篇:Lua基础知识


下一篇:openresty安装配置