Skip to content

超时和超卖问题解决

超卖问题

利用乐观锁淘汰用户,解决超卖问题。

代码

shell
package com.atguigu;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Transaction;

import java.io.IOException;
import java.util.List;

/**
 *
 */
public class SecKill_redis_advance {

	public static void main(String[] args) {
		Jedis jedis =new Jedis("192.168.117.134",6379);
		System.out.println(jedis.ping());
		jedis.close();
	}

	//秒杀过程
	public static boolean doSecKill(String uid,String prodid) throws IOException {
		//1 uid和prodid非空判断
		if(uid == null && prodid == null){
               return false;
		}

		//2 连接redis
		//通过连接池得到jedis对象
		JedisPool jedisPoolInstance = JedisPoolUtil.getJedisPoolInstance();
		Jedis jedis = jedisPoolInstance.getResource();

		//3 拼接key
		// 3.1 库存key
		String kcKey="sk:"+prodid+":qt";

		// 3.2 秒杀成功用户key
		String userKey="sk:"+prodid+":user";

		//监视库存 加乐观锁

		jedis.watch(kcKey);

		//4 获取库存,如果库存null,秒杀还没有开始
		String kcVal = jedis.get(kcKey);

		if(kcVal == null){
			System.out.println("秒杀还没有开始,请等待。");
			jedis.close();
			return false;
		}


		// 5 判断用户是否重复秒杀操作
		Boolean sismember = jedis.sismember(userKey, uid);
		if(sismember){
			System.out.println("已经秒杀过了,不能重复秒杀");
			jedis.close();
			return false;
		}
		//6 判断如果商品数量,库存数量小于1,秒杀结束
		int intKcVal = Integer.parseInt(kcVal);
		if(intKcVal<=0){
			System.out.println("秒杀结束");
			jedis.close();
			return false;
		}

		//7 秒杀过程
		//使用事务
		Transaction multi = jedis.multi();

		//组队操作
		multi.decr(kcKey);
		multi.sadd(userKey,uid);
		List<Object> result = multi.exec();
		if(result == null && result.size() ==0){
			System.out.println("事物中秒杀失败");
			jedis.close();
			return false;
		}
		
		System.out.println("秒杀成功");
		return true;
	}
}

继续增加并发测试

设置库存

ab工具模拟测试

shell
ab -n 1000 -c 100 -k -p /ab/postfile -T application/x-www-form-urlencoded http://192.168.10.1:8080/Seckill/doseckill

连接超时,使用连接池

shell
package com.atguigu;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class JedisPoolUtil {
	private static volatile JedisPool jedisPool = null;

	private JedisPoolUtil() {
	}

	public static JedisPool getJedisPoolInstance() {
		if (null == jedisPool) {
			synchronized (JedisPoolUtil.class) {
				if (null == jedisPool) {
					JedisPoolConfig poolConfig = new JedisPoolConfig();
					poolConfig.setMaxTotal(2000);
					poolConfig.setMaxIdle(32);
					poolConfig.setMaxWaitMillis(100*1000);
					poolConfig.setBlockWhenExhausted(true);
					poolConfig.setTestOnBorrow(true);  // ping  PONG
				 
					jedisPool = new JedisPool(poolConfig, "192.168.117.134", 6379, 60000 );
				}
			}
		}
		return jedisPool;
	}

	public static void release(JedisPool jedisPool, Jedis jedis) {
		if (null != jedis) {
			jedisPool.returnResource(jedis);
		}
	}

}