mysql 和 java 自增长序号
select (@rowNO := @rowNo+1) AS rowno,s.com_uid from (select com_uid from sms_balance) s,(select @rowNO :=0) b ;
或者 获取最大的编号,然后加1 再保存到数据库中.
产生自定义格式的自动增长序列号:
/**
* 自己维护的序列号,至少从1开始增长
*/
public abstract class IncrementNumber {
public IncrementNumber() {}
public IncrementNumber(int interval, int maxNum) {
this.interval = interval;
this.maxNum = maxNum;
}
public synchronized int cal() throws Exception {
if (serialNum == -1) {
serialNum = initStartNum(); // 已经使用的序列号一定 小于 缓存的序列号
intervalMax = serialNum + interval;
updateStartNum(intervalMax);
return serialNum;
}
if (isMax(serialNum)) { // 达到预定的最大值
resetSerialNum();
return serialNum;
}
serialNum++;
if (serialNum >= (intervalMax - 1)) { // 到达区间最大值
intervalMax += interval;
updateStartNum(intervalMax);
}
return serialNum;
}
/**
* 初始化序列号,从缓存系统中来,比如数据库、文件等
* @return 初始序列号
* @throws Exception
*/
public abstract int initStartNum() throws Exception;
/**
* 更新区间最大值到缓存系统,比如数据库、文件中。
* @param intervalMax 区间最大值
* @throws Exception
*/
public abstract void updateStartNum(int intervalMax) throws Exception;
/**
* 重置序列号,从1开始
*/
protected void resetSerialNum() throws Exception {
this.serialNum = 1;
intervalMax = serialNum + interval;
updateStartNum(intervalMax);
}
/**
* 是否是最大值
* @param num
* @return
*/
private boolean isMax(int num) {
return num >= maxNum;
}
public int getInterval() {
return this.interval;
}
public int getMaxNum() {
return this.maxNum;
}
/** 区间最大值 */
protected int intervalMax = 0;
/** 每次增加量 */
protected int interval = 20;
/** 预定的最大值 */
protected int maxNum = 9999;
/** 序列号 */
protected int serialNum = -1;
} 使用方法:
@Service
@Transactional
public class TableKeyManager extends IncrementNumber {
public TableKeyManager() {
super(100, 99999999);
}
@Override
public int initStartNum() throws Exception {
TableKey tableKey = tableKeyDao.getById(name);
date = DateConvertUtils.getDayEnd(DateConvertUtils.parse(tableKey.getDate(), "yyMMdd"));
dateEndMillis = date.getTime();
prefix = tableKey.getDate();
return (int) tableKey.getMaxNum();
}
@Override
public void updateStartNum(int intervalMax) throws Exception {
TableKey tableKey = tableKeyDao.getById(name);
tableKey.setDate(DateConvertUtils.format(new Date(dateEndMillis), "yyMMdd"));
tableKey.setMaxNum(intervalMax);
tableKeyDao.update(tableKey);
}
public String getNum() {
try {
long now = System.currentTimeMillis();
int no = 0;
if (now > dateEndMillis) {
date = DateConvertUtils.getDayEnd(new Date(now));
dateEndMillis = date.getTime();
prefix = DateConvertUtils.format(date, "yyMMdd");
resetSerialNum();
no = this.serialNum;
} else {
no = cal();
}
return prefix + ApplicationUtil.getFixedSizeNum(no, 8);
} catch (Exception e) {
e.printStackTrace();
}
throw new RuntimeException("生成序列号错误");
}
public void setName(String name) {
this.name = name;
}
private String prefix = null;
private long dateEndMillis = 0l;
private Date date = null;
private String name;
@Autowired
private TableKeyDao tableKeyDao;
} 这种方法仅在初始化时查询一次数据库,在每次到达增长上限时,计数自动叠加一个步长,同时更新数据库中的数据上限。
table_key的数据结构
- CREATE TABLE `table_key` (
- `key_name` varchar(100) NOT NULL COMMENT '需要维护的key名称',
- `cur_no` mediumtext COMMENT '当前数据编号',
- `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '数据编号更新时间',
- `create_time` datetime DEFAULT NULL COMMENT '记录创建时间',
- PRIMARY KEY (`key_name`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8
在不用AUTO_INCREMENT的情况下生成序列,可利用带参数的LAST_INSERT_ID()函数。如果用一个带参数的LAST_INSERT_ID(expr)去插入或修改一个数据列,紧接着又调用不带参数的LAST_INSERT_ID()函数,则第二次函数调用返回的就是expr的值。下面演示该方法的具体操作:
先创建一个只有一个数据行的数据表:create table seq_table (id int unsigned not null);insert into seq_table values (0);接着用以下操作检索出序列号:
update seq_table set seq = LAST_INSERT_ID( seq + 1 );select LAST_INSERT_ID();
通过修改seq+1中的常数值,可生成不同步长的序列,如seq+10可生成步长为10的序列。该方法可用于计数器,在数据表中插入多行以记录不同的计数值。再配合LAST_INSERT_ID()函数的返回值生成不同内容的计数值。这种方法的优点是不用事务或LOCK,UNLOCK表就可生成唯一的序列编号。不会影响其它客户程序的正常表操作.
