Spring Boot中如何通过触发器基于上条记录值手动生成唯一编码
Spring Boot 自定义递增唯一编码实现方案
你需要的A+3位自增数字格式的编码生成,有两种主流实现方式,可根据你的业务要求选择:
方案一:应用层实现(推荐,适配Spring Boot生态,灵活可控)
核心逻辑
插入数据前,先查询目标表最新的subject_code,拆分前缀和数字段,数字自增后补零拼接为新编码,插入时携带该值即可。
实现步骤
- 第一步:编写编码生成工具方法
/** * 生成业务编码 * @param latestCode 数据库查询到的最新编码,无历史数据时传null * @param prefix 编码固定前缀,示例中为"A" * @return 按规则生成的新编码 */ public String generateBizCode(String latestCode, String prefix) { // 无历史数据时返回初始值 if (latestCode == null) { return prefix + "001"; } // 提取数字段自增 int serialNum = Integer.parseInt(latestCode.substring(prefix.length())); serialNum++; // 补3位零后拼接返回 return prefix + String.format("%03d", serialNum); }
- 第二步:新增数据前查询最新编码,调用工具方法生成新值
注意:必须加事务+行锁避免并发场景下重复编码,查询最大编码时加
FOR UPDATE行锁,防止多个请求同时拿到相同的最大编码导致重复
Mapper层查询代码示例(MyBatis):
<select id="getLatestSubjectCode" resultType="java.lang.String"> SELECT MAX(subject_code) FROM your_table_name FOR UPDATE </select>
Service层代码示例:
@Transactional(rollbackFor = Exception.class) public void addSubject(Subject subject) { // 查询最新编码 String latestCode = subjectMapper.getLatestSubjectCode(); // 生成新编码 String newCode = generateBizCode(latestCode, "A"); subject.setSubjectCode(newCode); // 执行插入 subjectMapper.insert(subject); }
- 可选优化:如果用MyBatis-Plus/JPA框架,可以绑定插入前置拦截器/
@PrePersist注解,实现自动填充编码,无需每次手动调用生成方法。
方案二:数据库触发器实现(如果要求必须用触发器实现可选)
直接在数据库层创建前置插入触发器,每次插入数据时自动生成编码赋值,无需修改应用代码。
MySQL触发器示例:
DELIMITER // CREATE TRIGGER trg_generate_subject_code BEFORE INSERT ON your_table_name FOR EACH ROW BEGIN DECLARE max_code VARCHAR(10); DECLARE next_serial INT; -- 查询当前最大编码 SELECT MAX(subject_code) INTO max_code FROM your_table_name; IF max_code IS NULL THEN -- 无历史数据时设置初始值 SET NEW.subject_code = 'A001'; ELSE -- 提取数字段自增后补零拼接 SET next_serial = CAST(SUBSTRING(max_code, 2) AS UNSIGNED) + 1; SET NEW.subject_code = CONCAT('A', LPAD(next_serial, 3, '0')); END IF; END // DELIMITER ;
该方案缺点是调试难度高、跨数据库兼容性差,修改编码规则需要修改触发器,不支持多编码前缀的复杂场景。
高并发场景优化
如果业务插入并发量较高,可以改用Redis生成自增序号,避免数据库行锁带来的性能损耗,性能比数据库锁方案高10倍以上。
内容的提问来源于stack exchange,提问作者Learner
相关产品推荐
相关产品推荐

