??DAO(Data Access Object)是用于訪問數(shù)據(jù)的對象,雖然在大多數(shù)情況下將數(shù)據(jù)保存在數(shù)據(jù)庫中,但這并不是唯一的選擇,也可以將數(shù)據(jù)存儲到文件中或LDAP中。DAO不但屏蔽了數(shù)據(jù)的最終介質(zhì)的不同,也屏蔽了具體的實現(xiàn)技術(shù)的不同。
??早期,JDBC是訪問數(shù)據(jù)庫的主流選擇。近幾年,隨這個數(shù)據(jù)持久化技術(shù)獲得了長足的發(fā)展,Hibernate、Mybatis等技術(shù)成為持久層框架的更好選擇。
Spring統(tǒng)一數(shù)據(jù)訪問模板
??到一個餐館用餐,大抵會經(jīng)歷這樣一個流程:進入餐館→服務人員問候并領(lǐng)到合適位置→拿起菜單點菜→用餐→買單→離開餐館。之所以我們喜歡時不時到餐館用餐,就是因為我們只要點菜→用餐→買單就可以了,其他工作我們不關(guān)心,餐館完成即可。
??在直接使用具體的持久化技術(shù)時,大多需要處理整個流程,程序員并沒有享受到“餐館用餐”般的好體驗。Spring為支持持久化技術(shù)分別提供了模板訪問的方式,降低了使用各種持久化技術(shù)的難度,因此可大幅度地提高開發(fā)效率。
使用模板和回調(diào)機制
??我們來看一下傳統(tǒng)的JDBC連接方式:
Class.forName("JDBC驅(qū)動類的名稱");
Connection con = null;
PreparedStatement stmt = null;
try{
//1.獲取資源
con= DriverManager.getConnection(數(shù)據(jù)庫連接字符串,數(shù)據(jù)庫用戶名,密碼);
//2.啟動事務
con.setAutoCommit(false);
//3.具體業(yè)務邏輯
stmt=con.prepareStatement("插入數(shù)據(jù)");
//4.提交事務
con.commit();
} catch(Exception e){
try{
//5.回滾事務
con.rollback();
} catch...
...
//6.關(guān)閉資源
stmt.close();
con.close();
??如上述代碼所示,JDBC數(shù)據(jù)訪問數(shù)據(jù)操作按一下流程進行:(1)準備資源(2)啟動事務(3)在事務中執(zhí)行具體的數(shù)據(jù)訪問操作(4)提交/回滾事務(5)關(guān)閉資源,處理異常。
??按照傳統(tǒng)的方式,在編寫任何帶事務的數(shù)據(jù)訪問程序時,都需要重復編寫上面的代碼,而其中只有具體業(yè)務邏輯和業(yè)務相關(guān),其他代碼都是重復的。
??Spring將這個相同的數(shù)據(jù)訪問流程固化到模板中,并將數(shù)據(jù)訪問中固定和變化的部分分開,同時保證模板類是線程安全的,以便多個數(shù)據(jù)訪問線程共享同一個模板實例。固定的部分在模板類中已經(jīng)準備好,而變化的部分通過回調(diào)接口開放處理,用于定義具體數(shù)據(jù)訪問和結(jié)果返回的操作,如下圖:

??這樣,只要編寫好回調(diào)接口,并調(diào)用模板類進行數(shù)據(jù)訪問,就能得到預期的結(jié)果:數(shù)據(jù)訪問成功執(zhí)行,前置和后置的樣板化工作也按順序正確執(zhí)行,在提高開發(fā)效率的同時也保證了資源使用的正確性,徹底消除了因忘記資源釋放而引起的資源泄露問題。
Spring為不同持久化技術(shù)提供模板
??Spring為各種支持的持久化技術(shù)都提供了建行操作的模板和回調(diào),在回調(diào)中編寫具體的數(shù)據(jù)操作邏輯,使用模板執(zhí)行數(shù)據(jù)操作,這是Spring中典型的數(shù)據(jù)操作模式。我們會介紹其中幾個。

數(shù)據(jù)源
??不管使用何種持久化技術(shù),都必須擁有數(shù)據(jù)連接。在Spring中,數(shù)據(jù)連接是通過數(shù)據(jù)源獲得的。在以往的應用中,數(shù)據(jù)源一般是由Web應用服務器提供的。在Spring中,不但可以通過JNDI獲取應用服務器的數(shù)據(jù)源,也可以直接在Spring容器中配置數(shù)據(jù)源,此外,還可以通過代碼的方式創(chuàng)建一個數(shù)據(jù)源。
配置一個數(shù)據(jù)源
??Spring在第三方依賴包中包含了兩個數(shù)據(jù)源的實現(xiàn)類包:DBCP和C3P0。這個應該里都用過,我們可以在Spring文件中利用二者中的任何一個配置數(shù)據(jù)源。使用前請加入依賴包。
1.DBCP數(shù)據(jù)源
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://localhost:3306/test"
p:username="root"
p:password="123456"
/>
</beans>
2.C3P0數(shù)據(jù)源
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"
p:driverClass="com.mysql.jdbc.Driver"
p:jdbcUrl="jdbc:mysql://localhost:3306/test"
p:user="root"
p:password="123456"
/>
??當然,它們的屬性不僅僅于此,還有什么最大連接數(shù),空閑時間之類等,此處不做介紹,具體環(huán)境具體應用。
3.JNDI數(shù)據(jù)源(了解)
4.Spring的數(shù)據(jù)源實現(xiàn)類(了解)
使用屬性文件
??數(shù)據(jù)源的配置信息有可能經(jīng)常需要改動,同時可能被其他工程復用。此外,用戶名、密碼等信息比較敏感,可能需要加密措施。所以一般將數(shù)據(jù)源的配置信息獨立到一個屬性文件中,通過<context:property-placeholder>引入屬性文件,以${xxx}的方式引用屬性即可,代碼如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
//引入WEB-INF目錄下的文件
<context:property-placeholder location="WEB-INF/db.properties"/>
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close"
p:driverClassName="${jdbc.driverClass}"
p:url="${jdbc.url}"
p:username="${jdbc.username}"
p:password="${jdbc.password}"
/>
</beans>
??在WEB-INF目錄下創(chuàng)建的db.properties文件:
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=123
??此處,屬性文件的內(nèi)容是以明文方式存放的,也可進行加密,此處不介紹。
Spring的JDBC訪問數(shù)據(jù)庫(了解即可)
??前面說過傳統(tǒng)的JDBC方式的缺點,Spring通過目標和回調(diào)機制大大降低了使用JDBC的復雜度,借由JdbcTemplate的幫助,僅需要編寫那些“必不可少”的代碼就可以進行數(shù)據(jù)庫操作,而將資源獲取、Statement創(chuàng)建、資源釋放及異常處理等繁雜且乏味的工作交給Spring JDBC。
什么是JdbcTemplate?
??JdbcTemplate類是Spring框架數(shù)據(jù)抽象層的基礎(chǔ),它是Spring JDBC的核心類,繼承結(jié)構(gòu)如下:

??從
JdbcTemplate繼承關(guān)系圖可以看出,JdbcTemplate的直接父類是JdbcAccessor,該類為子類提供了一些訪問數(shù)據(jù)庫時的公用屬性。
-
DataSource:其主要功能是獲取數(shù)據(jù)庫的連接,還可以引入對數(shù)據(jù)庫連接的緩存池和分布式事務的支持,它可以作為訪問數(shù)據(jù)庫資源的標準接口。 -
SQLExceptionTranslator:該接口負責對SQLException進行轉(zhuǎn)譯工作。通過必要的設(shè)置獲取SQLExceptionTranslator的方法,可以使JdbcTemplate在需要處理SQLException時,委托給SQLExceptionTranslator的實現(xiàn)類來完成相關(guān)的轉(zhuǎn)譯工作。
??而JdbcOperations接口定義了在JdbcTemplate類中可以使用的操作集合,包括添加、修改、查詢和刪除等操作。
使用JdbcTemplate
??幾乎可以使用JdbcTemplate完成任何數(shù)據(jù)訪問操作,并充分享受它帶來的簡潔。它的使用方式有兩種:
1.代碼方式實現(xiàn)(了解即可)
//創(chuàng)建數(shù)據(jù)源并設(shè)置相關(guān)信息
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("");
ds.setUrl("");
ds.setUsername("");
ds.setPassword("");
JdbcTemplate jtp = new JdbcTemplate();
//設(shè)置數(shù)據(jù)源
jtp.setDataSource(ds);
String sql = "create table user(user_id int ,username varchar(50))";
jtp.insert(sql);
2.配置文件使用(常用)
??當然,我們一般都是在配置文件中配置,直接在DAO中注入即可:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--掃描相應包注冊以注解方式聲明的Bean-->
<context:component-scan base-package="cn"/>
<!--1.定義數(shù)據(jù)源-->
<context:property-placeholder location="WEB-INF/db.properties"/>
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close"
p:driverClassName="${jdbc.driverClass}"
p:url="${jdbc.url}"
p:username="${jdbc.username}"
p:password="${jdbc.password}"
/>
<!--2.聲明JdbcTemplate,并引用相應數(shù)據(jù)源-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
p:dataSource-ref="dataSource"/>
</beans>
然后在DAO中注入即可:
@Repository
public class UserDao{
private JdbcTemplate jdbcTemplate;
@Autowired
public void setJdbcTemplate(JdbcTemplate jdbcTemplate){
this.jdbcTemplate = jdbcTemplate;
}
public void saveUser(){
String sql ="sql語句";
jdbcTemplate.execute(sql);
}
}
jdbcTemplate的數(shù)據(jù)庫操作方法
??數(shù)據(jù)庫的增、刪、查、改及存儲過程調(diào)用是最常見的數(shù)據(jù)庫操作,jdbcTemplate提供了眾多方法完成這些數(shù)據(jù)操作。
-
execute:用于執(zhí)行sql語句。 -
update::用于執(zhí)行插入、更新和刪除操作。 -
query:用于執(zhí)行數(shù)據(jù)查詢操作。
??不詳細介紹了,因為我們一般都用Mybatis框架來代替Spring自帶的JDBC。
參考資料
《精通Spring 4.x 企業(yè)應用開發(fā)》