在 mybatis + mysql 项目里,完全可以通过 try-catch 捕获数据库抛出的唯一约束异常 来判断是否重复,从而避免提前多一次 select 查询。
1、原理
- mysql 在插入数据时,如果违反唯一索引约束(duplicate entry),会抛出 sql 异常。
- 通过 mybatis 调用时,这个异常会被包装成 java 异常(比如 org.springframework.dao.duplicatekeyexception,如果你用了 spring;或者原生的 java.sql.sqlintegrityconstraintviolationexception)。
- 你可以在代码里直接捕获并处理。
示例代码
假设用了spring+mybaits:
try { mymapper.insert(clue); } catch (duplicatekeyexception e) { // 这里捕获到 clue_id 唯一索引冲突 log.warn("clue_id 已存在: {}", clue.getclueid()); // 业务逻辑:例如更新已有数据,或者提示用户 }
如果没用 spring,只是原生 mybatis,可以捕获更底层的 sql 异常:
try { mymapper.insert(clue); } catch (sqlintegrityconstraintviolationexception e) { if (e.geterrorcode() == 1062) { // 1062 是 mysql 的 duplicate entry 错误码 log.warn("clue_id 已存在: {}", clue.getclueid()); // 业务处理 } else { throw e; // 不是唯一约束异常就继续抛出 } }
✅ 优点
- 避免额外的 select 查询,减少一次数据库交互。
- 并发场景下比 先查再插入 更安全(避免查询和插入之间的 race condition)。
⚠️ 缺点
- 异常走的是数据库错误路径,开销比普通逻辑分支稍高(但大多数业务场景下可以接受)。
- 如果异常抛出很频繁,可能会影响性能,最好在业务设计上减少重复的可能。
2、怎么理解“异常走的是数据库错误路径,开销比普通逻辑分支稍高”?
1. 普通逻辑分支 vs 异常机制
在 java 里,正常的逻辑判断(比如 if 判断)和 异常处理机制(try-catch)的开销是不一样的。
- 普通逻辑分支:jvm 在执行 if 判断时,基本就是一次条件判断+跳转,开销很小。
- 异常机制:java 的 throw 并不是普通返回,它会触发:
- 所以 throw 本身在 jvm 层面就比 if 要重很多。
- 创建异常对象(有可能包含堆栈快照 stack trace)。
- 异常从当前方法抛出,逐层回溯,直到找到匹配的 catch。
- 如果有 stack trace 打印,还会涉及额外的字符串拼接、i/o。
2. 数据库层面
当 mysql 插入违反唯一约束时,它并不是“返回 false”,而是:
- 先检测唯一索引冲突。
- 如果冲突,则构造错误码(1062)、错误信息(duplicate entry …)。
- 通过驱动(jdbc)抛到 java。
这意味着你触发了数据库错误路径,数据库和 jdbc 驱动要多做一些额外的处理。
3. 结合起来的理解
所以我说的“异常走的是数据库错误路径,开销比普通逻辑分支稍高”,意思是:
- 如果你在业务逻辑中 频繁依赖抛异常来做流程控制(比如大量数据都重复,几乎每次插入都报 duplicate),那开销会比较大:
- jvm 异常开销高于普通分支。
- 数据库错误处理开销高于正常 sql 执行。
- 但如果你的场景是 大部分数据不会重复,偶尔才会碰到 duplicatekeyexception,那完全可以用 try-catch,因为正常路径走的还是普通 sql 成功返回,异常的开销只在极少数情况下才体现。
到此这篇关于如何通过try-catch判断数据库唯一键字段是否重复的文章就介绍到这了,更多相关try-catch判断数据库字段是否重复内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论