說說 Spring DAO 的異常體系

Spring 提供了一套和實(shí)現(xiàn)技術(shù)無關(guān)的 、 面向 DAO 層語義級(jí)別的異常體系柒凉,內(nèi)部通過轉(zhuǎn)換器將不同持久化技術(shù)的異常轉(zhuǎn)換成 Spring 的異常钳宪,實(shí)現(xiàn)統(tǒng)一管理。

1 異常體系

很多正統(tǒng)的 AP中寨辩,使用了過多的檢查型異常,以致于在使用 API 時(shí)歼冰,代碼中充斥了大量 try/catch 樣板式的代碼 靡狞。 大多數(shù)情況下,這些 catch 代碼段除了記錄日志外停巷,并沒有做多少其它有益的工作耍攘。

比如 JDK 中的 JDBC API榕栏,大家都說不好用,因?yàn)闄z查型異常泛濫蕾各,許多異常處理代碼喧賓奪主地侵入到業(yè)務(wù)代碼中扒磁,從而破壞了整體代碼的整潔與優(yōu)雅 。

Spring 在 org.springframework.dao 中提供了一套優(yōu)雅的 DAO 異常體系式曲, 這些異常都繼承自 DataAccessException妨托, DataAccessException 繼承自NestedRuntimeException, NestedRuntimeException 異常以嵌套的方式封裝了源異常 。 因此吝羞,雖然不同的持久化技術(shù)的特定異常被轉(zhuǎn)換到 Spring 的 DAO 異常體系中兰伤,但我們可以通過 getCause() 方法獲取原始異常信息 。

這套異常體系從 DAO 的抽象層次上定義了異常目錄樹钧排,它使得開發(fā)者可以很容易地關(guān)注某個(gè)特定的語義異常敦腔。而 JDBC 的 SQLException 過于底層,而且與具體數(shù)據(jù)庫強(qiáng)相關(guān)(比如 getErrorCode())恨溜,不僅不好編碼符衔,而且很難移植。

Spring 建立了異常分類目錄糟袁,以適當(dāng)?shù)念w粒度劃分了異常類型判族。這樣做的好處是:

  • 開發(fā)者可以從底層繁瑣復(fù)雜的技術(shù)細(xì)節(jié)中解脫出來。
  • 開發(fā)者可以選擇自己感興趣的異常進(jìn)行處理 项戴。

DataAccessException 下有這些異常子類:

異常子類 說明
CleanupFailureDataAccessException 執(zhí)行 DAO 操作成功形帮,但在釋放數(shù)據(jù)資源時(shí)發(fā)生異常,如關(guān)閉 Connection 時(shí)發(fā)生異常周叮。
ConcurrencyFailureException 并發(fā)地操作數(shù)據(jù)時(shí)發(fā)生異常辩撑,如無法獲取樂觀鎖或悲觀鎖時(shí)、死鎖引發(fā)的失敗等場景则吟。
DataAccessResourceFailureException 訪問數(shù)據(jù)資源失敗槐臀,如無法獲取數(shù)據(jù)連接锄蹂,無法獲取 Hibernate 的會(huì)話等場景氓仲。
DataRetrievalFailureException 獲取數(shù)據(jù)失敗,如找不到對(duì)應(yīng)主鍵的數(shù)據(jù)或使用了錯(cuò)誤的列索引等場景得糜。
DataSourceLookupFailureException 無法從 JNDI 中查找到數(shù)據(jù)源敬扛。
DataIntegrityViolationException 數(shù)據(jù)操作違反了數(shù)據(jù)一致性限制時(shí)拋出,如插入重復(fù)的主鍵或引用不存在的外鍵場景朝抖。
InvalidDataAccessApiUsageException 不正確地調(diào)用某一種持久化技術(shù)時(shí)拋出啥箭,如在 Spring JDBC 中查詢對(duì)象在調(diào)用前沒有事先進(jìn)行編譯操作,就會(huì)拋出該異常治宣。這種異常主要是因?yàn)椴徽_地使用持久化技術(shù)而產(chǎn)生的急侥。
InvalidDataAccessResourceUsageException 在訪問數(shù)據(jù)源時(shí)使用了不正確的方法時(shí)拋出砌滞,如寫錯(cuò) SQL 語句。
PermissionDeniedDataAccessException 數(shù)據(jù)訪問權(quán)限不足時(shí)拋出坏怪。如僅擁有只讀權(quán)限卻試圖更改數(shù)據(jù)贝润。
UncategorizedDataAccessException 其它未被分類的異常。

Spring 為了進(jìn)一步細(xì)化錯(cuò)誤問題域铝宵, 它對(duì)上述的這些一級(jí)異常類又進(jìn)行了細(xì)分打掘。

這套異常體系具有高度的可擴(kuò)展性,當(dāng) Spring 需要對(duì)一個(gè)新的持久化技術(shù)提供支持時(shí)鹏秋,只要為其定義一個(gè)對(duì)應(yīng)的子異常即可尊蚁,這種方式實(shí)現(xiàn)了設(shè)計(jì)模式中的“開閉原則” 。

