最近又遇到需要根据日期生成流水号的业务,然后记录了几种生成方法,一个是通过java代码,一个是数据库的触发器,还有是通过redis。下面是代码:
通过java生成简易流水:
/**
* 通过日期和生成的流水号拼接
* @param maxCount 已经生成的个数
* @return
*/
public static String recountNew(int maxCount) {
if (maxCount < 0) {
return null;
}
//201707999
String str = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMM"));
String countStr = str + num(maxCount, 3, 3);
System.out.println("合同编号: " + Long.valueOf(countStr));
return countStr;
}
/**
* 生成流水号
* @param current 当前生成个数
* @param max 最大整数位
* @param min 最小整数位
* @return 生成的流水号
*/
public static String num(int current, int max, int min) {
current++;
NumberFormat numberFormat = NumberFormat.getInstance();
//设置是否使用分组
numberFormat.setGroupingUsed(false);
//设置最大整数位数
numberFormat.setMaximumIntegerDigits(max);
//设置最小整数位数
numberFormat.setMinimumIntegerDigits(min);
return numberFormat.format(current);
}
通过数据触发器实现:
主要逻辑:以201906001 为例,根据当前日期 201606 获取流水号最大的一个,保存到n。然后把流水号加1,再和当前日期201906拼接到一起
CREATE TABLE orders (
orders_id INT (10) PRIMARY KEY,
customer_name VARCHAR (100)
);
DROP TRIGGER tr_orders_id;
CREATE TRIGGER tr_orders_id BEFORE INSERT ON orders FOR EACH ROW
BEGIN
DECLARE
n INT;
SELECT
IFNULL(max(RIGHT(orders_id, 3)), 0) INTO n
FROM
orders
WHERE
mid(orders_id, 1, 6) = DATE_FORMAT(now(), '%Y%m');
SET NEW.orders_id = concat(
DATE_FORMAT(now(), '%Y%m'),
RIGHT (001 + n, 3)
);
END;
INSERT INTO orders VALUES (0, 'jack');
INSERT INTO orders VALUES (0, 'jack');
redis实现(采用)
主要利用 StringRedisTemplate 来操作redis,写在业务层,需要使用直接注入就行。这是没有详细的说明配置StringRedisTemplate,下面代码会有问题,只是知道有这个方法,有用的时候,自己去写一下就好了。
/**
* @version V1.0
* @Authoer CX
* @Since:2019/5/20
*/
public interface NumberGenService {
/**
* 根据code生成编号
* 例:NB000001
* @param code 前缀
* @return 编号
*/
String generateNumber(String code);
/**
* 根据code及年月生成编号
* 例子:NB201905000001
* @param code 前缀
* @return 编号
*/
String generateNumberByMonth(String code);
/**
* 根据code及年月生成编号
* 例子:NB20190508000001
* @param code 前缀
* @return 编号
*/
String generateNumberByDay (String code);
}
import com.cloudkeeper.confinement.main.service.NumberGenService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @version V1.0
* @Authoer CX
* @Since:2019/5/20
*/
@Service
public class NumberGenServiceImpl implements NumberGenService {
@Autowired
private StringRedisTemplate stringRedisTemplate;
private static final int LENGTH = 6;
private static final String MONTH_FORMAT = "yyyyMM";
private static final String DAY_FORMAT = "yyyyMMdd";
public String generateNumber (String code) {
return getNumber(code, "");
}
public String generateNumberByMonth (String code) {
return getNumber(code, new SimpleDateFormat(MONTH_FORMAT).format(new Date()));
}
public String generateNumberByDay (String code) {
return getNumber(code, new SimpleDateFormat(DAY_FORMAT).format(new Date()));
}
private String getNumber(String code, String month) {
code += month;
Long number = stringRedisTemplate.opsForValue().increment("" + ":" + code);
return code + StringUtils.leftPad(number.toString(), LENGTH, '0');
}
}
总结
以上是总结的几种实现方式,公司采用的是通过redis的自增来实现的,可以避免并发时生成相同编号的问题。通过java生成,在保存时会出现相同编号的问题。