本篇是《Spring3.X企業應用開發實戰》,陳雄華 林開雄著,電子工業出版社,2012.2出版”的學習筆記的第二篇,關于DAO和事務。
本篇從DAO操作,以及事務處理的基本知識談起,介紹事務本身,以及Spring如何通過注解實現事務。
# DAO
近幾年持久化技術領域異常喧囂,各種框架如雨后春筍般地冒出,Sun也連接不斷的頒布了幾個持久化規范。
Spring對多個持久化技術提供了持久化支持,包括Hibernate,iBatis,JDO,JPA,TopLink,另外,還通過Spring JDBC框架對JDBC API進行簡化。
Spring面向DAO制定了一個通用的異常體系,屏蔽具體持久化技術的異常,使業務層和具體的持久化技術達到解耦。
此外,Spring提供了模板類簡化各種持久化技術的使用。
通用的異常體系及模板類是Spring整合各種五花八門持久化技術的不二法門,Spring不但借此實現了對多種持久化技術的整合,還可以不費吹灰之力整合潛在的各種持久化框架,體現了“開-閉原則”的經典應用。
Spring支持目前大多數常用的數據持久化技術,Spring定義了一套面向DAO層的異常體系,并為各種支持的持久化技術提供了異常轉換器。這里,我們在設計DAO接口時,就可以拋開具體的實現技術,定義統一的接口。
不管采用何種持久化技術,訪問數據的流程是相對固定的。Spring將數據訪問流程劃分為固定和變化兩部分,并以模板的方式定義好流程,用回調接口將變化的部分開放出來,留給開發者自行定義。這樣,我們僅需提供業務相關的邏輯就可以完成整體的數據訪問了。
### 4種配置數據源的辦法
1、DHCP數據源
org.apache.commons.dbcp.BasicDataSource,需要commons-dhcp.jar和commons-pool.jar
對于MySQL,如果數據源配置不當,將可能發生經典的“8小時問題”:
原因是MySQL在默認情況下,如果發現一個連接的空閑時間超過8小時,將會在數據庫端自動關閉這個連接。而數據源并不知道這個連接以及被數據庫關閉了,當它將這個無用的連接返回給某個DAO時,DAO就會報無法獲取Connection的異常。
如果采用DHCP的默認配置,由于testOnBorrow屬性的默認值為true,數據源將在連接交給DAO前,檢測這個鏈接是否是好的,如果連接有問題(在數據庫端被關閉),則會取一個其他的連接給DAO。所以,并不會有“8小時問題”。如果每次將連接交給DAO時都檢測連接有效性,在高并發的應用中將帶來性能的問題,因為它會需要更多的數據庫訪問請求。
一種推薦的高效方式是:將testOnBorrow設置為false,而將testWhileIdle設置為true,再設置好timeBetweenEvictionRunsMillis值。這樣,DBCP將通過一個后臺線程定時對空閑連接進行檢測,當發現無用的連接時,就會將他們清除掉。只要這個值小于8小時,就可以避免“8小時問題”。
當然, MySQL本身可以通過調整interactive-timeout(以秒為單位)配置參數,更改空閑連接的過期時間。所以,設置這個timeBetweenEvictionRunsMillis值時,必須首先獲知MySQL空閑連接的最大過期時間。
**8小時問題的其他參考:**[http://blog.csdn.net/wangfayinn/article/details/24623575](http://blog.csdn.net/wangfayinn/article/details/24623575)
2.C3P0數據源,它在lib目錄中與Hibernate一起發布。
很多生產項目使用這個數據源的連接池,推薦。
3、Spring的數據源實現類
org.springframework.jdbc.datasource.DriverManagerDataSource
這個數據源是沒有連接池的,比較適合單元測試或簡單的獨立應用使用
4、使用應用服務器的JNDI數據源
org.springframework.jndi.JndiObjectFactoryBean
一般是在開發過程中使用Spring的數據源實現類就可以了,有公司也在測試生產環境中使用JNDI數據源。
不過這種方式,會對容器做一些改動,不是一種最好的方式,個人推薦C3P0。?
### 一個JBOSS的JNDI數據源文件例子
一個JBOSS的JNDI數據源文件mysql-ds.xml,需要拷貝至{jboss_home}/server/{default}/deploy/,內容如下:
~~~
<?xml version="1.0" encoding="UTF-8"?>
<!-- See http://www.jboss.org/community/wiki/Multiple1PC for information about local-tx-datasource -->
<!-- $Id: mysql-ds.xml 88948 2009-05-15 14:09:08Z jesper.pedersen $ -->
<!-- Datasource config for MySQL using 3.0.9 available from:
http://www.mysql.com/downloads/api-jdbc-stable.html
-->
<datasources>
<local-tx-datasource>
<jndi-name>MySqlDSSlave1</jndi-name>
<connection-url>jdbc:mysql://ip:3306/dbname?useUnicode=true&characterEncoding=utf-8</connection-url>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<user-name>root</user-name>
<password>root</password>
<exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>
<min-pool-size>5</min-pool-size>
<max-pool-size>150</max-pool-size>
<!-- should only be used on drivers after 3.22.1 with "ping" support-->
<valid-connection-checker-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLValidConnectionChecker</valid-connection-checker-class-name>
<!-- sql to call when connection is created
<new-connection-sql>some arbitrary sql</new-connection-sql>
-->
<!-- sql to call on an existing pooled connection when it is obtained from pool - MySQLValidConnectionChecker is preferred for newer drivers-->
<check-valid-connection-sql>select 1</check-valid-connection-sql>
<!-- corresponding type-mapping in the standardjbosscmp-jdbc.xml (optional) -->
<metadata>
<type-mapping>mySQL</type-mapping>
</metadata>
</local-tx-datasource>
<no-tx-datasource>
<jndi-name>MySqlDS_JDBC</jndi-name>
<connection-url>jdbc:mysql://ip:3306/dbname?useUnicode=true&characterEncoding=utf-8</connection-url>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<user-name>root</user-name>
<password>root</password>
<exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>
<min-pool-size>5</min-pool-size>
<max-pool-size>150</max-pool-size>
<!-- should only be used on drivers after 3.22.1 with "ping" support-->
<valid-connection-checker-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLValidConnectionChecker</valid-connection-checker-class-name>
<!-- sql to call when connection is created
<new-connection-sql>some arbitrary sql</new-connection-sql>
-->
<!-- sql to call on an existing pooled connection when it is obtained from pool - MySQLValidConnectionChecker is preferred for newer drivers-->
<check-valid-connection-sql>select 1</check-valid-connection-sql>
<!-- corresponding type-mapping in the standardjbosscmp-jdbc.xml (optional) -->
<metadata>
<type-mapping>mySQL</type-mapping>
</metadata>
</no-tx-datasource>
</datasources>
~~~
### Spring Data
Spring有一個比較活躍的子項目,名為SpringData,這個項目的目標主要是讓訪問No-SQL更加方便,并支持map-reduce框架和云計算的數據服務。
第二個目標就是支持基于關系型數據庫的數據服務,如Oracle RAC。對于擁有海量數據的項目,可以用SpringData這樣的項目來簡化項目的開發,SpringData會讓數據的訪問變得更加方便。SpringData由多個子項目組成,支持CouchDB、MongoDB、Neo4J、Hadoop、Hbase、Cassandra等,有興趣的讀者可以關注:http://www.springsource.com/spring-data。
# 事務
### 何為數據庫事務
數據庫事務有嚴格的定義,它必須同時滿足4個特性:原子性(Atomic)、一致性(Consistency)、隔離性(Isolation)和持久性(Durabiliy),簡稱為ACID。
原子性:表示組成一個事務的多個數據庫操作是一個不可分割的原子單元,只有所有的操作執行成功,整個事務才提交,事務中任何一個數據庫操作失敗,已經執行的任何操作都必須撤銷,讓數據庫返回到初始狀態。
一致性:事務操作成功后,數據庫所處的狀態和它的業務規則是一致的,即數據不會被破壞。如從A賬戶轉賬100元到B賬戶,不管操作成功與否,A和B的存款總額是不變的。
隔離性:在并發數據操作時,不同的事務擁有各自的數據空間,他們的操作不會對對方產生干擾。準確地說,并非要求做到完全無干擾,數據庫規定了各種事務隔離級別,不同隔離級別對應不同的干擾程度,隔離級別越高,數據一致性越好,但并發性越弱。
持久性:一旦數據提交成功后,事務中所有的數據操作都必須被持久化到數據庫中,即時提交事務后,數據庫馬上崩潰,在數據庫重啟時,也必須能保證能夠通過某種機制恢復數據。
數據庫管理系統一般采用重執行日志保證原子性、一致性和持久性,重執行日志記錄了數據庫變化的每一個動作,數據庫在一個事務中執行一部分操作后發生錯誤退出,數據即可以根據重執行日志撤銷已經執行的操作。此外,對于已經提交的事務,即使數據庫崩潰,在重啟數據庫時也能夠根據日志對尚未持久化的數據進行相應的重執行操作。
和Java程序采用對象鎖機制進行線程同步類似,數據庫管理系統采用數據庫鎖機制保證事務的隔離性。當多個事務試圖對相同的數據進行操作時,只有持有鎖的事務才能操作數據,直到前一個事務完成后,后面的事務才有機會對數據執行操作。
### 數據并發問題
一個數據庫擁有多個訪問客戶端,這些客戶端都可以并發方式訪問數據庫。
數據庫中相同數據可能同時被多個事務訪問,如果沒有采取必要的隔離措施,就會導致各種并發問題,破壞數據的完整性。
這些問題可以歸結為5類,包括3類數據讀問題(臟讀、不可重復讀、幻象讀)以及2類數據更新問題(第一類丟失更新和第二類丟失更新)。
<table border="1" width="100%" cellspacing="1" cellpadding="1"><tbody><tr><td>類型</td><td>描述</td><td>場景</td><td>解決</td></tr><tr><td>臟讀(dirty read)</td><td>A事務讀取B事務商務未提交的更改數據,并在這個數據的基礎上操作</td><td>事務1:張三給李四匯款100元,記錄日志(假設10秒)<br/>事務2:此時李四查詢,發現到賬<br/>事務1:記錄日志出錯,回滾,錢退給張三<br/><br/>結果:導致李四錯誤的認為收到款項</td><td>把事務隔離級別調整到READ COMMITTED</td></tr><tr><td>不可重復讀(unrepeatable read)</td><td>是指A事務讀取了B事務已經提交的更改數據,導致A事務對于同一個數據的多次讀取,結果是不一樣的。<br/><br/>一個事務先后讀取同一條記錄,但兩次讀取的數據不同,我們稱之為不可重復讀。</td><td>事務1:張三先后兩次查詢某一賬號的余額<br/>事務2:在兩次查詢期間,李四完成了銀行轉賬<br/><br/>結果:導致兩次的查詢結果不同</td><td>把事務隔離級別調整到REPEATABLE READ</td></tr><tr><td>幻象讀(phantom read)</td><td>A事務讀取B事務提交的新增數據,一般發生在計算統計數據的事務中。<br/><br/>一個事務先后讀取一個范圍的記錄,但兩次讀取的紀錄數不同,我們稱之為幻象讀。</td><td>事務1:張三先后兩次查詢所有賬號的余額<br/>事務2:在兩次查詢期間,李四給張三新開一個賬號,并存入100元<br/><br/>結果:導致兩次查詢的結果不同</td><td>把事務隔離級別調整到SERIALIZABLE</td></tr></tbody></table>
參考:[http://www.cnblogs.com/Sun_Blue_Sky/articles/2139996.html](http://www.cnblogs.com/Sun_Blue_Sky/articles/2139996.html)
不可重復讀和幻象讀,前者是指讀到了已經提交事務的更改數據,后者是指讀到了其他已經提交的事務的新增數據,為了避免這兩種情況,采取的多策是不同的,對于前者,需要鎖行,對于后者,需要鎖表。
第一類丟失更新:A事務撤銷時,把已經提交的B事務的更新覆蓋了。
第二類丟失跟新:A事務提交時,把已經提交的B事務的更新覆蓋了。
### 數據隔離級別
| 隔離級別 | 臟讀 | 不可重復讀 | 幻象讀 | 第一類丟失更新 | 第二類丟失更新 |
|-----|-----|-----|-----|-----|-----|
| READ UNCOMMITED | 允許 | 允許 | 允許 | 不允許 | 允許 |
| READ COMMITED | 不允許 | 允許 | 允許 | 不允許 | 允許 |
| REPEATABLE READ | 不允許 | 不允許 | 允許 | 不允許 | 不允許 |
| SERIALIZABLE | 不允許 | 不允許 | 不允許 | 不允許 | 不允許 |
SqlServer2008R2的默認隔離級別是“READ COMMITED”,MySQL的默認隔離級別是“REPEATABLE READ”。
### Spring 事務
Spring聲明式事務是Spring最核心、最常用的功能。
由于Spring通過IOC和AOP的功能非常透明地實現了聲明式事務的功能,一般的開發者基本上無須了解Spring聲明式事務的內部細節,僅需要懂得如何配置就可以了。
但是在實際應用開發過程中,Spring的這種透明地高階封裝在帶來便利的同時,也給我們帶來了困惑。
就像通過流言傳播的消息,最終聽眾已經不清楚事情的真相了,而這對于應用開發開說是很危險的。
剖析實際應用中給開發者造成困惑的各種觀點,通過分析Spring事務管理的內部運作機制將真相還原出來,真相如下:
在沒有事務管理的情況下,DAO照樣可以順利進行數據操作;
將應用分出Web、Service及DAO層只是一種參考的開發模式,并非是事務管理工作的前提條件;
Spring通過事務傳播機制可以很好地應對事務方法嵌套調用的情況,開發者無需為了事務管理而可以改變服務方法的設計;
由于單實例的對象不存在線程安全問題,所以經過事務管理增強的單實例Bean可以很好地工作在多線程環境下;
混合使用多個數據訪問技術框架的最佳組合是一個ORM技術框架(如Hibernate或JPA等)+一個JDBC技術框架(如Spring JDBC或iBatis)。直接使用ORM技術框架對應的事務管理器就可以了,但必須考慮ORM緩存同步的問題。
Spring AOP增強有兩個方案:其一為基于接口的動態代理,其二為基于CGLib動態生成子類的代理。由于Java語法的特性,有些特殊方法不能被Spring AOP代理,所以也就無法享受AOP織入帶來的事務增強;
使用Spring JDBC時如果直接獲取Connection,可能會造成連接泄露。為降低連接泄露的可能性,盡量使用DataSourceUtils獲取數據連接。也可以對數據源進行代理,以便使數據源具有感知事務上下文的能力。
我們描述了Spring JDBC防止連接泄露的解決方案,Spring同樣把這種解決方案平滑應用到其他的數據訪問技術框架中。
### DataSourceUtils
Spring提供了一個能從當前事務上下文中獲取綁定的數據連接的工具類,那就是DataSourceUtils。
Spring強調必須使用DataSourceUtils工具類獲取數據連接,Spring的JdbcTemplate內部也是通過DataSourceUtils來獲取連接的。
是否使用DataSourceUtils獲取數據連接就可以高枕無憂了呢?理想很美好,但現實很殘酷:如果DataSourceUtils在沒有事務上下文的方法中使用getConnection()獲取連接,依然會造成數據連接泄露!
而通過分析JdbcTemplate模板的實現,發現JdbcTemplate嚴謹的獲取連接及釋放連接的模式化流程保證了JdbcTemplate對數據連接泄露問題的免疫性。
所以,如果有可能,請盡量使用JdbcTemplate、HibernateTemplate等這些模板進行數據訪問操作,避免直接獲取數據連接的操作。
如果不得已要顯式獲取數據連接,除了使用DataSourceUtils獲取事務上下文綁定的連接之外,還可以通過TransactionAwareDataSourceProxy對數據源進行代理。數據源對象被代理后就具有了事務上下文的感知的能力。
### 不同持久化技術對應的事務管理器實現類
| org.springframework.orm.jpa.JpaTransactionManager | 使用JPA進行持久化時,使用該事務管理器 |
|-----|-----|
| org.springframework.orm.hibernate3.HibernateTransactionManager | 使用Hibernate3.0版本進行持久化時,使用該事務管理器 |
| org.springframework.jdbc.datasource.DataSourceTransactionManager | 使用Spring JDBC或iBatis等基于DataSource數據源的持久化技術時,使用該事務管理器 |
| org.springframework.orm.jdo.JdoTransactionManager | 使用JDO進行持久化時,使用該事務管理器 |
| org.springframework.transaction.jta.JtaTransactionManager | 具有多個數據源的全局事務使用該事務管理器(不管采用何種持久化技術),如果希望在Java EE容器里使用JTA,我們將通過JNDI和Spring的JtaTransactionManager獲取一個容器管理的DataSource。 |
大致來說,Spring支持兩類事務,一種是本地連接事務(使用DataSourceTransactionManager),一種是JTA事務(使用JtaTransactionManager)。
JTA事務實現相對較好理解,在執行實際類的符合模式的方法時,代理類通過在連接點前后插入預處理過程(開始事務)和后處理過程(commit或rollbak)即可。因為JTA事務支持兩階段提交所以在代碼中啟動多少個連接(不同的connection)都能保證事務最終提交或者回滾。
作為基于DataSource的事務管理,實際上數據庫連接Connection是最為核心的資源,事務的管理控制最終都會由Connection的相關方法來完成。關于其實現原理,不做深入探究。
### 事務傳播行為類型
| PROPAGATION_REQUIRED | 如果當前沒有事務,就新建一個事務,如果已經存在一個事務,加入到這個事務中。這是最常見的選擇。 |
|-----|-----|
| PROPAGATION_SUPPORTS | 支持當前事務,如果當前沒有事務,就以非事務方式執行。 |
| PROPAGATION_MANDATORY | 使用當前的事務,如果當前沒有事務,就拋出異常。 |
| PROPAGATION_REQUIRES_NEW | 新建事務,如果當前存在事務,把當前事務掛起。 |
| PROPAGATION_NOT_SUPPORTED | 以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。 |
| PROPAGATION_NEVER | 以非事務方式執行,如果當前存在事務,則拋出異常。 |
| PROPAGATION_NESTED | 如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則執行與PROPAGATION_REQUIRED類似的操作。 |
### ApplicationContext.xml里面配置示例
~~~
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
~~~
以上是用@Transactional注解方式需要的配置節點,如果不用@Transactional注解方式配置事務,也可以用XML表達式配置事務,如下:
~~~
<aop:config expose-proxy="true">
<!-- 只對業務邏輯層實施事務 -->
<aop:pointcut id="txPointcut" expression="execution(* com.yougou.pc.api.service..*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="del*" propagation="REQUIRED"/>
<tx:method name="xx*" propagation="REQUIRED"/>
<tx:method name="put*" read-only="true"/>
<tx:method name="query*" read-only="true"/>
<tx:method name="use*" read-only="true"/>
<tx:method name="get*" read-only="true"/>
<tx:method name="xx*" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
~~~
~~~
<!--iBatis的事務配置-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSourcejdbc"/>
</bean>
~~~
~~~
<!--JTA的事務配置-->
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
</bean>
~~~
~~~
<!-- 強烈建議用JdbcTemplate代替JdbcUtils -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSourcejdbc" />
</bean>
~~~
### 使用注解配置聲明式事務:@Transactional
使用基于@Transactional注解的配置和基于XML的配置方式一樣,它擁有一組普適性很強的默認事務屬性,我們往往可以直接使用這些默認的屬性就可以了,默認值如下:
| 事務傳播行為 | PROPAGATION_REQUIRED |
|-----|-----|
| 事務隔離級別 | SOLATION_DEFAULT,表示采用數據庫本身的隔離級別 |
| 讀寫事務屬性 | 讀寫事務 |
| 超時時間 | 依賴于底層的事務系統的默認值 |
| 回滾設置 | 任何運行期異常引發回滾(unchecked),任何檢查型異常不會引發回滾 |
?**@Transactional注解屬性說明:**
****
| propagation | 事務傳播行為,通過以下枚舉類提供合法值:org.springframework.transaction.annotation.Propagation,例如:@Transactional(propagation=Propagation.REQUIRES_NEW) |
|-----|-----|
| isolation | 事務隔離級別,通過以下枚舉類提供合法值:org.springframework.transaction.annotation.Isolation,例如:@Transactional(isolation=Isolation.READ_COMMITTED) |
| readOnly | 事務讀寫性,boolean型,例如:@Transactional(readOnly=true) |
| timeout | 超時時間,int型,例如:@Transactional(timeout=10) |
| rollbackFor | 一組異常類,遇到時進行回滾,類型為:Class<? Extends Throwable>[],默認為{}。例如:@Transactional(rollbackFor={SQLException.class}),多個異常之間可用逗號分隔。 |
| rollbackForClassName | 一組異常類名,遇到時進行回滾,類型為String[],默認值為{}。例如:@Transactional(rollbackForClassName={Exception"}) |
| noRollbackFor | 和rollbackFor相對。 |
| noRollbackForClassName | 和rollbackForClassName相對。 |
@Transactional注解可以被應用于接口定義和接口方法、類定義和類的public方法上。
Spring建議在具體業務類上使用@Transactional注解。
方法處的注解會覆蓋類定義處的注解,可以使用不同的事務管理器,例如:@Transactional("forum"),使用名為forum的事務管理器,需要在bean里面增加節點<qualifier value="forum"/>,如果不指定“限定符”,將默認使用“transationManager”命名對應的事務管理器。
指示spring事務管理器回滾一個事務的方法是在當前事務的上下文內拋出異常。spring事務管理器會捕捉任何未處理的異常,然后依據規則決定是否回滾拋出異常的事務。
默認配置下,spring只有在拋出的異常為運行時unchecked異常時才回滾該事務,也就是拋出的異常為RuntimeException的子類(Errors也會導致事務回滾),而拋出checked異常則不會導致事務回滾。
可以明確的配置在拋出哪些異常時回滾事務,包括checked異常。也可以明確定義那些異常拋出時不回滾事務。
如果在@Transactional標記指定的方法里面,使用catch把異常吃掉了,那么這個事務是不會回滾的。
對應Spring+MyBatis事務,必須保證applicationContext.xml配置文件里面,transactionManger和Mybatis的數據源是一致的,如果不一致,則@Transactional注解的方法是沒有事務的;可以用Corba作為數據源,是可以保證事務正常執行的,這個架構組做過測試。
### 演示一個老式的編程式事務管理,也感覺一下注解方式的優越:)
~~~
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = txManager.getTransaction(def);
try {
b.setBrandName("test");
brandMapper.upddateBrand(b);
b.setBrandName("..."); //設置名字超長,讓報錯
brandMapper.upddateBrand(b);
}
catch (Exception ex) {
txManager.rollback(status);
}
txManager.commit(status)
~~~
# 不同數據源下MyBatis配置數據源的辦法
<!-- 會自動將basePackage中配置的包路徑下的所有帶有@Mapper標注的接口生成代理類,實現數據訪問 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 多個數據源,這是mybatis-spring 1.2.0 的配置辦法 -->
<!-- <property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryXX" /> -->
<!-- 多個數據源,這是mybatis-spring 1.0.2 的配置辦法 -->
<property name="sqlSessionFactory" ref="sqlSessionFactoryXX" />
<property name="sqlSessionTemplate" ref="sqlSessionTemplateXX"/>
<property name="basePackage" value="com/xx/xx" />
</bean>
- 前言
- Java之旅--如何從草根成為技術專家
- 《深入理解Java虛擬機》學習筆記
- 《Spring3.X企業應用開發實戰》學習筆記--IoC和AOP
- 《Tomcat權威指南》第二版學習筆記
- Java之旅--多線程進階
- Java之旅--Web.xml解析
- 《Spring3.X企業應用開發實戰》學習筆記--DAO和事務
- 《Spring3.X企業應用開發實戰》學習筆記--SpringMVC
- Java之旅--定時任務(Timer、Quartz、Spring、LinuxCron)
- Spring實用功能--Profile、WebService、緩存、消息、ORM
- JDK框架簡析--java.lang包中的基礎類庫、基礎數據類型
- JDK框架簡析--java.util包中的工具類庫
- JDK框架簡析--java.io包中的輸入輸出類庫
- Java之旅--通訊
- Java之旅--XML/JSON
- Java之旅--Linux&amp;java進階(看清操作系統層面的事)
- Java之旅--硬件和Java并發(神之本源)
- Java之旅--設計模式
- jetty