基于SSM+Maven单号生成器:
- 订单号:业务类型+yyyyMMddHHmmss+ 6位流水号。
业务类型为任意2个英文字母,HHmmss为redis服务器的时间,6位流水号从1开始自增。
- KEY1:包名+业务类型+yyyyMMdd,48h过期
- KEY2:包名+HHmmss,这里设置KEY2是为了防止宕机后
仅作为初学记录,以供查阅。import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.xx.xx.JedisClient; /** * * @ClassName: SerialNumberUtil * @Description: 发号器:业务类型+yyyyMMddHHmmss+ 6位流水号 * @author * @date 2018年11月30日 下午12:42:01 * */ @Component public class SerialNumberUtil { @Autowired JedisClient jedisClient; Logger logger = LoggerFactory.getLogger(SerialNumberUtil.class); String value = ""; // 设置3秒过期 int DEFAULT_SINGLE_EXPIRE_TIME = 3; public String createNo(String bizCode) { // 此处代码是锁上的 if (this.tryLock("statusCheck")) { String date = new SimpleDateFormat("yyyMMdd").format(new Date()); String pacName = getPacName(); String key = pacName + bizCode + date; if (bizCode.matches("[a-zA-Z]{2}")) { jedisClient.incr(key); // 过期时间48小时 jedisClient.expire(key, 60 * 60 * 48); } String redisTime = getRedisTime(); // 获取redis服务器的时间HHmmss,防止宕机 String key2 = pacName + redisTime; if (jedisClient.get(key2) == null) { jedisClient.set(key2, redisTime); } value = jedisClient.get(key); value = bizCode + date + jedisClient.get(key2) + autoCOS(value); // unLock("statusCheck"); } return value; } /** * 获取包名 */ private String getPacName() { String clzName = Thread.currentThread().getStackTrace()[1].getClassName(); int index = clzName.lastIndexOf("."); String pacName = clzName.substring(0, index) + ":"; return pacName; } /** * 获取锁 如果锁可用 立即返回true, 否则立即返回false,作为非阻塞式锁使用 */ public boolean tryLock(String key) { try { return tryLock(key, key, 0L, null); } catch (InterruptedException e) { e.printStackTrace(); } return false; } /** * 锁在给定的等待时间内空闲,则获取锁成功 返回true, 否则返回false,作为阻塞式锁使用 * * @param key锁键 * @param value被谁锁定s * @param timeout尝试获取锁时长 * @param unit,建议传递TimeUnit.MILLISECONDS * @return * @throws InterruptedException */ public boolean tryLock(String key, String value, long timeout, TimeUnit unit) throws InterruptedException { // 纳秒 long begin = System.nanoTime(); do { // LOGGER.debug("{}尝试获得{}的锁.", value, key); Long i = jedisClient.setnx(key, value); if (i == 1) { jedisClient.expire(key, DEFAULT_SINGLE_EXPIRE_TIME); logger.debug(value + "-成功获取{}的锁,设置锁过期时间为{}秒 ", key, DEFAULT_SINGLE_EXPIRE_TIME); return true; } else { // 存在锁 ,但可能获取不到,原因是获取的一刹那间 // String desc = lockManger.jc.get(key); // LOGGER.error("{}正被{}锁定.", key, desc); } if (timeout == 0) { break; } // 在其睡眠的期间,锁可能被解,也可能又被他人占用,但会尝试继续获取锁直到指定的时间 Thread.sleep(100); } while ((System.nanoTime() - begin) < unit.toNanos(timeout)); // 因超时没有获得锁 return false; } /** * 释放单个锁 */ public void unLock(String key) { jedisClient.del(key); logger.debug("{}锁被{}释放 .", key, key); } /** * 获取Redis服务器时间(HHmmss) */ private String getRedisTime() { Long timestamp = Long.parseLong(jedisClient.time().get(0)) * 1000; String redisTime = new SimpleDateFormat("HHmmss", Locale.CHINA).format(new Date(timestamp)); return redisTime; } /** * 自动补全6位数自增序列 */ private String autoCOS(String v) { int DEFAULT_LENGTH = 6; int length = v.length(); if (length >= DEFAULT_LENGTH) { return v; } int rest = DEFAULT_LENGTH - length; StringBuilder sb = new StringBuilder(); for (int i = 0; i < rest; i++) { sb.append('0'); } sb.append(v); return sb.toString(); } }