Redis客户端之Jedis(二)demo

redis使用的频次过多,key值的分散使用,可能会导致key值的重复或者混乱,下面的demo为了使key值简明易懂,进行格式化。

即key = keyFormat + keyValues 。keyFormat为格式化字符串,可以用占位符占位keyValues,组成一个完整的Key,因为keyFormat中规定keyValues可以不传或者传多个,因此keyValues是可变长度。

如keyFormat可以为:product:lock:{productId}、product:lock:{productId}:{userId}、product:lock。现在使用格式化的key来实现缓存和处理并发。

项目结构如下:

1、pom:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.demo</groupId>
  <artifactId>redisformat</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
  <parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.4.1.RELEASE</version>
	</parent>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.1.1</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.21</version>
		</dependency>
		
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.33</version>
		</dependency>
	</dependencies>
</project>

2、application.properties配置文件:


#mysql

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/produce?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=wtyy
#mybatis
mybatis.mapper-locations=classpath*:Mapper/*Mapper.xml


spring.redis.host=localhost
spring.redis.port=6379
#spring.redis.password=
spring.redis.database=1
spring.redis.pool.max-active=8
spring.redis.pool.max-wait=-1
spring.redis.pool.max-idle=500
spring.redis.pool.min-idle=0
spring.redis.timeout=0

3、serviceImpl:

package com.demo.serviceImpl;

import java.util.Date;

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

import com.demo.mapper.ProductMapper;
import com.demo.mapper.UserOrderMapper;
import com.demo.module.Product;
import com.demo.module.UserOrder;
import com.demo.service.OrderService;
import com.demo.service.ProductService;

@Service("orderService")
public class OrderServiceImpl implements OrderService {

	@Autowired
	private ProductService productService;

	@Autowired
	private UserOrderMapper userOrderMapper;

	// 用户下订单,返回订单id
	@Override
	public  Integer order(String productId, String userId) {
		// 先判断productId是否存在
		Product product = productService.getByProductId(productId);

		
			if (product == null) {
				return null;
			}
			// 是否有库存
			Integer id = product.getId();
			Integer total = product.getTotal();
			System.out.println("下单前库存" + total);

			UserOrder order = new UserOrder();
			if (total <= 0) {
				return null;
			}

			order.setCreatetime(new Date());
			order.setProductid(productId);
			order.setUserid(userId);
			int add = userOrderMapper.addOrder(order);
			if (add > 0) {
				// 创建订单成功,库存--
				total--;
				System.out.println("下单后库存" + total);
				productService.updateTotal(id, total);
				return order.getId();
			}
		return null;	
	}

	@Override
	public Integer getCountByProductId(String productId) {
		return userOrderMapper.getCountByProductId(productId);
	}

}


package com.demo.serviceImpl;

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

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.demo.mapper.ProductMapper;
import com.demo.module.Product;
import com.demo.service.ProductService;
import com.demo.util.RedisUtil;

 
@Service("productService")
public class ProductServiceImpl implements ProductService{
	@Autowired
	private ProductMapper productMapper;
	
	@Autowired
	private RedisUtil redisUtil;
	
	private String PRODUCT_KEY_FORMAT = "product:id:{productId}";

	@Override
	public Product getByProductId(String productId) {
		return productMapper.getByProductId(productId);
	}

	
	@Override
	public int updateTotal(Integer id, Integer total) {
		return productMapper.updateTotal(id,total);
	}

	@Override
	public Product getProductInfo(String productId) {
		String key = "productInfo"+productId;
		boolean exists = redisUtil.exists(PRODUCT_KEY_FORMAT, productId); 
		Product product = null;
		if(exists){
			
			String productStr = redisUtil.get(PRODUCT_KEY_FORMAT, productId);
			System.out.println("存在缓存"+productStr);
			product = JSON.parseObject(productStr,Product.class);
		}else{
			System.out.println("没有走缓存");
			 product = productMapper.getByProductId(productId);
			 String productStr = JSON.toJSONString(product);
			redisUtil.set(PRODUCT_KEY_FORMAT, productStr, productId);
			//设置缓存过期时间
			redisUtil.expire(PRODUCT_KEY_FORMAT, 10, productId);
		}
		return product;
	}

}

4、redis工具类:

package com.demo.util;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.ws.BindingType;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import com.alibaba.fastjson.JSONObject;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Tuple;

/**
 * @Description:redis工具类
 * @ClassName:
 * @date 2016年10月31日 上午11:25:06
 */
@SuppressWarnings("unused")
@Component
public class RedisUtil {
	private static final String IP = "127.0.0.1"; // ip
	private static final int PORT = 6379; // 端口
	// private static final String AUTH=""; // 密码(原始默认是没有密码)
	private static int MAX_ACTIVE = 1024; // 最大连接数
	private static int MAX_IDLE = 200; // 设置最大空闲数
	private static int MAX_WAIT = 10000; // 最大连接时间
	private static int TIMEOUT = 10000; // 超时时间
	private static boolean BORROW = true; // 在borrow一个事例时是否提前进行validate操作
	private static JedisPool pool = null;
	private static Logger logger = Logger.getLogger(RedisUtil.class);
	/**
	 * 初始化线程池
	 */
	static {
		JedisPoolConfig config = new JedisPoolConfig();
		config.setMaxTotal(MAX_ACTIVE);
		config.setMaxIdle(MAX_IDLE);
		config.setMaxWaitMillis(MAX_WAIT);
		config.setTestOnBorrow(BORROW);
		pool = new JedisPool(config, IP, PORT, TIMEOUT);
	}

