Realized commodity spike of --Redis Watch mechanism

Watch command

       watch command can monitor one or more keys, once one of which keys were modified or deleted after the transaction will not be executed. Monitoring continued until the exec command, transaction command is executed only after the exec, so you can modify the watch to monitor key after multi command. Suppose we watch command by monitoring a number of Key prior to transaction execution, when there is any value in Key has changed after the watch, the exec command to execute the transaction will be discarded.

Application in the business

1. Create Redis operating tools

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
 
@Service
public class RedisService {
	
	@Autowired
	private JedisPool jedisPool;
	
	/**
	 * 获取对象
	 */
	public <T> T get(String key,Class<T> clazz){
	    Jedis jedis = null;
	    try {
		jedis = jedisPool.getResource();
		String sval = jedis.get(key);
		//将String转换为Bean
		T t = stringToBean(sval,clazz);
		return t;
	    }finally {
		if(jedis != null) {	
		    jedis.close();
		}
	    }
        }
	
	/**
	 * 设置对象
	 */					
	public <T> boolean set(String key,T value){
	    Jedis jedis = null;
	    try {
	    	jedis = jedisPool.getResource();
		//将Bean转换为String
		String s = beanToString(value);
		if(s == null || s.length() <= 0) {
		    return false;
		}
		jedis.set(key, s);
		return true;
	    }finally {
	        if(jedis != null) {	
	    	    jedis.close();
	        }
	    }
        }
	
	/**
	 * 减少值
	 */
	public <T> Long decr(String key){
	    Jedis jedis = null;
	    try {
	    	jedis = jedisPool.getResource();
	    	//返回value减1后的值
	    	return jedis.decr(key);
	    }finally {
	    	if(jedis != null) {	
	    	    jedis.close();
	    	}
	    }
        }
	
	/**
	 * 将字符串转换为Bean对象
	 */
	@SuppressWarnings("unchecked")
	public static <T> T stringToBean(String str,Class<T> clazz) {
	    if(str == null || str.length() == 0 || clazz == null) {
	    	return null;
	    }		
	    if(clazz == int.class || clazz == Integer.class) {
	    	return ((T) Integer.valueOf(str));
	    }else if(clazz == String.class) {
	    	return (T) str;
	    }else if(clazz == long.class || clazz == Long.class) {
	    	return (T) Long.valueOf(str);
	    }else if(clazz == List.class) {
	    	return JSON.toJavaObject(JSONArray.parseArray(str), clazz);
	    }else {
	    	return JSON.toJavaObject(JSON.parseObject(str), clazz);
	    }		
        }
	
	/**
	 * 将Bean对象转换为字符串类型
	 */
	public static <T> String beanToString(T value) {
	    if(value == null){
	    	return null;
	    }
	    Class<?> clazz = value.getClass();
	    if(clazz == int.class || clazz == Integer.class) {
	    	return ""+value;
	    }else if(clazz == String.class) {
	    	return (String)value;
	    }else if(clazz == long.class || clazz == Long.class) {
	    	return ""+value;
	    }else {
	    	return JSON.toJSONString(value);
	    }		
	}
	
}

2. The business calls spike

import java.util.HashMap;
import java.util.List;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Response;
import redis.clients.jedis.Transaction;
import cn.com.app.redis.RedisService;

@Controller
public class RedisWatchController implements InitializingBean {
	
    @Autowired
    private RedisService redisService;
    @Autowired
    private JedisPool jedisPool;
	
    //内存标记,减少redis访问
    private HashMap<String, Boolean> localOverMap =  new HashMap<String, Boolean>();
    
	/**
	 * 系统初始化的时把商品库存加入到缓存中
	 */
	@Override
	public void afterPropertiesSet() throws Exception {
	    //设置默认商品库存
	    redisService.set("goodsStock", "10");
            //添加内存标记
	    localOverMap.put("goodsStock", false);
	}
    
	/**
         * 请求秒杀,redis watch事务方式
         */
	@RequestMapping(value="/miaoshawatch")
	@ResponseBody
        public String miaoshawatch(HttpServletRequest request,@RequestParam("userid")String userid){
    	    boolean over = localOverMap.get("goodsStock");
    	    if(over) {
    		System.out.println("秒杀结束");
    		return "秒杀结束";
    	    }
    	    Jedis jedis = null;
	    try {
	        jedis = jedisPool.getResource();
		//监视商品库存key和订单key
		jedis.watch("goodsStock","order"+userid);
	    	int count = redisService.get("goodsStock",Integer.class);
	    	if(count <= 0){
	    	    localOverMap.put("goodsStock", true);
	    	    System.out.println("库存不足");
	    	    return "库存不足";
	    	}
	    	String orderInfo = redisService.get("order"+userid,String.class);
		if(orderInfo != null){
		    System.out.println("重复下单");
		    return "重复下单";
		}
		//开启事务    
		Transaction transaction = jedis.multi();
		//保存订单
		transaction.set("order"+userid, userid+"_"+UUID.randomUUID().toString());
	        //扣减库存
		Response<Long> v = transaction.decrBy("goodsStock",1);
	        List<Object> result = transaction.exec();
		if(result == null || result.isEmpty()){
	            System.out.println("秒杀失败");
	            return "秒杀失败";
	        }
	        System.out.println("秒杀成功,剩余:" + v.get().intValue());
	        /**
        	 * 数据库操作减少库存,下订单,在一个事务中
        	 */        
	}finally {
	    if(jedis != null) {	
		jedis.close();
	    }
	}
	return "秒杀成功";
    }
}

 

Published 95 original articles · won praise 131 · views 160 000 +

Guess you like

Origin blog.csdn.net/rexueqingchun/article/details/104007636