1. 程式人生 > >mysql 自增長通用單號生成

mysql 自增長通用單號生成

平時工作中我們經常會生成各種單號,大部分的單號都是日期加上自增長的序列如:VC20181115001,VC201811151525001,常用格式: 字母 + yyyyMMdd + 001,字母 + yyyyMMddHHmmss + 001等等。

我們可以使用mysql解決這個問題,使用儲存過程呼叫,適合普通單號生成,不適合高併發的單號生成。

1.我們新建一張序列表 sys_sequence

 

CREATE TABLE `sys_sequence` (
  `name` varchar(32) NOT NULL,
  `value` int(10) DEFAULT NULL,
  `step` smallint(5) DEFAULT NULL,
  `start` int(10) DEFAULT NULL,
  PRIMARY KEY (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 name 欄位為我們設定的字母標識,value 欄位為當前的序列號,step為每次增長的數字大小,start為起始數字

2.我們新建一個儲存過程來呼叫生成序列,也可以用程式碼

 

CREATE PROCEDURE `generateSeq`(
IN m VARCHAR(100),OUT n INTEGER
)
BEGIN
   DECLARE t_error INTEGER DEFAULT 0;    
   DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET t_error=1;    
   START TRANSACTION;  
     
   SET @v:= (SELECT EXISTS (SELECT `value` FROM `sys_sequence` WHERE `name`=m));  
   SET @m=0;  
   IF(@v=0) THEN
	INSERT INTO `sys_sequence`(`name`,`value`,`step`,`start`) VALUE(m,(SELECT @m:=1),1,1);
   ELSE
	 UPDATE `sys_sequence` SET `value`
[email protected]
:=`value`+1 WHERE `name`=m; END IF; SET [email protected]; IF t_error =1 THEN ROLLBACK; SET n = -1; ELSE COMMIT; END IF; SELECT n ; END

儲存過程一個入參 name,一個出參n

首先根據傳入的引數name查詢出當前的序列值value,做個判斷如果這個value值等於0則表示是第一次生成序列號,則預設即將生成的序列號為1,自增長為1,如果value值不等0則表示不是第一次生成序列號,則更新當前獲取的序列號value值加1,最後在返回生成的序列號。

3.程式碼呼叫

我們可以用mybatis程式碼生成器生成表 sys_sequence 的程式碼,然後放進專案裡,這裡步驟省略。

SequenceService程式碼:

@Service
public class SequenceService {
    @Autowired
    private  SequenceExMapper sequenceExMapper

    //使用儲存過程事物控制
    @Transactional(readOnly = false, propagation = Propagation.NOT_SUPPORTED)
    public int getSeq(String name){
        Sequence sq = new Sequence();
        sq.setName(name);
        int value = sequenceExMapper.getSeq(sq);
        return  value;
    }

}

SequenceExMapper程式碼:

@Repository
public interface SequenceExMapper {

    int getSeq(Sequence sequence);

}

SequenceExMapper.xml 程式碼:

<select  id="getSeq"  statementType="CALLABLE" resultType="INTEGER">
       {    CALL generateSeq(
           #{name,jdbcType=VARCHAR,mode=IN},
           #{value,jdbcType=INTEGER,mode=OUT})
       }
</select >

Sequence 物件程式碼:

public class Sequence implements Serializable{
    private static final long serialVersionUID = 1L;
    private java.lang.String name;//
    private java.lang.Integer value;//
    private Short step;//
    private java.lang.Integer start;//
	
    // 省略get和set方法
}

我們在需要生成單號的地方呼叫 SequenceService的getSeq方法即可,注意這個方法返回的只是一個當前的序列號數字如5,如果想要005這樣的就需要我們再次拼接一下。

新建一個 CertificationService 程式碼:

@Service
public class CertificationService {
    private static Logger logger = LoggerFactory.getLogger(CertificationService.class);
    @Autowired
    private  SequenceService sequenceService;

    /**
     * 獲取編碼,格式如 VC20181115001
     * @return
     */
    public String getSeqDateNo() {
        int seqNo = sequenceService.getSeq("VC");
        String suffixCode =  String.format("%03d", seqNo);
        String currentDate = DateUtil.getDateStringCompact(new Date());
        String certificationNo = "VC" + currentDate + suffixCode;
        return certificationNo;
    }

    /**
     * 獲取編碼,格式如 VC201811151525001
     * @return
     */
    public String getSeqDateTimeNo() {
        int seqNo = sequenceService.getSeq("VC");
        String suffixCode =  String.format("%03d", seqNo);
        String currentDate = DateUtil.getDateTimeString4(new Date());
        String certificationNo = "VC" + currentDate + suffixCode;
        return certificationNo;
    }
} 

DateUtil的程式碼點選檢視