Spring Boot集成Oracle时如何实现AAA格式字母编码自增
3位大写字母自增产品编码实现方案
这个编码规则本质是固定3位的26进制计数:A对应数值0,B对应1,一直到Z对应25,进位逻辑和十进制完全一致——最低位(最右侧字符)从A走到Z后归位为A,向中间位进1;中间位走到Z后继续向最高位(最左侧字符)进位,初始值AAA对应数值0,每新增1条记录数值加1再转成字母即可,和给出的序列规则完全匹配。
以下是对应技术栈的具体实现,优先保证并发场景下不重号:
1. Oracle数据库层实现(核心逻辑放这层最稳妥)
推荐直接用Oracle原生序列做数值自增,从底层避免并发重号问题,不需要业务层做额外控制。
- 第一步:创建自增序列
-- 序列从0开始,每次步长1,缓存20个值提升插入性能 CREATE SEQUENCE SEQ_PRODUCT_CODE START WITH 0 INCREMENT BY 1 CACHE 20;
- 第二步:创建数值转编码的自定义函数,直接输出符合规则的3位编码
CREATE OR REPLACE FUNCTION NUM_TO_PRODUCT_CODE(p_num IN NUMBER) RETURN VARCHAR2 IS v_code VARCHAR2(3); v_remain NUMBER := p_num; v_bit NUMBER; BEGIN -- 计算最低位(最右侧字符,对应26^0位) v_bit := MOD(v_remain, 26); v_code := CHR(65 + v_bit); v_remain := TRUNC(v_remain / 26); -- 计算中间位(对应26^1位) v_bit := MOD(v_remain, 26); v_code := CHR(65 + v_bit) || v_code; v_remain := TRUNC(v_remain / 26); -- 计算最高位(最左侧字符,对应26^2位) v_bit := MOD(v_remain, 26); v_code := CHR(65 + v_bit) || v_code; RETURN v_code; END; /
可以直接在Oracle里测试验证:
SELECT NUM_TO_PRODUCT_CODE(0) FROM DUAL;返回AAASELECT NUM_TO_PRODUCT_CODE(25) FROM DUAL;返回AAZSELECT NUM_TO_PRODUCT_CODE(26) FROM DUAL;返回ABA,完全匹配示例规则。- 第三步(可选):配置表触发器自动赋值,插入数据时不需要业务层传入编码字段
-- 示例:给PRODUCT表的PRODUCT_CODE字段自动生成编码 CREATE OR REPLACE TRIGGER TRG_PRODUCT_CODE BEFORE INSERT ON PRODUCT FOR EACH ROW BEGIN :NEW.PRODUCT_CODE := NUM_TO_PRODUCT_CODE(SEQ_PRODUCT_CODE.NEXTVAL); END; /
不推荐用“先查当前最大编码、转数值加1再转码”的方案,并发插入时会出现重复编码,除非手动加悲观锁,性能和稳定性都不如原生序列。
2. Spring Boot后端实现
如果不想把转码逻辑放在数据库,后端也可以自行实现,核心是保证取递增数值的原子性。
- 第一步:编写编码转换工具类
public class ProductCodeUtil { // 固定3位编码,后续要扩长度直接改这个值就行,逻辑兼容 private static final int CODE_LENGTH = 3; private static final int BASE = 26; private static final char START_CHAR = 'A'; // 数值转3位产品编码 public static String numToCode(long num) { StringBuilder sb = new StringBuilder(); long remain = num; for (int i = 0; i < CODE_LENGTH; i++) { int bit = (int) (remain % BASE); sb.append((char)(START_CHAR + bit)); remain = remain / BASE; } // 拼接时从最低位开始,需要反转得到最高位在前的正确编码 return sb.reverse().toString(); } // 编码转数值,用于校验、排查问题场景 public static long codeToNum(String code) { if (code == null || code.length() != CODE_LENGTH) { throw new IllegalArgumentException("产品编码必须为3位大写字母"); } long num = 0; for (char c : code.toCharArray()) { num = num * BASE + (c - START_CHAR); } return num; } }
- 第二步:插入数据时直接取Oracle序列的nextval值,调用
numToCode方法转成编码即可,不要自己查最大编码计算。MyBatis、JPA都支持直接取序列值,原子性由Oracle保证,多实例部署也不会出现重号。
3. Angular前端实现
前端不要做任何编码生成逻辑:
- 新增产品表单里的产品编码字段设为只读/禁用状态,不允许用户手动修改
- 提交新增请求后,直接拿后端返回的、入库后的真实编码展示即可,不要在前端本地计算下一个编码,避免和后端实际值不一致
- 如果需要给用户展示编码规则,可以做静态示例,不要对接业务逻辑。
边界说明
3位大写字母一共支持26*26*26=17576个唯一编码,如果后续产品量超过这个值,只需要修改编码长度常量(数据库函数对应加位、Java工具类改CODE_LENGTH值),进位逻辑完全兼容,比如4位长度初始值为AAAA,ZZZ后会自动进位为ABAA。
内容的提问来源于stack exchange,提问作者Majed Abdullah
相关产品推荐
相关产品推荐

