日期+序列构建系统唯一序列号(二)

前一篇博客中介绍了如何简单构建时间+序号的唯一序列号,

本次介绍下构建带有按年、月、日复位的时间+序号的唯一序列号方法。

基本思路:

1、设计一张表存储序列号,字段要包含:序列号、复位标志、时间;

2、每次取序列号的时候,都需要拿当前时间和存储的时间比较;

3、判断复位标志,

     如果是按年复位,比较的年不同则序列号清零;

     如果是按月复位,比较的月不同则序列号清零;

     如果是按日复位,比较的日不同则序列号清零;

     如果比较的日期相同,则序列号+1后更新到表格,时间也要更新。


show code

一、建表sql

-- Create table
create table T_SERIAL
(
  id          VARCHAR2(32) not null,
  name        VARCHAR2(50),
  scope       VARCHAR2(50),
  serial      VARCHAR2(10),
  formatter   VARCHAR2(64),
  description VARCHAR2(100),
  subsys      CHAR(1),
  st          TIMESTAMP(6),
  revision    INTEGER
)
tablespace USERS
  pctfree 10
  initrans 1
  maxtrans 255
  storage
  (
    initial 64K
    next 1M
    minextents 1
    maxextents unlimited
  );
-- Add comments to the table 
comment on table T_SERIAL is '序列号记录表';
-- Add comments to the columns 
comment on column T_SERIAL.id is '物理主键';
comment on column T_SERIAL.name is '序列号名称(英文或字母表示)';
comment on column T_SERIAL.scope is '序列号取值范围';
comment on column T_SERIAL.serial is '序列号';
comment on column T_SERIAL.formatter is '序列号格式化位数(序列号补足位数前面补0)';
comment on column T_SERIAL.description is '序列号中文描述';
comment on column T_SERIAL.subsys is '序列号复位标志(1:按天复位 2:按月复位 3:按年复位)';
comment on column T_SERIAL.st is '系统时间';
comment on column T_SERIAL.revision is '序列版本号';
-- Create/Recreate primary, unique and foreign key constraints 
alter table T_SERIAL add constraint PRIMARY_KEY_B3 primary key (ID)
  using index 
  tablespace USERS
  pctfree 10
  initrans 2
  maxtrans 255
  storage
  (
    initial 64K
    next 1M
    minextents 1
    maxextents unlimited
  );

--  插入序列号
--  发送流水号 按天复位   格式如:20170911000000001
insert into T_SERIAL(id, name, scope, serial, formatter, description, subsys, st, revision) values
(sys_guid(), 'FSLSH','' , '0', '%09d', '发送流水号', '1', sysdate, '0');
--  业务流水号 按月复位   格式如:201709000000001
insert into T_SERIAL(id, name, scope, serial, formatter, description, subsys, st, revision) values
(sys_guid(), 'YWLSH','' , '0', '%09d', '业务流水号', '2', sysdate, '0');
--  角色编号 按年复位   格式如:201700001
insert into T_SERIAL(id, name, scope, serial, formatter, description, subsys, st, revision) values
(sys_guid(), 'ROLECODE','' , '0', '%05d', '角色编号', '3', sysdate, '0');

二、表实例

package serial;

import java.util.Date;

 public class CtlSerial{
   private String id;
   private String name;
   private String scope;
   private String serial;
   private String formatter;
   private String description;
   private String subsys;
   private Date st;
   private int revision;
 
   public String getId(){
     return this.id; }
 
   public void setId(String id) {
     this.id = id;
   }
 
   public String getName() {
     return this.name; }
 
   public void setName(String name) {
     this.name = name;
   }
 
   public String getScope() {
     return this.scope; }
 
   public void setScope(String scope) {
     this.scope = scope;
   }
 
   public String getSerial() {
     return this.serial; }
 
   public void setSerial(String serial) {
     this.serial = serial;
   }
 
   public String getFormatter() {
     return this.formatter; }
 
   public void setFormatter(String formatter) {
     this.formatter = formatter;
   }
 
   public String getDescription() {
     return this.description; }
 
   public void setDescription(String description) {
     this.description = description;
   }
 
   public String getSubsys() {
     return this.subsys; }
 
   public void setSubsys(String subsys) {
     this.subsys = subsys;
   }
 
   public Date getSt() {
     return this.st; }
 
   public void setSt(Date st) {
     this.st = st;
   }
 
   public int getRevision() {
     return this.revision; }
 
   public void setRevision(int revision) {
     this.revision = revision;
   }
 
   public int getRevisionNext() {
     return (this.revision + 1);
   }
 }


三、业务序列号获取

package serial;

import java.util.Calendar;

import com.tienon.framework.supports.SpringContext;

/**
 * @author leiwei
 * @Description 业务序列号获取,如业务流水号   获取方法Serial.getYWLSH()
 * @date 2016年10月10日
 */
public class Serial { 
	static CtlSerialService ctlSerialService = SpringContext.getApplicationContext().getBean(CtlSerialService.class);
	public static final String YEAR = "3";
	public static final String MONTH = "2";
	public static final String DAY = "1";
	
