小夜埙
路很长,要耐心,慢慢走!

最近又遇到需要根据日期生成流水号的业务,然后记录了几种生成方法,一个是通过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生成,在保存时会出现相同编号的问题。

posted on 2019-06-12 18:13  小夜埙  阅读(1243)  评论(0编辑  收藏  举报