SQL是Structured Query Language(结构化查询语言)的缩写。SQL是专为数据库而建立的操作命令集,是一种功能齐全的数据库语言。在使用它时,只需要发出“做什么”的命令,“怎么做”是不用使用者考虑的。SQL功能强大、简单易学、使用方便,已经成为了数据库操作的基础,并且现在几乎所有的数据库均支持SQL。 下面小编就为大家带来一篇基于Mysql的Sequence实现方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧团队更换新框架。新的业务全部使用新的框架,甚至是新的数据库--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接口
/**
* <p></p>
* @author coderzl
* @Title MysqlSequence
* @Description 基于mysql数据库实现的序列
* @date 2017/6/6 23:03
*/
public interface MysqlSequence {
/**
* <p>
* 获取指定sequence的序列号
* </p>
* @param seqName sequence名
* @return String 序列号
*/
public String nextVal(String seqName);
} 序列区间 用于本地缓存一段序列,从min到max区间
/**
* <p></p>
*
* @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);
}
/**
* <p>Gets and increment</p>
*
* @return
*/
public long getAndIncrement() {
long currentValue = value.getAndIncrement();
if (currentValue > max) {
over = true;
return -1;
}
return currentValue;
}
} BO 对应数据库记录
@Data
public class MysqlSequenceBo {
/**
* seq名
*/
private String seqName;
/**
* 当前值
*/
private Long seqValue;
/**
* 最小值
*/
private Long minValue;
/**
* 最大值
*/
private Long maxValue;
/**
* 每次取值的数量
*/
private Long step;
/** */
private Date tmCreate;
/** */
private Date tmSmp;
public boolean validate(){
//一些简单的校验。如当前值必须在最大最小值之间。step值不能大于max与min的差
if (StringUtil.isBlank(seqName) |