如何通過try-catch判斷數(shù)據(jù)庫唯一鍵字段是否重復(fù)
在 MyBatis + MySQL 項(xiàng)目里,完全可以通過 try-catch 捕獲數(shù)據(jù)庫拋出的唯一約束異常 來判斷是否重復(fù),從而避免提前多一次 SELECT 查詢。
1、原理
- MySQL 在插入數(shù)據(jù)時,如果違反唯一索引約束(Duplicate entry),會拋出 SQL 異常。
- 通過 MyBatis 調(diào)用時,這個異常會被包裝成 Java 異常(比如 org.springframework.dao.DuplicateKeyException,如果你用了 Spring;或者原生的 java.sql.SQLIntegrityConstraintViolationException)。
- 你可以在代碼里直接捕獲并處理。
示例代碼
假設(shè)用了spring+MyBaits:
try {
myMapper.insert(clue);
} catch (DuplicateKeyException e) {
// 這里捕獲到 clue_id 唯一索引沖突
log.warn("clue_id 已存在: {}", clue.getClueId());
// 業(yè)務(wù)邏輯:例如更新已有數(shù)據(jù),或者提示用戶
}如果沒用 Spring,只是原生 MyBatis,可以捕獲更底層的 SQL 異常:
try {
myMapper.insert(clue);
} catch (SQLIntegrityConstraintViolationException e) {
if (e.getErrorCode() == 1062) { // 1062 是 MySQL 的 Duplicate entry 錯誤碼
log.warn("clue_id 已存在: {}", clue.getClueId());
// 業(yè)務(wù)處理
} else {
throw e; // 不是唯一約束異常就繼續(xù)拋出
}
}? 優(yōu)點(diǎn)
- 避免額外的 SELECT 查詢,減少一次數(shù)據(jù)庫交互。
- 并發(fā)場景下比 先查再插入 更安全(避免查詢和插入之間的 race condition)。
?? 缺點(diǎn)
- 異常走的是數(shù)據(jù)庫錯誤路徑,開銷比普通邏輯分支稍高(但大多數(shù)業(yè)務(wù)場景下可以接受)。
- 如果異常拋出很頻繁,可能會影響性能,最好在業(yè)務(wù)設(shè)計上減少重復(fù)的可能。
2、怎么理解“異常走的是數(shù)據(jù)庫錯誤路徑,開銷比普通邏輯分支稍高”?
1. 普通邏輯分支 vs 異常機(jī)制
在 Java 里,正常的邏輯判斷(比如 if 判斷)和 異常處理機(jī)制(try-catch)的開銷是不一樣的。
- 普通邏輯分支:JVM 在執(zhí)行 if 判斷時,基本就是一次條件判斷+跳轉(zhuǎn),開銷很小。
- 異常機(jī)制:Java 的 throw 并不是普通返回,它會觸發(fā):
- 所以 throw 本身在 JVM 層面就比 if 要重很多。
- 創(chuàng)建異常對象(有可能包含堆??煺?stack trace)。
- 異常從當(dāng)前方法拋出,逐層回溯,直到找到匹配的 catch。
- 如果有 stack trace 打印,還會涉及額外的字符串拼接、I/O。
2. 數(shù)據(jù)庫層面
當(dāng) MySQL 插入違反唯一約束時,它并不是“返回 false”,而是:
- 先檢測唯一索引沖突。
- 如果沖突,則構(gòu)造錯誤碼(1062)、錯誤信息(Duplicate entry …)。
- 通過驅(qū)動(JDBC)拋到 Java。
這意味著你觸發(fā)了數(shù)據(jù)庫錯誤路徑,數(shù)據(jù)庫和 JDBC 驅(qū)動要多做一些額外的處理。
3. 結(jié)合起來的理解
所以我說的“異常走的是數(shù)據(jù)庫錯誤路徑,開銷比普通邏輯分支稍高”,意思是:
- 如果你在業(yè)務(wù)邏輯中 頻繁依賴拋異常來做流程控制(比如大量數(shù)據(jù)都重復(fù),幾乎每次插入都報 Duplicate),那開銷會比較大:
- JVM 異常開銷高于普通分支。
- 數(shù)據(jù)庫錯誤處理開銷高于正常 SQL 執(zhí)行。
- 但如果你的場景是 大部分?jǐn)?shù)據(jù)不會重復(fù),偶爾才會碰到 DuplicateKeyException,那完全可以用 try-catch,因?yàn)檎B窂阶叩倪€是普通 SQL 成功返回,異常的開銷只在極少數(shù)情況下才體現(xiàn)。
到此這篇關(guān)于如何通過try-catch判斷數(shù)據(jù)庫唯一鍵字段是否重復(fù)的文章就介紹到這了,更多相關(guān)try-catch判斷數(shù)據(jù)庫字段是否重復(fù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中的do while循環(huán)控制語句基本使用
這篇文章主要介紹了Java中的do while循環(huán)控制語句基本使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-01-01
Java?Thread.currentThread().getName()?和?this.getName()區(qū)別詳
本文主要介紹了Thread.currentThread().getName()?和?this.getName()區(qū)別詳解,TestThread?testThread?=?new?TestThread();2022-02-02
如何自定義hibernate validation注解示例代碼
Hibernate Validator 是 Bean Validation 的參考實(shí)現(xiàn) . Hibernate Validator 提供了 JSR 303 規(guī)范中所有內(nèi)置 constraint 的實(shí)現(xiàn),下面這篇文章主要給大家介紹了關(guān)于如何自定義hibernate validation注解的相關(guān)資料,需要的朋友可以參考下2018-04-04
SpringBoot如何使用Scala進(jìn)行開發(fā)的實(shí)現(xiàn)
這篇文章主要介紹了SpringBoot如何使用Scala進(jìn)行開發(fā)的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12
SpringMVC的處理器攔截器HandlerInterceptor詳解
這篇文章主要介紹了SpringMVC的處理器攔截器HandlerInterceptor詳解,SpringWebMVC的處理器攔截器,類似于Servlet開發(fā)中的過濾器Filter,用于處理器進(jìn)行預(yù)處理和后處理,需要的朋友可以參考下2024-01-01
SpringBoot3各種配置的優(yōu)先級對比小結(jié)
SpringBoot3提供了多種配置來源以滿足不同場景下的需求,本文詳細(xì)介紹了SpringBoot3中的配置優(yōu)先級對比小結(jié),具有一定的參考價值,感興趣的可以了解一下2024-12-12