	/**
	 * 获取连接
	 */
	public static synchronized Jedis getJedis() {
		try {
			if (pool != null) {
				return pool.getResource();
			} else {
				return null;
			}
		} catch (Exception e) {
			logger.info("连接池连接异常");
			return null;
		}

	}




	/**
	 * @Description: 关闭连接
	 * @param @param jedis
	 * @return void 返回类型
	 */

	public static void getColse(Jedis jedis) {
		if (jedis != null) {
			jedis.close();
		}
	}
	
	
	/**
	 * 格式化Key
	 */
	public static String format(String formatKey, String... keyValues) {
		if (keyValues == null || keyValues.length == 0) {
			return formatKey;
		}
		StringBuilder key = new StringBuilder();
		char[] chars = formatKey.toCharArray();
		int index = -1;
		boolean inmark = false;
		boolean firstinmark = false;
		for (int i = 0; i < chars.length; i++) {
			char ch = chars[i];
			if (ch == '{') {
				index++;
				inmark = true;
				firstinmark = true;
			} else if (ch == '}') {
				inmark = false;
			} else if (inmark) {
				if (firstinmark) {
					firstinmark = false;
					key.append(keyValues[index]);
				}
			} else {
				key.append(chars[i]);
			}
		}
		return key.toString();
	}

	/********************************** 针对key的操作 **************************************/