開閉原則( OCP )是面向?qū)ο笤O(shè)計(jì)中 “ 可復(fù)用設(shè)計(jì) ” 的基石侣夷,是面向?qū)ο笤O(shè)計(jì)中最重要的原則之一横朋,其它很多的設(shè)計(jì)原則都是實(shí)現(xiàn)開閉原則的一種手段 。 對(duì)于擴(kuò)展是開放的百拓,對(duì)于修改是關(guān)閉的叶撒,這意味著模塊的行為是可以擴(kuò)展的 。 當(dāng)應(yīng)用的需求改變時(shí)耐版,我們可以對(duì)模塊進(jìn)行擴(kuò)展祠够,使其具有滿足那些改變的新行為 。

2 異常轉(zhuǎn)換器

2.1 JDBC

一般情況下粪牲,JDBC API 在執(zhí)行數(shù)據(jù)操作出現(xiàn)異常時(shí)古瓤,大都會(huì)拋出 SQLException ,SQLException 把異常的細(xì)節(jié)封裝在異常屬性中腺阳,所以如果希望了解異常的具體原因落君,我們必須對(duì)異常屬性進(jìn)行分析。

SQLException 擁有兩個(gè)代表異常具體原因的屬性:

屬性 類型 說明
錯(cuò)誤碼 int 與具體數(shù)據(jù)庫相關(guān)亭引,調(diào)用 getErrorCode() 返回绎速。
SQL 狀態(tài)碼 String 標(biāo)準(zhǔn)錯(cuò)誤代碼,由 5 個(gè)字符組成,調(diào)用 getSQLState() 返回焙蚓。

Spring 會(huì)根據(jù)錯(cuò)誤碼和 SQL 狀態(tài)碼將 SQLExeption 轉(zhuǎn)換為對(duì)應(yīng)的 Spring DAO 異常 纹冤。 在 org.springframework.jdbc.support 包中定義了 SQLExceptionTranslator 接口,該接口的兩個(gè)實(shí)現(xiàn)類 SQLErrorCodeSQLExceptionTranslator 和 `SQLStateSQLExceptionTranslator
分別負(fù)責(zé)處理 SQLException 中錯(cuò)誤代碼和 SQL 狀態(tài)碼的轉(zhuǎn)換工作 购公。

2.2 其它 ORM 持久化技術(shù)

其它 ORM 持久化技術(shù)都擁有一個(gè)語義明確的異常體系萌京,所以轉(zhuǎn)換相對(duì)簡單。

注意:Spring4 只支持 Hibernate3.6+宏浩。

Spring 在 org.springframe.orm 中為所支持的 ORM 技術(shù)定義了相應(yīng)的子包知残。對(duì)應(yīng)的異常轉(zhuǎn)換器也定義在這些子包中:

ORM 持久化技術(shù) 異常轉(zhuǎn)換器
HibernateX,X 可為 3比庄、4 或 5 org.springframework.orm.hibernateX.SessionFactoryUtils
JPA org.springframework.orm.jpa.EntityManagerFactoryUtils
JDO org.springframework.orm.jdo.PersistenceManagerFactoryUtils

這些工具類除了具有異常轉(zhuǎn)換的功能外求妹,在進(jìn)行事務(wù)管理時(shí)乏盐,還提供了從事務(wù)上下文環(huán)境中返回相同會(huì)話的功能 。

Spring 也支持 myBatis 持久化技術(shù)制恍,因?yàn)?myBatis 拋出的異常與 JDBC 相同丑勤, 都是 SQLException 異常,所以采用了和 JDBC 相同的異常轉(zhuǎn)換器 吧趣。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末法竞,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子强挫,更是在濱河造成了極大的恐慌岔霸,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件俯渤,死亡現(xiàn)場離奇詭異呆细,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)八匠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門絮爷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人梨树,你說我怎么就攤上這事坑夯。” “怎么了抡四?”我有些...
    開封第一講書人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵柜蜈,是天一觀的道長。 經(jīng)常有香客問我指巡,道長淑履,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任藻雪,我火速辦了婚禮秘噪,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘勉耀。我一直安慰自己指煎,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開白布瑰排。 她就那樣靜靜地躺著贯要,像睡著了一般暖侨。 火紅的嫁衣襯著肌膚如雪椭住。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評(píng)論 1 305
  • 那天字逗,我揣著相機(jī)與錄音京郑,去河邊找鬼宅广。 笑死,一個(gè)胖子當(dāng)著我的面吹牛些举,可吹牛的內(nèi)容都是我干的跟狱。 我是一名探鬼主播,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼户魏,長吁一口氣:“原來是場噩夢啊……” “哼驶臊!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起叼丑,我...
    開封第一講書人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤关翎,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后鸠信,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體纵寝,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年星立,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了爽茴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡绰垂,死狀恐怖室奏,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情劲装,我是刑警寧澤窍奋,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站酱畅,受9級(jí)特大地震影響琳袄,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜纺酸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一窖逗、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧餐蔬,春花似錦碎紊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至词爬,卻和暖如春秃嗜,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來泰國打工锅锨, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留叽赊,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓必搞,卻偏偏與公主長得像必指,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子恕洲,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容