	public static String getBusinessCode(String name){
		String busiCode = null;
		CtlSerial serial = ctlSerialService.getCtlSerial(name);
		try{ 
			if(serial != null){
				String formatter = serial.getFormatter();
				if(formatter != null && !"".equals(formatter))
					busiCode = String.format(formatter, Integer.parseInt(serial.getSerial()));
				else
					busiCode = serial.getSerial();
			}
			String subsys = serial.getSubsys();//复位标识符
			if(subsys != null) {
				String prefix = "";//前缀
				Calendar calendar = Calendar.getInstance();
				int year = calendar.get(Calendar.YEAR);
				int month = calendar.get(Calendar.MONTH) + 1;
				String months = String.format("%02d", month);
				int day = calendar.get(Calendar.DAY_OF_MONTH);
				String days = String.format("%02d", day);
				if(YEAR.equals(subsys)) {//按年复位     格式:yyyy+序列号
					prefix = String.valueOf(year);
				} else if(MONTH.equals(subsys)){//按月复位    格式:yyyyMM+序列号
					prefix = String.valueOf(year) + months;
				} else if(DAY.equals(subsys)){//按日复位    格式:yyyyMMdd+序列号
					prefix = String.valueOf(year) + months + days;
				}
				busiCode = prefix + busiCode;
			}
		}catch(Exception e){
			throw new RuntimeException("序列号{"+name+"}格式化出错!", e);
		}
		return busiCode;
	}

	/**
	 * 获取交易流水号
	 * @return
	 */
	public static String getYWLSH(){
		return getBusinessCode("YWLSH");
	}

}

四、处理序列号核心service

package serial;

import java.util.Calendar;
import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;


public class CtlSerialService {

	@Resource
	CtlSerialMapper ctlSerialMapper;

	public CtlSerial getCtlSerial(String name) {
		//每次查询序列号的时候都使用悲观锁防止并发问题s  select ... from ...  where ... for update
		CtlSerial ctlSerial = this.ctlSerialMapper.selectByName(name);
		//如果该name对应的序列号不存在,则新增一条记录
		if (ctlSerial == null) {
			ctlSerial = new CtlSerial();
			ctlSerial.setId(UUID.randomUUID().toString().replace("-", ""));
			ctlSerial.setName(name);

			ctlSerial.setRevision(1);
			ctlSerial.setSerial("1");
			ctlSerial.setSt(new Date());
			this.ctlSerialMapper.insert(ctlSerial);
		}

		String subsys = ctlSerial.getSubsys();
		Date st = ctlSerial.getSt();
		if ((StringUtils.isNotEmpty(subsys)) && (null != st)) {
			Calendar bizCal = Calendar.getInstance();
			bizCal.setTime(st);
			Calendar sysCal = Calendar.getInstance();
			sysCal.setTime(new Date());

			if (("1".equals(subsys)) && (bizCal.get(5) != sysCal.get(5))){//日复位
				ctlSerial.setSerial("0");
			} else if (("2".equals(subsys)) && (bizCal.get(2) != sysCal.get(2))){//月复位
				ctlSerial.setSerial("0");
			} else if (("3".equals(subsys)) && (bizCal.get(1) != sysCal.get(1))){//年复位
				ctlSerial.setSerial("0");
			}
		}

		//序号加一后更新序号记录表
		long oldValue = Long.parseLong(ctlSerial.getSerial());
		long newValue = oldValue + 1L;
		ctlSerial.setSerial(Long.toString(newValue));
		ctlSerial.setSt(new Date());
		this.ctlSerialMapper.updateByPrimaryKey(ctlSerial);
		return ctlSerial;
	}
}


五、DAO接口

package serial;


public abstract interface CtlSerialMapper {

	public abstract int insert(CtlSerial paramCtlSerial);

	public abstract int updateByPrimaryKey(CtlSerial paramCtlSerial);

	public abstract CtlSerial selectByName(String paramString);
}


六、SQL

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="serial.CtlSerialMapper">
	<resultMap id="BaseResultMap" type="serial.CtlSerial">
		<id column="ID" property="id" jdbcType="VARCHAR" />
		<result column="NAME" property="name" jdbcType="VARCHAR" />
		<result column="SCOPE" property="scope" jdbcType="VARCHAR" />
		<result column="SERIAL" property="serial" jdbcType="VARCHAR" />
		<result column="FORMATTER" property="formatter" jdbcType="VARCHAR" />
		<result column="DESCRIPTION" property="description" jdbcType="VARCHAR" />
		<result column="SUBSYS" property="subsys" jdbcType="CHAR" />
		<result column="ST" property="st" jdbcType="TIMESTAMP" />
		<result column="REVISION" property="revision" jdbcType="INTEGER" />
	</resultMap>
	<sql id="Base_Column_List">
		ID, NAME, SCOPE, SERIAL, FORMATTER, DESCRIPTION, SUBSYS,
		ST, REVISION
	</sql>

	<insert id="insert" parameterType="serial.CtlSerial">
		insert into SS_CTL_SERIAL (
		ID,
		NAME,
		SCOPE,
		SERIAL,
		FORMATTER,
		DESCRIPTION,
		SUBSYS,
		ST,
		REVISION
		) values (
		#{id,jdbcType=VARCHAR},
		#{name,jdbcType=VARCHAR},
		#{scope,jdbcType=VARCHAR},
		#{serial,jdbcType=VARCHAR},
		#{formatter,jdbcType=VARCHAR},
		#{description,jdbcType=VARCHAR},
		#{subsys,jdbcType=CHAR},
		#{st,jdbcType=TIMESTAMP},
		1
		)
	</insert>

	<update id="updateByPrimaryKey" parameterType="serial.CtlSerial">
		update
		SS_CTL_SERIAL set
		SERIAL = #{serial,jdbcType=VARCHAR},
		ST = #{st,jdbcType=TIMESTAMP},
		REVISION = #{revisionNext,jdbcType=INTEGER}
		where
		ID = #{id,jdbcType=VARCHAR}
		AND REVISION = #{revision,jdbcType=INTEGER}
	</update>

	<select id="selectByName" resultMap="BaseResultMap">
		select *
		from SS_CTL_SERIAL
		where
		NAME = #{name,jdbcType=VARCHAR}
		for update
	</select>

</mapper>




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值