1、本文适用MySQL8.0以上,其它版本未测试,开发人员无测试环境,建议使用DOCKER,一行命令即实现安装测试.
注意:以下命令创建的MYSQL数据库
docker run --name mysql -p 3306:3306 -v /light/mysql/conf:/etc/mysql/conf.d -v /light/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=xxxx@PasswOrdD8mi -e TZ=Asia/Shanghai -d mysql --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --lower_case_table_names=1 --log_bin_trust_function_creators=true
2、现状:MySQL有内置的UUID()或者UUID_SHORT()可以满足到大多数场景,但当我们看到如下所示ID时候,维护是非常不便
3、为得到更有“意义”的ID,或者说表意ID,或者叫顺序号ID,我们要自己生成,如下图所示:
4、MYSQL自定义函数,实现自增ID
使用时直接输入ID分组即可自动增加,不需要手工配置,NEWID函数参数根据需要自己填写即可,非常方便,用法如下:
select newid(null), newid('USER'), newid('EQUIP');
5、先生成ID数据表
生成脚本
drop table if exists t_sm_id;
/*==============================================================*/
/* Table: t_sm_id */
/*==============================================================*/
create table t_sm_id
(
id varchar(50) not null comment 'rowid',
syscode varchar(20) comment '功能编码',
last_id bigint comment '最新id',
remark varchar(200) comment '备注',
create_time varchar(30),
update_time varchar(30),
create_user_id varchar(50),
update_user_id varchar(50),
primary key (id)
);
alter table t_sm_id comment '系统ID表';
6、newid定义函数(MYSQL自定义函数)
-- QQ: 380105206 WECHAT: 13316098767
DROP FUNCTION IF EXISTS newid;
DELIMITER $$$
CREATE FUNCTION newid(
P_SYSCODE VARCHAR(20)
)
RETURNS varchar(50)
BEGIN
DECLARE v_syscode VARCHAR(20); -- ID分组编码
DECLARE v_last_id VARCHAR(50); -- 最新的ID
DECLARE v_last_id_format VARCHAR(100); -- 最新的ID
DECLARE v_id_len INT ; -- ID最小填充长度
DECLARE v_id_sep_len INT ; -- ID 分组长度
SET v_syscode = IFNULL(P_SYSCODE, 'ID'); -- NULL默认取'ID'
SET v_syscode = CASE WHEN v_syscode = '' THEN 'ID' ELSE v_syscode END; -- '' 默认取'ID'
SET v_id_len = 9; -- ID最小填充长度
SET v_id_sep_len = 3; -- ID 分组长度
-- 如果没有定义编码,则应该先定义,但可能产生并发问题,所以插入是还应增加判定条件
-- ID = SYSCODE
IF NOT EXISTS (SELECT * FROM t_sm_id WHERE id = v_syscode) THEN
INSERT INTO t_sm_id
(
id ,-- varchar(50) not null comment 'rowid',
syscode ,-- varchar(20) comment '功能编码',
last_id ,-- bigint comment '最新id',
remark ,-- varchar(200) comment '备注',
create_time ,-- varchar(30),
update_time ,-- varchar(30),
create_user_id ,-- varchar(50),
update_user_id -- varchar(50),
)
SELECT v_syscode, v_syscode, 0, '', NOW(), NOW(), 'SYS', 'SYS'
WHERE NOT EXISTS (SELECT * FROM t_sm_id WHERE id = v_syscode);
END IF;
-- 更新ID
UPDATE t_sm_id SET last_id=LAST_INSERT_ID(last_id+1), update_time = NOW() WHERE id = v_syscode;
SET v_last_id = LAST_INSERT_ID();
-- 返回结果
-- 格式1:编码 + '-' + 序列号
-- RETURN CONCAT( v_syscode, '-', LAST_INSERT_ID() );
-- 格式2:6位0 左填充
-- RETURN CONCAT( v_syscode, '-', LPAD( v_last_id, 6, '0') );
-- 格式3:9 位0 左填充
SET v_last_id = LPAD( v_last_id, v_id_len, '0');
SET v_last_id_format = (SELECT REPLACE(
GROUP_CONCAT(
SUBSTRING(v_last_id, IDX * v_id_sep_len + 1, v_id_sep_len)
)
, ',', '-')
-- , SUBSTRING('7654769877827788', IDX * 4 + 1, 4)
FROM (SELECT 0 AS idx UNION SELECT 1 AS idx UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) t
WHERE IDX < LENGTH(v_last_id) / v_id_sep_len);
RETURN CONCAT( v_syscode, '-', v_last_id_format );
END
$$$
select newid('USER'), LPAD(4, 3, '0') ;
select newid(null), newid('USER'), newid('EQUIP');
SELECT * FROM t_sm_id;
7、简单测试了一下性能,因为要更新表,速度不是太快,如果要生成的ID比较多,建议调整ID步长,或者将ID步长作为参数从外面传入也可:
不足之处或建议意见,请QQ:380105206 或者wx: 13316098767 或 [email protected]