目录
- 订单号生成
- redis单机与集群
单据号生成器:
- 使用redis操作自增序列号:yyyyMMdd{4位随机数}{bizCode}{6位流水号:6位的自增序列号}
- key=包名:业务类型+yyyymmdd,设置key后需要设置过期时间
- key2:radom值为4位随机数
这里设置随机数是为了防止宕机后,生成重复的订单号。为了方便遍历使用以及保证订单号整体自增,把随机数改为redis服务器时间(HHmmss)。
package com.test.util;
import org.apache.log4j.Logger;
import redis.clients.jedis.Jedis;
/**
*
* @ClassName: SerialNumberUtil
* @Description: 订单号生成工具类
* @author
* @date 2018年7月30日 上午10:56:56
*
*/
public class SerialNumberUtil {
/**
* 根据两位业务类型码字符串,生成一个流水号,格式按照:
* yyyyMMdd{Redis服务器6位时间}{bizCode}{6位流水号:6位的自增序列号}
*
* @param bizCode两位业务类型码字符串,00-99
* @return 22位的序列号
* @throws Exception
*/
public static String createNo(String bizCode) {
// JedisClientSingle jedis = new JedisClientSingle();
Jedis jedis = new Jedis("localhost");
Logger log = Logger.getLogger(SerialNumberUtil.class);
String pacName = StringUtil.getPacName();// 获取当前类所在的包名
log.info("pacName:" + pacName);
String date = StringUtil.getToday(); // 时间yyMMdd
log.info("Time(yyMMdd):" + date);
String key = pacName + bizCode + date;// 构建订单号key
log.info("key:" + key);
String key2 = pacName + "time";
String redisTime = StringUtil.getRedisTime();// 获取redis服务器的时间HHmmss
log.info("redis服务器当前时间:" + redisTime);
if (StringUtil.isLegal(bizCode)) {
jedis.incr(key);
jedis.expire(key, 60 * 60 * 48);// 过期时间48小时
log.info("key(expire:)" + jedis.ttl(key) + "s");
}
if (jedis.get(key2) == null) {
jedis.set(key2, redisTime);
}
String v = "";
v = jedis.get(key);
v = StringUtil.autoCOS(v);
v = bizCode + date + jedis.get(key2) + v;
log.info("value:" + v);
return v;
}
}
上面所用到的方法:
package com.test.util;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import org.apache.commons.lang3.RandomStringUtils;
import redis.clients.jedis.Jedis;
/**
*
* @ClassName: StringUtil
* @Description: 自增序列工具类
* @author
* @date 2018年7月20日 下午2:04:34
*
*/
public class StringUtil {
static final int DEFAULT_LENGTH = 6;
private static Jedis jedis = new Jedis("localhost");
public static String getSequence(long seq) {
String str = String.valueOf(seq);
int length = str.length();
if (length >= DEFAULT_LENGTH) {// 每天超过6位
return str;
}
int rest = DEFAULT_LENGTH - length;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < rest; i++) {
sb.append('0');
}
sb.append(str);
return sb.toString();
}
/**
*
* @Title: autoCOS
* @Description: 补全6位字符串(Auto completion of string)
* @return 参数
* @return String 返回类型
* @throws
*/
public static String autoCOS(String value) {
int length = value.length();
if (length >= DEFAULT_LENGTH) {
return value;
}
int rest = DEFAULT_LENGTH - length;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < rest; i++) {
sb.append('0');
}
sb.append(value);
return sb.toString();
}
/**
*
* @Title: isLegal
* @Description: 对bizCode进行白名单验证,以免恶意伪造
* @param
* @return 参数
* @return boolean 返回类型
* @throws BizCodeException
*/
public static boolean isLegal(String bizCode) {
if (bizCode == null || bizCode.length() != 2) {
throw new BizCodeException(bizCode);
}
if (Character.isDigit(bizCode.charAt(0)) && Character.isDigit(bizCode.charAt(1)))
return true;
return false;
}
/**
*
* @Title: getPacName
* @Description: 获取包名
* @param @return 参数
* @return String 返回类型
*/
public static String getPacName() {
String clzName = Thread.currentThread().getStackTrace()[1].getClassName();
int index = clzName.lastIndexOf(".");
String pacName = clzName.substring(0, index) + ":";
return pacName;
}
/**
*
* @Title: getRandom
* @Description: 获取四位随机数
* @param @return 参数
* @return String 返回类型
*/
public static Set<String> m = new HashSet<String>();
public static String getRandom() {
String randomDigit;
do {
randomDigit = RandomStringUtils.random(4, false, true);
} while (m.contains(randomDigit));
m.add(randomDigit);
return randomDigit;
}
/**
*
* @Title: getToday
* @Description: 获取今天的日期:yyyyMMdd
* @param @return 参数
* @return String 返回类型
*/
public static String getToday() {
return new SimpleDateFormat("yyyMMdd").format(new Date());
}
/**
*
* @Title: getRedisTime
* @Description:获取Redis服务器的时间HHssmm
* @param @return参数
* @return String 返回类型
* @throws
*/
public static String getRedisTime() {
List<String> time = jedis.time();
Long timestamp = Long.parseLong(time.get(0)) * 1000;
String redisTime = new SimpleDateFormat("HHmmss", Locale.CHINA).format(new Date(timestamp));
return redisTime;
}
}
maven+spring+redis配置
pom.xml
<!-- Redis客户端 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>${jedis.version}</version>
</dependency>
applicationContext-jedis.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- 加载配置文件 -->
<context:property-placeholder ignore-unresolvable="true"
location="classpath:redis.properties" />
<!-- 连接池配置 -->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<!-- 最大连接数 -->
<property name="maxTotal"><value>${redis.maxTotal}</value>
</property>
<!-- 最大空闲连接数 -->
<property name="maxIdle"><value>${redis.maxIdle}</value></property>
<!-- 每次释放连接的最大数目 -->
<property name="numTestsPerEvictionRun">
<value>${redis.numTestsPerEvictionRun}</value></property>
<!-- 释放连接的扫描间隔(毫秒) -->
<property name="timeBetweenEvictionRunsMillis">
<value>${redis.timeBetweenEvictionRunsMillis}</value></property>
<!-- 连接最小空闲时间 -->
<property name="minEvictableIdleTimeMillis">
<value>${redis.minEvictableIdleTimeMillis}</value></property>
<!-- 连接空闲多久后释放, 当空闲时间>该值 且 空闲连接>最大空闲连接数 时直接释放 -->
<property name="softMinEvictableIdleTimeMillis">
<value>${redis.softMinEvictableIdleTimeMillis}</value></property>
<!-- 获取连接时的最大等待毫秒数,小于零:阻塞不确定的时间,默认-1 -->
<property name="maxWaitMillis"><value>${redis.maxWaitMillis}</value></property>
<!-- 在获取连接的时候检查有效性, 默认false -->
<property name="testOnBorrow"><value>${redis.testOnBorrow}</value></property>
<!-- 在空闲时检查有效性, 默认false -->
<property name="testWhileIdle"><value>${redis.testWhileIdle}</value></property>
<!-- 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true -->
<property name="blockWhenExhausted"><value>${redis.blockWhenExhausted}</value></property>
</bean>
<!-- jedis客户端单机版 -->
<bean id="jedisPool" class="redis.clients.jedis.JedisPool">
<constructor-arg name="host" value="${redis.host}"></constructor-arg>
<constructor-arg name="port" value="${redis.port}" type="int"></constructor-arg>
<constructor-arg name="timeout" value="${redis.timeout}" type="int"></constructor-arg>
<constructor-arg name="password" value="${redis.password}"></constructor-arg>
<constructor-arg name="poolConfig" ref="jedisPoolConfig"></constructor-arg>
</bean>
<bean id="jedisClient" class="com.test.dao.impl.JedisClientSingle"/>
<!-- jedis集群版配置 -->
<!-- <bean id="redisClient" class="redis.clients.jedis.JedisCluster">
<constructor-arg name="nodes">
<set>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="${redis.host1}"></constructor-arg>
<constructor-arg name="port" value="${redis.post1}" type="int"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="${redis.host2}"></constructor-arg>
<constructor-arg name="port" value="${redis.post2}" type="int"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="${redis.host3}"></constructor-arg>
<constructor-arg name="port" value="${redis.post3}" type="int"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="${redis.host4}"></constructor-arg>
<constructor-arg name="port" value="${redis.post4}" type="int"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="${redis.host5}"></constructor-arg>
<constructor-arg name="port" value="${redis.post5}" type="int"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="${redis.host6}"></constructor-arg>
<constructor-arg name="port" value="${redis.post6}" type="int"></constructor-arg>
</bean>
</set>
</constructor-arg>
<constructor-arg name="poolConfig" ref="jedisPoolConfig"></constructor-arg>
</bean>
<bean id="jedisClientCluster" class="com.taotao.rest.dao.impl.JedisClientCluster"></bean> -->
</beans>
redis.properties
#最大连接数
redis.maxTotal=30
#最大空闲连接数
redis.maxIdle=10
#每次释放连接的最大数目
redis.numTestsPerEvictionRun=1024
#释放连接的扫描间隔(毫秒)
redis.timeBetweenEvictionRunsMillis=30000
#连接最小空闲时间
redis.minEvictableIdleTimeMillis=1800000
#连接空闲多久后释放, 当空闲时间>该值 且 空闲连接>最大空闲连接数 时直接释放
redis.softMinEvictableIdleTimeMillis=10000
#获取连接时的最大等待毫秒数,小于零:阻塞不确定的时间,默认-1
redis.maxWaitMillis=1500
#在获取连接的时候检查有效性, 默认false
redis.testOnBorrow=true
#在空闲时检查有效性, 默认false
redis.testWhileIdle=true
#连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true
redis.blockWhenExhausted=false
#redis://:[密码]@[服务器地址]:[端口]/[db index]
redis.url=redis://:[email protected]:6379/0
redis.host=192.168.168.223
redis.port=6379
redis.timeout=1000
redis.password=foobared
redis.database=0
jedis接口
package com.test.dao;
public interface JedisClient {
String get(String key);
String set(String key, String value);
String hget(String hkey, String key);
long hset(String hkey, String key, String value);
long incr(String key);
long expire(String key, int second);
long ttl(String key);
long del(String key);
long hdel(String hkey, String key);
}
单机实现与集群实现。
package com.test.dao.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.test.dao.JedisClient;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
@Service
public class JedisClientSingle implements JedisClient {
@Autowired
private JedisPool jedisPool;
@Override
public String get(String key) {
Jedis jedis = jedisPool.getResource();
String string = jedis.get(key);
jedis.close();
return string;
}
@Override
public String set(String key, String value) {
Jedis jedis = jedisPool.getResource();
String string = jedis.set(key, value);
jedis.close();
return string;
}
@Override
public String hget(String hkey, String key) {
Jedis jedis = jedisPool.getResource();
String string = jedis.hget(hkey, key);
jedis.close();
return string;
}
@Override
public long hset(String hkey, String key, String value) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.hset(hkey, key, value);
jedis.close();
return result;
}
@Override
public long incr(String key) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.incr(key);
jedis.close();
return result;
}
@Override
public long expire(String key, int second) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.expire(key, second);
jedis.close();
return result;
}
@Override
public long ttl(String key) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.ttl(key);
jedis.close();
return result;
}
@Override
public long del(String key) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.del(key);
jedis.close();
return result;
}
@Override
public long hdel(String hkey, String key) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.hdel(hkey, key);
jedis.close();
return result;
}
}
扫描二维码关注公众号,回复:
2649832 查看本文章
package com.test.dao.impl;
import org.springframework.beans.factory.annotation.Autowired;
import com.test.dao.JedisClient;
import redis.clients.jedis.JedisCluster;
public class JedisClientCluster implements JedisClient {
@Autowired
private JedisCluster jedisCluster;
@Override
public String get(String key) {
return jedisCluster.get(key);
}
@Override
public String set(String key, String value) {
return jedisCluster.set(key, value);
}
@Override
public String hget(String hkey, String key) {
return jedisCluster.hget(hkey, key);
}
@Override
public long hset(String hkey, String key, String value) {
return jedisCluster.hset(hkey, key, value);
}
@Override
public long incr(String key) {
return jedisCluster.incr(key);
}
@Override
public long expire(String key, int second) {
return jedisCluster.expire(key, second);
}
@Override
public long ttl(String key) {
return jedisCluster.ttl(key);
}
@Override
public long del(String key) {
return jedisCluster.del(key);
}
@Override
public long hdel(String hkey, String key) {
return jedisCluster.hdel(hkey, key);
}
}