JAVA纯代码自增序列支持集群

生成规则:

前缀+递增序列+后缀(如:A000001B;ALI000001BABA)

数据库实体对象Sequence(注:mod 属性不在表中,这里用于取模,使value的值循环在指定长度中)

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;

/**
 * mst_sequence
 * @author lix
 * @Date 2020/4/24
 */
@TableName("mst_sequence")
public class Sequence {

    /**
     * 主键,类型
     */
    @TableId
    private String type;
    /**
     * 前缀
     */
    private String prefix;
    /**
     * 后缀
     */
    private String suffix;
    /**
     * 缓存大小
     */
    @TableField("cache_size")
    private int cacheSize;
    /**
     * 当前值
     */
    private long value;
    /**
     * 临界值
     */
    private long crucial;
    /**
     * value最大长度(不含前后缀)
     */
    @TableField("value_length")
    private int valueLen;
    /**
     * 版本号
     */
    private int version;
    /**
     * 模
     */
    @TableField(exist = false)
    private int mod = 1;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getPrefix() {
        return prefix == null ? "" : prefix;
    }

    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }

    public String getSuffix() {
        return suffix == null ? "" : suffix;
    }

    public void setSuffix(String suffix) {
        this.suffix = suffix;
    }

    public int getCacheSize() {
        return cacheSize;
    }

    public void setCacheSize(int cacheSize) {
        this.cacheSize = cacheSize;
    }

    public long getValue() {
        return value;
    }

    public void setValue(long value) {
        this.value = value;
    }

    public long getCrucial() {
        return crucial;
    }

    public void setCrucial(long crucial) {
        this.crucial = crucial;
    }

    public int getValueLen() {
        return valueLen;
    }

    public void setValueLen(int valueLen) {
        this.valueLen = valueLen;
    }

    public int getVersion() {
        return version;
    }

    public void setVersion(int version) {
        this.version = version;
    }


    public int getMod() {
        if (mod == 1) {
            for (int i = 0; i < valueLen; i++) {
                mod *= 10;
            }
        }
        return mod;
    }

    /**
     * 获取String补零format
     * @return
     */
    public String getValueFillFormat(){
        return "%0" + this.valueLen + "d";
    }

}

生成逻辑service(关于缓存序列号的问题这里不作处理,有nosql或者MQ的可以使用更好的方式处理,这里也不使用多线程异步更新,个人感觉意义不是很大。对于代码中的cacheMap各位码友根据自己情况优化)

import com.platform.mst.model.entity.Sequence;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

@Service
public class SequenceService {

    private Map<String, Sequence> cacheMap = new HashMap<>();

    @Autowired
    private SequenceHelper helper;

    public String serial(String type){
        synchronized (cacheMap){
            Sequence sequence = cacheMap.get(type);
            if(sequence == null || sequence.getValue() >= sequence.getCrucial()){
                sequence = helper.getSequence(type);
            }
            long nextVal = sequence.getValue() + 1;
            sequence.setValue(nextVal);
            cacheMap.put(type, sequence);
            long seq = nextVal % sequence.getMod();
            return sequence.getPrefix() + String.format(sequence.getValueFillFormat(), seq) + sequence.getSuffix();
        }
    }
}

辅助类SequenceHelper(注:这里需要分开写在不同的类里,这里的代码不要和service放在一起,这里需要加入事物注解,创建新事物管理,无论service是否异常,这里必须提交成功,否则会出现重复序列)

import com.platform.mst.database.mapper.SequenceMapper;
import com.platform.mst.model.entity.Sequence;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Component
public class SequenceHelper {

    @Autowired
    private SequenceMapper sequenceMapper;

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public Sequence getSequence(String type) {
        Sequence sequence;
        int count;
        do {
            sequence = sequenceMapper.selectById(type);
            if (sequence == null) throw new IllegalArgumentException(String.format("序列表中没有type为%s的数据", type));
            sequence.setValue(sequence.getCrucial());
            sequence.setCrucial(sequence.getCrucial() + sequence.getCacheSize());
            count = sequenceMapper.updateById(sequence);
        } while (count < 1);
        return sequence;
    }


}

mysql建表语句

CREATE TABLE `mst_sequence` (
  `type` varchar(64) NOT NULL COMMENT '唯一类型',
  `prefix` varchar(4) DEFAULT NULL COMMENT '前缀',
  `suffix` varchar(4) DEFAULT NULL COMMENT '后缀',
  `cache_size` smallint(3) NOT NULL DEFAULT '0' COMMENT '缓存大小',
  `value` bigint(16) NOT NULL DEFAULT '0' COMMENT '当前值',
  `crucial` bigint(16) NOT NULL DEFAULT '0' COMMENT '临界值',
  `value_length` tinyint(2) NOT NULL COMMENT '值得长度(不含前后缀)',
  `version` int(255) NOT NULL DEFAULT '0' COMMENT '版本号',
  PRIMARY KEY (`type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

你可能感兴趣的:(JAVA,java)