团队更换新框架。新的业务全部使用新的框架,甚至是新的数据库--Mysql。
这边之前一直是使用oracle,各种订单号、流水号、批次号啥的,都是直接使用oracle的sequence提供的数字序列号。现在数据库更换成Mysql了,显然以前的老方法不能适用了。
需要新写一个:
分布式场景使用
满足一定的并发要求
找了一些相关的资料,发现mysql这方面的实现,原理都是一条数据库记录,不断update它的值。然后大部分的实现方案,都用到了函数。
贴一下网上的代码:
基于mysql函数实现
表结构
CREATE TABLE `t_sequence` (
`sequence_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '序列名称' ,
`value` int(11) NULL DEFAULT NULL COMMENT '当前值' ,
PRIMARY KEY (`sequence_name`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci
ROW_FORMAT=COMPACT
;
获取下一个值
CREATE DEFINER = `root`@`localhost` FUNCTION `nextval`(sequence_name varchar(64))
RETURNS int(11)
BEGIN
declare current integer;
set current = 0;
update t_sequence t set t.value = t.value + 1 where t.sequence_name = sequence_name;
select t.value into current from t_sequence t where t.sequence_name = sequence_name;
return current;
end;
并发场景有可能会出问题,虽然可以在业务层加锁,但分布式场景就无法保证了,然后效率应该也不会高。
自己实现一个,java版
原理:
读取一条记录,缓存一个数据段,如:0-100,将记录的当前值从0修改为100
数据库乐观锁更新,允许重试
读取数据从缓存中读取,用完再读取数据库
不废话,上代码:
基于java实现
表结构
每次update,都是将SEQ_VALUE设置为SEQ_VALUE+STEP
CREATE TABLE `t_pub_sequence` (
`SEQ_NAME` varchar(128) CHARACTER SET utf8 NOT NULL COMMENT '序列名称',
`SEQ_VALUE` bigint(20) NOT NULL COMMENT '目前序列值',
`MIN_VALUE` bigint(20) NOT NULL COMMENT '最小值',
`MAX_VALUE` bigint(20) NOT NULL COMMENT '最大值',
`STEP` bigint(20) NOT NULL COMMENT '每次取值的数量',
`TM_CREATE` datetime NOT NULL COMMENT '创建时间',
`TM_SMP` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`SEQ_NAME`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='流水号生成表';
sequence接口
/**
*
* @author coderzl
* @Title MysqlSequence
* @Description 基于mysql数据库实现的序列
* @date 2017/6/6 23:03
*/
public interface MysqlSequence {
/**
*
* 获取指定sequence的序列号
*
* @param seqName sequence名
* @return String 序列号
*/
public String nextVal(String seqName);
}
序列区间
用于本地缓存一段序列,从min到max区间
/**
*
*
* @author coderzl
* @Title SequenceRange
* @Description 序列区间,用于缓存序列
* @date 2017/6/6 22:58
*/
@Data
public class SequenceRange {
private final long min;
private final long max;
/** */
private final AtomicLong value;
/** 是否超限 */
private volatile boolean over = false;
/**
* 构造.
*
* @param min
* @param max
*/
public SequenceRange(long min, long max) {
this.min = min;
this.max = max;
this.value = new AtomicLong(min);
}
/**
*
Gets and increment