Spring JDBC-Spring對(duì)DAO的支持

      網(wǎng)友投稿 716 2025-04-01

      概述

      Spring的DAO理念

      統(tǒng)一的異常體系

      統(tǒng)一的數(shù)據(jù)訪問模板

      使用模板和回調(diào)機(jī)制

      模板類

      數(shù)據(jù)源

      配置數(shù)據(jù)源

      DBCP數(shù)據(jù)源

      C3P0數(shù)據(jù)源

      獲取JNDI數(shù)據(jù)源

      Spring的數(shù)據(jù)源實(shí)現(xiàn)類

      總結(jié)

      概述

      Spring對(duì)多個(gè)持久化技術(shù)提供了集成支持,包括Hibernate、MyBatis、JPA、JDO。 此外Spring還提供了一個(gè)簡(jiǎn)化JDBC API操作的Spring JDBC框架。

      Spring面向DAO制定了一個(gè)通用的異常體系,屏蔽了持久化技術(shù)的異常,使業(yè)務(wù)層和具體的持久化技術(shù)實(shí)現(xiàn)解耦。

      另外,Spring提供了模板類簡(jiǎn)化各種持久化技術(shù)的使用。

      通用的異常體系和模板類是Spring整合各種持久化技術(shù)的不二法門。

      Spring的DAO理念

      DAO(DATA Acces Object)是用于訪問數(shù)據(jù)的對(duì)象,雖然大多數(shù)情況下存儲(chǔ)在數(shù)據(jù)庫(kù)中,但是也可以存放在文件或者LDAP(輕量目錄訪問協(xié)議,Lightweight Directory Access Protocol)中。 DAO不但屏蔽了數(shù)據(jù)存儲(chǔ)最重介質(zhì)的不同,也屏蔽了具體的實(shí)現(xiàn)技術(shù)的不同。

      早起,JDBC是主流選擇,近些年,數(shù)據(jù)庫(kù)持久化技術(shù)得到了長(zhǎng)足的發(fā)展。 只要為數(shù)據(jù)訪問定義好DAO接口,并使用具體的實(shí)現(xiàn)技術(shù)實(shí)現(xiàn)DAO接口的功能,就可以在不同的實(shí)現(xiàn)技術(shù)之間平滑的切換。

      我們來舉個(gè)例子 : 如下是一個(gè)典型的DAO應(yīng)用實(shí)例,在USerDAO中定義訪問User數(shù)據(jù)對(duì)象的接口方法,業(yè)務(wù)層通過UserDao操作數(shù)據(jù),并使用具體的持久化技術(shù)實(shí)現(xiàn)USerDao接口方法,這樣就實(shí)現(xiàn)了業(yè)務(wù)層和具體的持久化技術(shù)之間的解耦

      提供DAO抽象層的好處:

      首先可以很容易的構(gòu)造模擬對(duì)象,方便單元測(cè)試的開展

      其次在使用切面會(huì)有更多的選擇,可以使用JDK動(dòng)態(tài)代理,又可以使用CGLib動(dòng)態(tài)代理

      Spring本質(zhì)上希望以統(tǒng)一的方式整合底層的持久化技術(shù),即以統(tǒng)一的方式進(jìn)行調(diào)用及事務(wù)管理,避免讓具體的實(shí)現(xiàn)侵入到業(yè)務(wù)層的代碼中。 由于每種持久化技術(shù)都有各自的異常體系,所以Spring提供了統(tǒng)一的異常體系,使不同異常體系的阻抗得以消弭,方便定義出和具體實(shí)現(xiàn)技術(shù)無關(guān)的DAO接口,以及整合到相同的事務(wù)管理體系中。

      統(tǒng)一的異常體系

      統(tǒng)一的異常體系是整合不同的持久化技術(shù)的關(guān)鍵。 Spring提供了一套和實(shí)現(xiàn)技術(shù)無關(guān)的、面向DAO層語(yǔ)義的異常體系,并通過轉(zhuǎn)換器將不同持久化技術(shù)的異常轉(zhuǎn)換成Spring的異常

      很多正統(tǒng)API或者框架中,檢查型異常被過多的使用,以致在使用API時(shí),代碼中充斥了大量的try/cath樣板式的代碼。這樣就導(dǎo)致一堆異常處理的代碼喧賓奪主侵入到業(yè)務(wù)代碼中,破壞了代碼的整潔和優(yōu)雅。

      Spring在org.springframework.dao包中提供了一套完備優(yōu)雅的DAO異常體系,

      這些異常都繼承于DataAccessException , 而DataAccessException本身又繼承于NestedRuntimeException, NestedRuntimeException異常以嵌套的方式封裝了源異常。 因此,雖然不同的持久化技術(shù)的特定異常被轉(zhuǎn)換到Spring的DAO異常體系中,但原始的異常信息并不會(huì)丟失,我們依然可以通過getCaucse()方法獲取原始的異常信息。

      JDBC/Mybatis的異常轉(zhuǎn)換器為SQLErrorCodeSQLExceptionTranslator

      Spring以分類手法建立了異常分類目錄 ,如下所示(為第一層次的異常類,每個(gè)異常類下都可能有眾多子異常類),一方面可以使開發(fā)者從底層細(xì)如針麻的技術(shù)細(xì)節(jié)中脫離出來,另一方面可以選擇感興趣的異常加以處理。

      統(tǒng)一的數(shù)據(jù)訪問模板

      Spring為支持持久化技術(shù)分別提供了模板訪問的方式,降低了使用各種持久化技術(shù)的難度,因此可以大幅度的提供開發(fā)效率。

      使用模板和回調(diào)機(jī)制

      我們先看一段使用JDBC進(jìn)行數(shù)據(jù)操作的簡(jiǎn)單代碼,已經(jīng)盡可能的簡(jiǎn)化了整個(gè)處理的過程

      public void saveUser(User user) { Connection connection = null; PreparedStatement stmt = null; try { // 獲取連接 connection = DriverManager.getConnection(url, user, password); // 啟動(dòng)事物 connection.setAutoCommit(false); // 業(yè)務(wù)操作 stmt = connection .prepareStatement("insert into user(id ,name) values(?,?)"); stmt.setLong(1, user.getUserId()); stmt.setString(2, user.getUserName()); // 執(zhí)行提交 stmt.execute(); // 提交事務(wù) connection.commit(); } catch (Exception e) { // 回滾 connection.rollback(); } finally { // 釋放資源 stmt.close(); connection.close(); } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      如上代碼所述,JDBC訪問數(shù)據(jù)按照如下流程

      獲取連接

      開啟事務(wù)(如果有需要)

      執(zhí)行具體的數(shù)據(jù)訪問操作

      提交/回滾事務(wù)

      關(guān)閉資源

      我們可以看到只有具體的業(yè)務(wù)操作才是我們關(guān)心的, Spring將這些相同的數(shù)據(jù)訪問流程固化到模板中,并將數(shù)據(jù)訪問中固定和變化的部分分開,同時(shí)保證模板類是線程安全的,以便多個(gè)數(shù)據(jù)訪問線程共享同一個(gè)模板實(shí)例。變化的部分通過回調(diào)接口開放出來,用于定義數(shù)據(jù)訪問和結(jié)果返回的操作。 (如下圖)

      這樣我們只需要編寫回調(diào)接口,并調(diào)用模板類進(jìn)行數(shù)據(jù)訪問,就可以得到我們期待的結(jié)果:數(shù)據(jù)訪問成功執(zhí)行,前置和后置的樣板化工作也按照順序正確執(zhí)行,在提供開發(fā)效率的同時(shí)保證了資源使用的正確性,徹底消除了因?yàn)橥涍M(jìn)行資源釋放而引起的資源泄漏問題。

      模板類

      Spring為各種支持的持久化技術(shù)都提供了簡(jiǎn)化操作的模板和回調(diào),在回調(diào)中編寫具體的數(shù)據(jù)操作邏輯,使用模板執(zhí)行數(shù)據(jù)操作,在Spring中這是典型的數(shù)據(jù)操作模式。

      我們來了解下Spring為不同的持久化技術(shù)所提供的模板類

      如果直接使用模板類,則演需要在DAP中定義一個(gè)模板對(duì)象并提供數(shù)據(jù)資源。 Spring為每種持久化技術(shù)都提供了支持列,支持類中已完成了這樣的功能。 這樣我們只需要擴(kuò)展這些支持類,就可以直接編寫實(shí)際的數(shù)據(jù)訪問邏輯,因此更加方便。

      這些類都是繼承于dao.support.DaoSupport類, DaoSupport實(shí)現(xiàn)了InitializingBean接口,在afterPropertiesSet()接口中檢查模板對(duì)象和數(shù)據(jù)源是否被正確設(shè)置,否則將拋出異常。

      所有的支持類都是abstract,其目的是希望被繼承使用,而非直接使用

      數(shù)據(jù)源

      在Spring中,不但可以通過JNDI獲取應(yīng)用服務(wù)器的數(shù)據(jù)源,也可以在Spring容器中配置數(shù)據(jù)源。 此外還可以通過代碼的方式創(chuàng)建一個(gè)數(shù)據(jù)源,以便進(jìn)行無容器依賴的單元測(cè)試

      配置數(shù)據(jù)源

      Spring在第三方依賴包中包含了2個(gè)數(shù)據(jù)源的實(shí)現(xiàn)類包

      Apache的DBCP

      C2P0

      我們可以在Spring配置文件中利用二者中的任何一個(gè)配置數(shù)據(jù)源。

      DBCP數(shù)據(jù)源

      因篇幅原因,另開一篇 Apache-DBCP數(shù)據(jù)庫(kù)連接池解讀

      簡(jiǎn)略配置如下:

      1

      2

      3

      4

      5

      6

      BasicDataSource提供了close()方法關(guān)閉數(shù)據(jù)源,所以必須設(shè)定destroy-method=”close”屬性,以便Spring容器關(guān)閉時(shí),數(shù)據(jù)源能夠正常關(guān)閉。

      假設(shè)數(shù)據(jù)庫(kù)為MySQL,如果配置不當(dāng),會(huì)發(fā)生經(jīng)典的“8小時(shí)為” 。

      原因是MySQL在默認(rèn)情況下發(fā)現(xiàn)一個(gè)連接空閑時(shí)間超過8小時(shí),則會(huì)在數(shù)據(jù)庫(kù)端自動(dòng)關(guān)閉這個(gè)連接。 而數(shù)據(jù)源并不知道這個(gè)連接已經(jīng)被數(shù)據(jù)庫(kù)關(guān)閉了,當(dāng)它將這個(gè)無用的連接返回個(gè)某個(gè)DAO時(shí),DAO就會(huì)拋出無法獲取Connection的異常。

      如果采用DBCP默認(rèn)配置,由于testOnBorrow默認(rèn)為true,數(shù)據(jù)源在將連接交給DAO之前,會(huì)事先檢查這個(gè)連接是否良好,如果連接有問題(在數(shù)據(jù)庫(kù)端被關(guān)閉),則回取一個(gè)其他的連接給DAP,并不會(huì)有“8小時(shí)問題”。 但是這樣每次都檢查有效性,在高并發(fā)的應(yīng)用中會(huì)帶來性能問題。

      一種推薦的高效方式是: 將testOnBorrow設(shè)置為false,而將testWhielIdel設(shè)置為true,再設(shè)置好 timeBetweenEvictionRunsMillis的值。 這樣DBCP將通過一個(gè)后臺(tái)線程定時(shí)的對(duì)空閑連接進(jìn)行檢測(cè),當(dāng)發(fā)現(xiàn)無用的空閑連接(那些被數(shù)據(jù)庫(kù)關(guān)閉的連接)時(shí),就會(huì)將它們清掉,只要將timeBetweenEvictionRunsMillis設(shè)置為小于8小時(shí),那些被MySQL關(guān)閉的空閑連接就可以被清除出去,從而避免“8小時(shí)問題”

      當(dāng)然,MySQL本身可以通過調(diào)整interactive-timeout(以秒為單位)配置參數(shù),更改空閑連接的過期時(shí)間, 所以在設(shè)置timeBetweenEvictionRunsMillis值時(shí),必須首先獲知MySQL空閑連接的最大過期時(shí)間。

      C3P0數(shù)據(jù)源

      因篇幅原因,另開一篇 C3P0-數(shù)據(jù)庫(kù)連接池解讀

      一個(gè)簡(jiǎn)單的配置

      oracle.jdbc.driver.OracleDriver jdbc:oracle:thin:@ip:port:instanceName artisan artisan

      1

      2

      3

      4

      5

      6

      7

      8

      9

      Spring JDBC-Spring對(duì)DAO的支持

      10

      11

      12

      13

      14

      獲取JNDI數(shù)據(jù)源

      Java Naming and Directory Interface (Java命名和目錄服務(wù)接口)

      如果應(yīng)用配置在高性能的應(yīng)用服務(wù)器比如weblogic/websphere等,則可能希望使用應(yīng)用本身提供的數(shù)據(jù)源。 應(yīng)用服務(wù)器的數(shù)據(jù)源使用JNDI開放調(diào)用者使用,Spring為此專門提供了引用JNDI數(shù)據(jù)源的JndiObjectFactoryBean,我們來看一個(gè)簡(jiǎn)單的配置

      1

      2

      3

      通過jndiName指定引用的JNDI數(shù)據(jù)源名稱

      Spring為JavaEE資源提供了一個(gè)jee命名空間,通過jee命名空間,可以有效的簡(jiǎn)化Java EE資源的引用, 如下所示:

      1

      2

      3

      4

      5

      6

      7

      8

      9

      Spring的數(shù)據(jù)源實(shí)現(xiàn)類

      Spring本身也提供了一個(gè)簡(jiǎn)單的數(shù)據(jù)源實(shí)現(xiàn)類org.springframework.jdbc.datasource.DriverManagerDataSource

      這個(gè)類實(shí)現(xiàn)了javax.sql.DataSource接口, 但 它并沒有提供池化連接的機(jī)制,每次調(diào)用getConnection()獲取新連接時(shí),只是簡(jiǎn)單地創(chuàng)建一個(gè)新的連接。

      因此,這個(gè)數(shù)據(jù)源類比較適合在單元測(cè)試 或簡(jiǎn)單的獨(dú)立應(yīng)用中使用,因?yàn)樗恍枰~外的依賴類。

      下面,我們來看一下DriverManagerDataSource的簡(jiǎn)單使用。

      DriverManagerDataSource ds = new DriverManagerDataSource (); ds.setDriverClassName("com.mysql.jdbc.Driver"); ds.setUrl("jdbc:mysql://localhost:3309/sampledb"); ds.setUsername("artisan"); ds.setPassword("123456"); Connection actualCon = ds.getConnection();

      1

      2

      3

      4

      5

      6

      當(dāng)然,我們也可以通過配置的方式直接使用DriverManagerDataSource。 如下

      1

      2

      3

      4

      5

      6

      7

      8

      總結(jié)

      不管采用何種持久化技術(shù),都需要定義數(shù)據(jù)源。Spring附帶了兩個(gè)數(shù)據(jù)源的實(shí)現(xiàn)類包,你可以自行選擇進(jìn)行定義。 在實(shí)際部署時(shí),我們可能會(huì)直接采用應(yīng)用服 務(wù)器本身提供的數(shù)據(jù)源, 這時(shí),則可以通過JndiObjectFactoryBean或jee命名空間引用JNDI中的數(shù)據(jù)源

      JDBC Spring

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:企業(yè)安全生產(chǎn)管理檔案(企業(yè)安全生產(chǎn)管理檔案代做)
      下一篇:改變游戲規(guī)則,進(jìn)入櫥柜訂單管理系統(tǒng)的嶄新時(shí)代
      相關(guān)文章
      亚洲第一页日韩专区| 亚洲人成77777在线观看网| 亚洲中文字幕无码久久2020 | 亚洲综合无码一区二区| 亚洲中文字幕久久精品无码喷水| 亚洲不卡AV影片在线播放| 亚洲AV无码成人精品区大在线| 久久久久久亚洲精品无码| 亚洲成av人片天堂网无码】| 亚洲欧美日韩综合久久久久 | 亚洲一级大黄大色毛片| 亚洲人成综合在线播放| 亚洲va在线va天堂va手机| 亚洲一区欧洲一区| 亚洲人成77777在线播放网站不卡 亚洲人成77777在线观看网 | 国产亚洲人成无码网在线观看 | 亚洲色无码专区在线观看| 亚洲综合国产一区二区三区| 亚洲色大成网站www永久一区| 亚洲中文久久精品无码ww16| 亚洲男同帅GAY片在线观看| 亚洲国产精品无码一线岛国| 久久亚洲成a人片| 91久久亚洲国产成人精品性色 | 亚洲一级片在线播放| 亚洲中文字幕一二三四区| 亚洲AV永久无码精品网站在线观看 | 高清在线亚洲精品国产二区| mm1313亚洲精品国产| 国产a v无码专区亚洲av| 亚洲精品无码av天堂| 亚洲精品无码久久千人斩| 亚洲AV无码乱码国产麻豆| 亚洲视频在线观看网址| 亚洲中文字幕久在线| 亚洲精品精华液一区二区| 亚洲国产精品13p| 亚洲AV无码一区二区乱孑伦AS| 911精品国产亚洲日本美国韩国| 亚洲国产日韩在线| 亚洲αⅴ无码乱码在线观看性色|