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表就可生成唯一的序列编号。不会影响其它客户程序的正常表操作.