	/**
	 * 删除一个key
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param keyValues
	 *            key变量
	 * @return 被删除的keys的数量
	 */
	public Long del(String keyFormat, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.del(key);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 查询一个key是否存在
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param keyValues
	 *            key变量
	 * @return key是否存在。
	 */
	public boolean exists(String keyFormat, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.exists(key);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 设置一个key的过期的秒数
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param seconds
	 *            过期的秒数
	 * @param keyValues
	 *            key变量
	 * @return 1表示设置成功, 0 表示设置失败或者无法被设置
	 */
	public Long expire(String keyFormat, int seconds, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.expire(key, seconds);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 设置一个UNIX时间戳的过期时间
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param expireDate
	 *            过期时间
	 * @param keyValues
	 *            key变量
	 * @return 1表示设置成功, 0 表示设置失败或者无法被设置
	 */
	public Long expireAt(String keyFormat, Date expireDate, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.pexpireAt(key, expireDate.getTime());
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 移除给定key的生存时间,将这个 key 从『易失的』(带生存时间 key )转换成『持久的』(一个不带生存时间、永不过期的 key )。
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param keyValues
	 *            key变量
	 * @return 当生存时间移除成功时,返回 1 . 如果 key 不存在或 key 没有设置生存时间,返回 0 .
	 */
	public Long persist(String keyFormat, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.persist(key);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 设置一个key的过期的毫秒数
	 * 
	 * <pre>
	 * 这个命令和 EXPIRE 命令的作用类似,但是它以毫秒为单位设置 key 的生存时间,而不像 EXPIRE 命令那样,以秒为单位。
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param milliSeconds
	 *            过期的毫秒数
	 * @param keyValues
	 *            key变量
	 * @return 设置成功,返回 1,不存在或设置失败,返回 0
	 */
	public Long pexpire(String keyFormat, long milliSeconds,
			String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.pexpire(key, milliSeconds);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 获取key的有效毫秒数
	 * 
	 * <pre>
	 * 这个命令类似于 TTL 命令,但它以毫秒为单位返回 key 的剩余生存时间,而不是像 TTL 命令那样,以秒为单位。
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param keyValues
	 *            key变量
	 * @return 当 key 不存在时,返回 -2 。当 key 存在但没有设置剩余生存时间时,返回 -1 。否则,以毫秒为单位,返回 key
	 *         的剩余生存时间。
	 */
	public Long pttl(String keyFormat, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.pttl(key);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

//	/**
//	 * 将一个key重命名
//	 * 
//	 * <pre>
//	 * 	注意:重命名的旧key和新key必须都在同一个reids实例维护,否则将报异常
//	 * </pre>
//	 * 
//	 * @param keyFormat
//	 *            要重命名的key标识
//	 * @param newKeyFormat
//	 *            重命名目标key标识
//	 * @param newKeyValues
//	 *            重命名目标key变量
//	 * @param keyValues
//	 *            要重命名的key变量
//	 * @return Status code repy, "OK" 表示成功
//	 */
//	public String rename(String keyFormat, String newKeyFormat,
//			String[] newKeyValues, String... keyValues) {
//		String key = format(keyFormat, keyValues);
//		String newKey = format(newKeyFormat, newKeyValues);
//		Jedis jedis = null;
//		Jedis jedisNewKey = null;
//		try {
//			jedis = getJedis();
//			jedisNewKey = getJedis(newKeyFormat);
//			if (jedis != jedisNewKey) {
//				throw new RuntimeException(
//						String.format(
//								"rename 新key和旧key必须维护在同一个redis实例!keFormate:%s   newKeyFormat:%s",
//								keyFormat, newKeyFormat));
//			}
//			return jedis.rename(key, newKey);
//		} finally {
//			if (jedis != null) {
//				jedis.close();
//			}
//			if (jedisNewKey != null) {
//				jedisNewKey.close();
//			}
//		}
//	}

//	/**
//	 * 将一个key重命名,新的key必须是不存在的key
//	 * 
//	 * <pre>
//	 * 注意:重命名的旧key和新key必须都在同一个reids实例维护,否则将报异常。
//	 * 当且仅当 newkey 不存在时,将 key 改名为 newkey 。当 key 不存在时,返回一个错误。
//	 * </pre>
//	 * 
//	 * @param keyFormat
//	 *            要重命名的key标识
//	 * @param newKeyFormat
//	 *            重命名目标key标识
//	 * @param newKeyValues
//	 *            重命名目标key变量
//	 * @param keyValues
//	 *            要重命名的key变量
//	 * @return 修改成功时,返回 1 。如果 newkey 已经存在,返回 0 。
//	 */
//	public Long renamenx(String keyFormat, String newKeyFormat,
//			String[] newKeyValues, String... keyValues) {
//		String key = format(keyFormat, keyValues);
//		String newKey = format(newKeyFormat, newKeyValues);
//		Jedis jedis = null;
//		Jedis jedisNewKey = null;
//		try {
//			jedis = getJedis();
//			jedisNewKey = getJedis(newKeyFormat);
//			if (jedis != jedisNewKey) {
//				throw new RuntimeException(
//						String.format(
//								"rename 新key和旧key必须维护在同一个redis实例!keFormate:%s   newKeyFormat:%s",
//								keyFormat, newKeyFormat));
//			}
//			return jedis.renamenx(key, newKey);
//		} finally {
//			if (jedis != null) {
//				jedis.close();
//			}
//			if (jedisNewKey != null) {
//				jedisNewKey.close();
//			}
//		}
//	}

	/**
	 * 获取key的有效时间(单位:秒)
	 * 
	 * <pre>
	 * 以秒为单位,返回给定 key 的剩余生存时间(TTL, time to live)。
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param keyValues
	 *            key变量
	 * @return 当 key 不存在时,返回 -2 。当 key 存在但没有设置剩余生存时间时,返回 -1 。否则,以秒为单位,返回 key
	 *         的剩余生存时间。
	 */
	public Long ttl(String keyFormat, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.ttl(key);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/********************************** 针对字符串(string)的操作 **************************************/

	/**
	 * 追加一个值到key上
	 * 
	 * <pre>
	 * 如果 key 已经存在,并且值为字符串,那么这个命令会把 value 追加到原来值(value)的结尾。 
	 * 如果 key 不存在,那么它将首先创建一个空字符串的key,再执行追加操作,这种情况 APPEND 将类似于 SET 操作。
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param value
	 *            要追加的值
	 * @param keyValues
	 *            key变量
	 * @return 返回append后字符串值(value)的长度。
	 */
	public Long append(String keyFormat, String value, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.append(key, value);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 整数原子减1
	 * 
	 * <pre>
	 * 对key对应的数字做减1操作。如果key不存在,那么在操作之前,这个key对应的值会被置为0。
	 * 如果key有一个错误类型的value或者是一个不能表示成数字的字符串,就返回错误。
	 * 这个操作最大支持在64位有符号的整型数字。
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param keyValues
	 *            key变量
	 * @return 数字:减小之后的value
	 */
	public Long decr(String keyFormat, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.decr(key);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 原子减指定的整数
	 * 
	 * <pre>
	 * 将key对应的数字减decrement。如果key不存在,操作之前,key就会被置为0。
	 * 如果key的value类型错误或者是个不能表示成数字的字符串,就返回错误。
	 * 这个操作最多支持64位有符号的正型数字。
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param integer
	 *            要减小的数值
	 * @param keyValues
	 *            key变量
	 * @return 返回一个数字:减少之后的value值。
	 */
	public Long decrby(String keyFormat, long integer, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.decrBy(key, integer);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 
	 * @param formatKey
	 *            key标识
	 * @param keyValues
	 *            key变量
	 * @return key对应的value,或者null(key不存在时)
	 */
	public String get(String keyFormat, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.get(key);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 设置一个key的value,并获取设置前的值
	 * 
	 * <pre>
	 * 自动将key对应到value并且返回原来key对应的value。如果key存在但是对应的value不是字符串,就返回错误。
	 * exp:
	 * GETSET可以和INCR一起使用实现支持重置的计数功能。
	 * 举个例子:每当有事件发生的时候,一段程序都会调用INCR给key mycounter加1,但是有时我们需要获取计数器的值,并且自动将其重置为0。
	 * 这可以通过GETSET mycounter "0"来实现:
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param value
	 *            要设置的值
	 * @param keyValues
	 *            key变量
	 * @return 设置之前的值
	 */
	public String getSet(String keyFormat, String value, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.getSet(key, value);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 执行原子加1操作
	 * 
	 * <pre>
	 * 对key对应的数字做加1操作。如果key不存在,那么在操作之前,这个key对应的值会被置为0。
	 * 如果key有一个错误类型的value或者是一个不能表示成数字的字符串,就返回错误。这个操作最大支持在64位有符号的整型数字。
	 * 提醒:这是一个string操作,因为Redis没有专用的数字类型。key对应的string都被解释成10进制64位有符号的整型来执行这个操作。
	 * Redis会用相应的整数表示方法存储整数,所以对于表示数字的字符串,没必要为了用字符串表示整型存储做额外开销。
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param keyValues
	 *            key变量
	 * @return 增加之后的value
	 */
	public Long incr(String keyFormat, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.incr(key);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 执行原子加1操作,并且设置过期时间(单位:s)
	 * 
	 * <pre>
	 * 本操作是在{@linkplain RedisClient#incr(String, String...)}之上增加了一个设置过期时间的操作
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param expireTime
	 *            过期时间(单位:s)
	 * @param keyValues
	 *            key变量
	 * @return 增加之后的value
	 */
	public Long incr(String keyFormat, int expireTime, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			long result = jedis.incr(key);
			jedis.expire(key, expireTime);
			return result;
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 执行原子增加一个整数
	 * 
	 * <pre>
	 * 将key对应的数字加increment。如果key不存在,操作之前,key就会被置为0。
	 * 如果key的value类型错误或者是个不能表示成数字的字符串,就返回错误。这个操作最多支持64位有符号的正型数字。
	 * 查看方法{@linkplain RedisClient#incr(String, String...)}了解关于增减操作的额外信息。
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param increment
	 *            要增加的数值
	 * @param keyValues
	 *            key变量
	 * @return 增加后的value
	 */
	public Long incrBy(String keyFormat, long increment, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.incrBy(key, increment);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 执行原子增加一个浮点数
	 * 
	 * <pre>
	 * 将key对应的数字加increment。如果key不存在,操作之前,key就会被置为0。
	 * 如果key的value类型错误或者是个不能表示成数字的字符串,就返回错误。
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param increment
	 *            要增加的数值
	 * @param keyValues
	 *            key变量
	 * @return 增加后的value
	 */
	public Double incrByFloat(String keyFormat, double increment,
			String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.incrByFloat(key, increment);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 设置一个key的value值
	 * 
	 * <pre>
	 * 警告:如果key已经存在了,它会被覆盖,而不管它是什么类型。
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param value
	 *            要设置的值
	 * @param keyValues
	 *            key变量
	 * 
	 * @return 总是"OK"
	 */
	public String set(String keyFormat, String value, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.set(key, value);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 设置key-value并设置过期时间(单位:秒)
	 * 
	 * <pre>
	 * 设置key对应字符串value,并且设置key在给定的seconds时间之后超时过期。
	 * 该命令相当于执行了{@link #set(String, String, String...) SET} + {@link #expire(String, int, String...) EXPIRE}.并且该操作是原子的
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param seconds
	 *            超时时间(单位:s)
	 * @param value
	 *            设置的值
	 * @param keyValues
	 *            key变量
	 * @return 状态码
	 */
	public String setex(String keyFormat, int seconds, String value,
			String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.setex(key, seconds, value);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 设置key-value并设置过期时间(单位:毫秒)
	 * 
	 * <pre>
	 * 跟{@link #setex(String, int, String, String...)}效果差不多,唯一区别是超时时间是ms
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param milliseconds
	 *            超时时间(单位:ms)
	 * @param value
	 *            设置的值
	 * @param keyValues
	 *            key变量
	 * @return 状态码
	 */
	public String psetex(String keyFormat, int milliseconds, String value,
			String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.psetex(key, (long) milliseconds, value);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 设置的一个关键的价值,只有当该键不存在
	 * 
	 * <pre>
	 * 如果key不存在,就设置key对应字符串value。在这种情况下,该命令和SET一样。
	 * 当key已经存在时,就不做任何操作。SETNX是"SET if Not eXists"。
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param value
	 *            设置的value
	 * @param keyValues
	 *            key变量
	 * @return 1 如果key被set,0 如果key没有被set
	 */
	public Long setnx(String keyFormat, String value, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.setnx(key, value);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/********************************* Hash 操作 ******************************/

	/**
	 * 删除一个哈希域
	 * 
	 * <pre>
	 * 从 key 指定的哈希集中移除指定的域。在哈希集中不存在的域将被忽略。
	 * 如果 key 指定的哈希集不存在,它将被认为是一个空的哈希集,该命令将返回0。
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param field
	 *            要删除的域
	 * @param keyValues
	 *            key变量
	 * @return 返回从哈希集中成功移除的域的数量,不包括指出但不存在的那些域
	 */
	public long hdel(String keyFormat, String field, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.hdel(key, field);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 删除一个hash中的多个域
	 * 
	 * <pre>
	 * 相当于多次执行{@link #hdel(String, String, String...)}, 效率会有所提高
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param fileds
	 *            要删除的域
	 * @param keyValues
	 *            key变量
	 * 
	 * @return 返回从哈希集中成功移除的域的数量,不包括指出但不存在的那些域
	 */
	public Long hdel(String keyFormat, Set<String> fileds, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.hdel(key, fileds.toArray(new String[fileds.size()]));
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 判断给定域是否存在于哈希集中
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param field
	 *            指定的域
	 * @param keyValues
	 *            key变量
	 * @return 返回字段是否是 key 指定的哈希集中存在的字段。
	 */
	public Boolean hexists(String keyFormat, String field, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.hexists(key, field);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 读取哈希域的的值
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param field
	 *            指定的域
	 * @param keyValues
	 *            key变量
	 * @return 该字段所关联的值。当字段不存在或者 key 不存在时返回null。
	 */
	public String hget(String keyFormat, String field, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.hget(key, field);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 读取哈希域的的值(返回的是byte[])
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param field
	 *            指定的域
	 * @param keyValues
	 *            key变量
	 * @return 该字段所关联的值(byte[])。当字段不存在或者 key 不存在时返回null。
	 */
	public byte[] hgetBytes(String keyFormat, String field, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.hget(key.getBytes(), field.getBytes());
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 从哈希集中读取全部的域和值
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param keyValues
	 *            key变量
	 * @return 哈希集中字段和值的列表。当 key 指定的哈希集不存在时返回空列表。
	 */
	public Map<String, String> hgetAll(String keyFormat, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.hgetAll(key);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 将哈希集中指定域的值增加给定的数字
	 * 
	 * <pre>
	 * 增加 key 指定的哈希集中指定字段的数值。
	 * 如果 key 不存在,会创建一个新的哈希集并与 key 关联。
	 * 如果字段不存在,则字段的值在该操作执行前被设置为 0
	 * HINCRBY 支持的值的范围限定在 64位 有符号整数
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param field
	 *            指定的域
	 * @param value
	 *            给定的数字
	 * @param keyValues
	 *            key变量
	 * @return 增值操作执行后的该字段的值。
	 */
	public long hincrBy(String keyFormat, String field, long value,
			String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.hincrBy(key, field, value);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 将哈希集中指定域的值增加给定的浮点数
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param field
	 *            指定的域
	 * @param value
	 *            给定的浮点数
	 * @param keyValues
	 *            key变量
	 * @return 增值操作执行后的该字段的值。
	 */
	public Double hincrByFloat(String keyFormat, String field, double value,
			String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.hincrByFloat(key, field, value);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 获取hash的所有字段
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param keyValues
	 *            key变量
	 * @return 哈希集中的字段列表,当 key 指定的哈希集不存在时返回空列表。
	 */
	public Set<String> hkeys(String keyFormat, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.hkeys(key);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 获取hash里所有字段的数量
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param keyValues
	 *            key变量
	 * @return 哈希集中字段的数量,当 key 指定的哈希集不存在时返回 0
	 */
	public Long hlen(String keyFormat, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.hlen(key);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 批量获取hash中的值
	 * 
	 * <pre>
	 * 返回 key 指定的哈希集中指定字段的值。
	 * 对于哈希集中不存在的每个字段,返回null值。
	 * 因为不存在的keys被认为是一个空的哈希集,对一个不存在的 key 执行 HMGET 将返回一个只含有 null值的列表
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param fileds
	 *            指定的域
	 * @param keyValues
	 *            key变量
	 * @return 含有给定字段及其值的列表,并保持与请求相同的顺序。
	 */
	public List<String> hmget(String keyFormat, List<String> fileds,
			String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.hmget(key, fileds.toArray(new String[fileds.size()]));
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 批量设置hash中的值
	 * 
	 * <pre>
	 * 设置 key 指定的哈希集中指定字段的值。该命令将重写所有在哈希集中存在的字段。
	 * 如果 key 指定的哈希集不存在,会创建一个新的哈希集并与 key 关联
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param hash
	 *            指定的域和值
	 * @param keyValues
	 *            key变量
	 * @return Return OK or Exception if hash is empty
	 */
	public String hmset(String keyFormat, Map<String, String> hash,
			String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.hmset(key, hash);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 设置hash里面一个字段的值
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param field
	 *            字段
	 * @param value
	 *            值
	 * @param keyValues
	 *            key变量
	 * @return 含义如下:1如果field是一个新的字段 0如果field原来在map里面已经存在
	 * 
	 */
	public Long hset(String keyFormat, String field, String value,
			String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.hset(key, field, value);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 设置hash里面一个字段的值(值为byte[]数组类型)
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param field
	 *            字段
	 * @param value
	 *            值
	 * @param keyValues
	 *            key变量
	 * @return 含义如下:1如果field是一个新的字段 0如果field原来在map里面已经存在
	 * 
	 */
	public Long hset(String keyFormat, String field, byte[] value,
			String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.hset(key.getBytes(), field.getBytes(), value);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 设置hash的一个字段,只有当这个字段不存在时有效
	 * 
	 * <pre>
	 * 只在 key 指定的哈希集中不存在指定的字段时,设置字段的值。
	 * 如果 key 指定的哈希集不存在,会创建一个新的哈希集并与 key 关联。
	 * 如果字段已存在,该操作无效果。
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param field
	 *            字段
	 * @param value
	 *            值
	 * @param keyValues
	 *            key变量
	 * @return 1:如果字段是个新的字段,并成功赋值 0:如果哈希集中已存在该字段,没有操作被执行
	 */
	public Long hsetnx(String keyFormat, String field, String value,
			String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.hsetnx(key, field, value);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 获得hash的所有值
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param keyValues
	 *            key变量
	 * @return 哈希集中的值的列表,当 key 指定的哈希集不存在时返回空列表。
	 */
	public List<String> hvals(String keyFormat, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.hvals(key);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/******************************* SET 操作 *************************/

	/**
	 * 添加一个元素到集合(set)里
	 * 
	 * <pre>
	 * 添加一个指定的member元素到集合的 key中.
	 * 如果已经在集合key中存在则忽略.如果集合key 不存在,则新建集合key,并添加member元素到集合key中.
	 * 如果key 的类型不是集合则返回错误.
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param value
	 *            元素
	 * @param keyValues
	 *            key变量
	 * @return 返回新成功添加到集合里元素的数量,不包括已经存在于集合中的元素.
	 */
	public Long sadd(String keyFormat, String value, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.sadd(key, value);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 批量添加元素到集合(set)里
	 * 
	 * <pre>
	 * 添加指定的member元素到集合的 key中.
	 * 如果已经在集合key中存在则忽略.如果集合key 不存在,则新建集合key,并添加member元素到集合key中.
	 * 如果key 的类型不是集合则返回错误.
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param values
	 *            要添加的元素集合
	 * @param keyValues
	 *            key变量
	 * @return 返回新成功添加到集合里元素的数量,不包括已经存在于集合中的元素.
	 */
	public Long sadd(String keyFormat, List<String> values, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.sadd(key, values.toArray(new String[values.size()]));
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 获取集合里面的元素数量
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param keyValues
	 *            key变量
	 * @return 集合的基数(元素的数量),如果key不存在,则返回 0.
	 */
	public Long scard(String keyFormat, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.scard(key);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 确定一个给定的值是一个集合的成员
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param value
	 *            给定的值
	 * @param keyValues
	 *            key变量
	 * @return 返回成员 value是否是存储的集合 key的成员.
	 */
	public Boolean sismember(String keyFormat, String value,
			String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.sismember(key, value);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 获取集合里面的所有key
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param keyValues
	 *            key变量
	 * @return 集合中的所有元素.
	 */
	public Set<String> smembers(String keyFormat, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.smembers(key);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 删除并获取一个集合里面的元素
	 * 
	 * <pre>
	 * 移除并返回一个集合中的随机元素
	 * 该命令与 {@link #srandmember(String, String...)}相似,不同的是srandmember命令返回一个随机元素但是不移除.
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param keyValues
	 *            key变量
	 * @return 被移除的元素, 当key不存在的时候返回 null .
	 */
	public String spop(String keyFormat, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.spop(key);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 从集合里面随机获取一个key
	 * 
	 * <pre>
	 *  随机返回key集合中的一个元素.
	 *  该命令作用类似于{@link #spop(String, String...)}命令,
	 *  不同的是SPOP命令会将被选择的随机元素从集合中移除, 而SRANDMEMBER仅仅是返回该随记元素,而不做任何操作.
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param keyValues
	 *            key变量
	 * @return 被移除的元素, 当key不存在的时候返回 null .
	 */
	public String srandmember(String keyFormat, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.srandmember(key);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 从集合里删除一个元素
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param member
	 *            要删除的元素
	 * @param keyValues
	 *            key变量
	 * @return 从集合中移除元素的个数,不包括不存在的成员.
	 */
	public Long srem(String keyFormat, String member, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.srem(key, member);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 批量从集合里删除元素
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param members
	 *            要删除的元素
	 * @param keyValues
	 *            key变量
	 * @return 从集合中移除元素的个数,不包括不存在的成员.
	 */
	public Long srem(String keyFormat, List<String> members,
			String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.srem(key, members.toArray(new String[members.size()]));
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/***************************** ZSET 操作 *****************************/

	/**
	 * 添加到有序set的一个成员,如果它已经存在,则更新分数。
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param member
	 *            成员
	 * @param score
	 *            分值
	 * @param keyValues
	 *            key变量
	 * @return 如果是新添加的,返回1,如果是更新,返回0
	 */
	public Long zadd(String keyFormat, String member, double score,
			String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.zadd(key, score, member);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 批量添加到有序的成员,如果已经存在,则更新分数。
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param scoreMembers
	 *            成员和对应的分值
	 * @param keyValues
	 *            key变量
	 * @return 返回添加到有序集合中元素的个数,不包括那种已经存在只是更新分数的元素。
	 */
	public Long zadd(String keyFormat, Map<String, Double> scoreMembers,
			String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.zadd(key, scoreMembers);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 获取一个排序的集合中的成员数量
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param keyValues
	 *            key变量
	 * @return key存在的时候,返回有序集的元素个数,否则返回0。
	 */
	public Long zcard(String keyFormat, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.zcard(key);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 获取给定值范围内的成员数
	 * 
	 * <pre>
	 * 返回有序集key中,score值在min和max之间(默认包括score值等于min或max)的成员。
	 * 关于参数min和max的详细使用方法,请参考ZRANGEBYSCORE命令。
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param min
	 *            范围下限
	 * @param max
	 *            范围上限
	 * @param keyValues
	 *            key变量
	 * @return key存在的时候,返回有序集的元素个数,否则返回0。
	 */
	public Long zcount(String keyFormat, double min, double max,
			String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.zcount(key, min, max);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 给一个有序集合中的成员增加指定的分值
	 * 
	 * <pre>
	 * 为有序集key的成员member的分值值加上score。如果key中不存在member,就在key中添加一个member,分值是score
	 * 如果key不存在,就创建一个只含有指定member成员的有序集合。
	 * 当key不是有序集类型时,返回一个错误。
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param member
	 *            成员
	 * @param score
	 *            增加的分值
	 * @param keyValues
	 *            key变量
	 * @return member成员的新分值。
	 */
	public Double zincrby(String keyFormat, String member, double score,
			String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.zincrby(key, score, member);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 获取排名在[start, end]之间的成员
	 * 
	 * <pre>
	 * 返回有序集key中,指定区间内的成员。其中成员按score值递增(从小到大)来排序。具有相同score值的成员按字典序来排列。
	 * 如果你需要成员按score值递减(score相等时按字典序递减)来排列,请使用ZREVRANGE命令。 
	 * 下标参数start和stop都以0为底,也就是说,以0表示有序集第一个成员,以1表示有序集第二个成员,以此类推。
	 * 你也可以使用负数下标,以-1表示最后一个成员,-2表示倒数第二个成员,以此类推。
	 * 超出范围的下标并不会引起错误。如果start的值比有序集的最大下标还要大,或是start > stop时,ZRANGE命令只是简单地返回一个空列表。
	 * 另一方面,假如stop参数的值比有序集的最大下标还要大,那么Redis将stop当作最大下标来处理。
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param start
	 *            排名开始
	 * @param end
	 *            排名结尾
	 * @param keyValues
	 *            key变量
	 * @return 排名在[start, end]之间的成员
	 */
	public Set<String> zrange(String keyFormat, long start, long end,
			String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.zrange(key, start, end);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 获取排名在[start, end]之间的成员及分数
	 * 
	 * <pre>
	 * 该方法和{@link #zrange(String, long, long, String...)}相似,只是连带分数值一起返回
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param start
	 *            排名开始
	 * @param end
	 *            排名结尾
	 * @param keyValues
	 *            key变量
	 * @return 排名在[start, end]之间的成员及分数
	 * @see #zrange(String, long, long, String...)
	 */
	public Set<Tuple> zrangeWithScores(String keyFormat, long start, long end,
			String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.zrangeWithScores(key, start, end);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 获取分数值在[min, max]之间的成员
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param min
	 *            最小分值
	 * @param max
	 *            最大分值
	 * @param keyValues
	 *            keyValues key变量
	 * @return 分值在[min, max]之间的成员
	 */
	public Set<String> zrangeByScore(String keyFormat, double min, double max,
			String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.zrangeByScore(key, min, max);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 获取分数值在[min, max]之间的成员及分数
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param min
	 *            最小分值
	 * @param max
	 *            最大分值
	 * @param keyValues
	 *            keyValues key变量
	 * @return 分值在[min, max]之间的成员及分数
	 */
	public Set<Tuple> zrangeByScoreWithScores(String keyFormat, double min,
			double max, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.zrangeByScoreWithScores(key, min, max);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 获取有序集合中某个成员的排名(从0开始)
	 * 
	 * <pre>
	 * 返回有序集key中成员member的排名。其中有序集成员按score值递增(从小到大)顺序排列。
	 * 排名以0为底,也就是说,score值最小的成员排名为0。
	 * 使用ZREVRANK命令可以获得成员按score值递减(从大到小)排列的排名。
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param member
	 *            指定的成员
	 * @param keyValues
	 *            key变量
	 * @return 该元素的排名,如果集合中不存在该元素,返回null
	 */
	public Long zrank(String keyFormat, String member, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.zrank(key, member);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 从排序的集合中删除一个成员
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param member
	 *            要删除的成员
	 * @param keyValues
	 *            key变量
	 * @return 删除成功返回1,如果集合中不存在返回0
	 */
	public Long zrem(String keyFormat, String member, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.zrem(key, member);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 删除排名在[start,end](从小到大)之间的成员
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param start
	 *            排名的开始
	 * @param end
	 *            排名的结尾
	 * @param keyValues
	 *            key变量
	 * @return 被移除成员的数量。
	 */
	public Long zremrangeByRank(String keyFormat, long start, long end,
			String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.zremrangeByRank(key, start, end);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 删除分数值在[min,max]之间的成员
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param min
	 *            最小分数值
	 * @param max
	 *            最大分数值
	 * @param keyValues
	 *            key变量
	 * @return 被移除成员的数量。
	 */
	public Long zremrangeByScore(String keyFormat, double min, double max,
			String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.zremrangeByScore(key, min, max);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 获取排名在[start, end](从大到小)之间的成员
	 * 
	 * <pre>
	 * 返回有序集key中,指定区间内的成员。
	 * 其中成员的位置按score值递减(从大到小)来排列。具有相同score值的成员按字典序的反序排列。 
	 * 除了成员按score值递减的次序排列这一点外,ZREVRANGE命令的其他方面和ZRANGE命令一样。
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param start
	 *            排名开始
	 * @param end
	 *            排名结束
	 * @param keyValues
	 *            key变量
	 * @return 取排名在[start, end](从大到小)之间的成员
	 */
	public Set<String> zrevrange(String keyFormat, long start, long end,
			String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.zrevrange(key, start, end);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 获取排名在[start, end](从大到小)之间的成员及分数值
	 * 
	 * <pre>
	 * 返回有序集key中,指定区间内的成员。
	 * 其中成员的位置按score值递减(从大到小)来排列。具有相同score值的成员按字典序的反序排列。 
	 * 除了成员按score值递减的次序排列这一点外,ZREVRANGEWITHSCORE命令的其他方面和ZRANGEWITHSCORE命令一样。
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param start
	 *            排名开始
	 * @param end
	 *            排名结束
	 * @param keyValues
	 *            key变量
	 * @return 排名在[start, end](从大到小)之间的成员及分数值
	 */
	public Set<Tuple> zrevrangeWithScores(String keyFormat, long start,
			long end, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.zrevrangeWithScores(key, start, end);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 获得成员按 score 值递减(从大到小)排列的排名
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param member
	 *            成员
	 * @param keyValues
	 *            key变量
	 * @return 成员的排名
	 */
	public Long zrevrank(String keyFormat, String member, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.zrevrank(key, member);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 获取分数值在[max, min](从大到小)之间的成员
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param max
	 *            最大分数值
	 * @param min
	 *            最小分数值
	 * @param keyValues
	 *            key变量
	 * @return 分数值在[max, min](从大到小)之间的成员
	 */
	public Set<String> zrevrangeByScore(String keyFormat, double max,
			double min, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.zrevrangeByScore(key, max, min);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 获取成员在有序集合中的分数值
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param member
	 *            成员
	 * @param keyValues
	 *            key变量
	 * @return member成员的score值,如果member元素不是有序集key的成员,或key不存在,返回null。
	 */
	public Double zscore(String keyFormat, String member, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.zscore(key, member);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/***************************** LIST 操作 *************************************/

	/**
	 * 删除,并获得该列表中的第一元素,或阻塞,直到有一个可用
	 * 
	 * <pre>
	 * 该操作是从left 到 right获取第一个元素
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param timeout
	 *            指定阻塞的最大秒数的整型值。当 timeout 为 0 是表示阻塞时间无限制。
	 * @param keyValues
	 *            key变量
	 * @return 如果阻塞超时还没有获取值,则返回空(列表)。如果有值则返回一个List,第一个值表示key名称,第二个元素为value
	 */
	public List<String> blpop(String keyFormat, int timeout,
			String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.blpop(timeout, key);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 删除,并获得该列表中的第一元素,或阻塞,直到有一个可用
	 * 
	 * <pre>
	 * 该操作是从right 到 left获取第一个元素
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param timeout
	 *            指定阻塞的最大秒数的整型值。当 timeout 为 0 是表示阻塞时间无限制。
	 * @param keyValues
	 *            key变量
	 * @return 如果阻塞超时还没有获取值,则返回空(列表)。如果有值则返回一个List,第一个值表示key名称,第二个元素为value
	 */
	public List<String> brpop(String keyFormat, int timeout,
			String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.brpop(timeout, key);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 获得队列(List)的长度
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param keyValues
	 *            key变量
	 * @return list长度
	 */
	public Long llen(String keyFormat, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.llen(key);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 从队列的左边出队一个元素
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param keyValues
	 *            key变量
	 * @return 返回第一个元素的值,或者当 key 不存在时返回 null。
	 */
	public String lpop(String keyFormat, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.lpop(key);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 从队列的左边入队一个元素
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param value
	 *            元素值
	 * @param keyValues
	 *            key变量
	 * @return 在 push 操作后的 list 长度。
	 */
	public Long lpush(String keyFormat, String value, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.lpush(key, value);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 从队列的左边入队多个元素
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param values
	 *            元素值列表
	 * @param keyValues
	 *            key变量
	 * @return 在 push 操作后的 list 长度。
	 */
	public Long lpush(String keyFormat, List<String> values,
			String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.lpush(key, values.toArray(new String[values.size()]));
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 从队列的右边入队一个元素
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param value
	 *            元素值
	 * @param keyValues
	 *            key变量
	 * @return 在 push 操作后的 list 长度。
	 */
	public Long rpush(String keyFormat, String value, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.rpush(key, value);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 从队列的右边入队多个元素
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param values
	 *            元素值列表
	 * @param keyValues
	 *            key变量
	 * @return 在 push 操作后的 list 长度。
	 */
	public Long rpush(String keyFormat, List<String> values,
			String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.rpush(key, values.toArray(new String[values.size()]));
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 从队列的右边出队一个元素
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param keyValues
	 *            key变量
	 * @return 返回第一个元素的值,或者当 key 不存在时返回 null。
	 */
	public String rpop(String keyFormat, String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.rpop(key);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

	/**
	 * 从列表中获取指定返回的元素
	 * 
	 * <pre>
	 * 返回存储在 key 的列表里指定范围内的元素。 
	 * start 和 end 偏移量都是基于0的下标,即list的第一个元素下标是0(list的表头),第二个元素下标是1,以此类推。
	 * 偏移量也可以是负数,表示偏移量是从list尾部开始计数。 例如, -1 表示列表的最后一个元素,-2 是倒数第二个,以此类推。
	 * </pre>
	 * 
	 * @param keyFormat
	 *            key标识
	 * @param start
	 *            开始偏移量
	 * @param end
	 *            结束偏移量
	 * @param keyValues
	 *            key变量
	 * @return
	 */
	public List<String> lrange(String keyFormat, long start, long end,
			String... keyValues) {
		String key = format(keyFormat, keyValues);
		Jedis jedis = null;
		try {
			jedis = getJedis();
			return jedis.lrange(key, start, end);
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}

//	/**
//	 * 使用管道进行批量的操作
//	 * 
//	 * @param keyFormat
//	 *            key标识
//	 * @param executeInPipeline
//	 *            批量执行的回调
//	 */
//	public void pipelined(String keyFormat, ExecuteInPipeline executeInPipeline) {
//		Jedis jedis = null;
//		try {
//			jedis = getJedis();
//			Pipeline pipeline = jedis.pipelined();
//			executeInPipeline.execute(pipeline);
//		} finally {
//			if (jedis != null) {
//				jedis.close();
//			}
//		}
//	}
//
//	public String getConfigFile() {
//		return configFile;
//	}

//	public void setConfigFile(String configFile) {
//		this.configFile = configFile;
//	}

}

5、controller:


package com.demo.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.demo.module.Product;
import com.demo.service.OrderService;
import com.demo.service.ProductService;
import com.demo.util.RedisUtil;



@RequestMapping("/product")
@RestController
public class ProductController {
	
	@Autowired
	private OrderService orderService;
	
	@Autowired
	private ProductService productService;
	
	@Autowired
	private RedisUtil redisUtil;
	
	private String PRODUCT_LOCK = "product:lock:{productId}";
	
	private String VALUE = "lock";
	

	@RequestMapping("/order")
	public void order(@RequestParam String userId,@RequestParam String productId){
 
		//是否有缓存
		boolean exists = redisUtil.exists(PRODUCT_LOCK, productId);
		if(!exists){
			//没有,加上
			Long sexNx = redisUtil.setnx(PRODUCT_LOCK, VALUE, productId);
			if(sexNx == 1){
				orderService.order(productId,userId);
				redisUtil.del(PRODUCT_LOCK, productId);
			}
		}else{
			System.out.println(productId+"正在被抢购");
		}
		
	}

	
	@RequestMapping("/getProductInfo")
	public void getProductInfo(@RequestParam String productId){
		Product product = productService.getProductInfo(productId);
		System.err.println(product);
	}
	
}

6、启动类:


package com.demo;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

 
@SpringBootApplication
@MapperScan("com.demo.mapper")
 
public class RedisFormatStart {
	public static void main(String[] args) {
		SpringApplication.run(RedisFormatStart.class, args);
	}

}

测试:

(1)缓存:程序中查询缓存设置的过期时间是10秒钟,断续访问后台打印如下:

(2)并发:方法如前:

另建一个测试工程:


package com.test.test;

import com.test.util.HttpRequestUtil;

public class ProductTest implements Runnable{
	public static void main(String[] args) {
		
		ProductTest productTest = new ProductTest();
      for(int i=0;i<500;i++){
    	 Thread thread = new Thread(productTest);
    	  thread.start();
      }
      
	
	}
	@Override
	public void run() {
		 String url = "http://localhost:8080/product/order";
   	  String productId = "abcd";
   	  String userId = "userid";
   	  String param = "userId="+userId+"&productId="+productId;
   	  HttpRequestUtil.sendPost(url, param);
	}
}

 并发量为500的情况下:

订单表:

商品表:

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

w_t_y_y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值