javascript
Spring JDBC-Spring对事务管理的支持
- 概述
- 事務(wù)管理關(guān)鍵抽象
- Spring事務(wù)管理的實(shí)現(xiàn)類
- Spring JDBC 和MybBatis的事務(wù)管理器的配置
- JPA的事務(wù)管理器的配置
- Hibernate的事務(wù)管理器的配置
- JTA 的事務(wù)管理器的配置
- 事務(wù)同步管理器
- 事務(wù)的傳播行為
- 示例
- 編程式的事務(wù)管理
- 示例
概述
Spring為事務(wù)管理提供了一致的編程模板,在高層次建立了統(tǒng)一的事務(wù)抽象。也就是說,不管選擇Spring JDBC、Hibernate 、JPA 還是iBatis,Spring都讓我們可以用統(tǒng)一的編程模型進(jìn)行事務(wù)管理。
類似Spring DAO 為不同的持久化技術(shù)實(shí)現(xiàn)提供了模板類一樣,Spring事務(wù)管理也提供了事務(wù)模板類TransactionTemplate。 通過TransactionTemplate并配合使用事務(wù)回調(diào)TransactionCallback指定具體的持久化操作,就可以 通過編程的方式實(shí)現(xiàn)事務(wù)管理,而無須關(guān)注資源獲取、復(fù)用、釋放、事務(wù)同步和異步處理等操作。
Spring事務(wù)管理的亮點(diǎn)在于聲明式事務(wù)管理,Spring允許通過聲明的方式,在IoC配置中指定事務(wù)的邊界和事務(wù)屬性,Spring會(huì)自動(dòng)在指定的事務(wù)邊界上應(yīng)用事務(wù)屬性。
事務(wù)管理關(guān)鍵抽象
在Spring事務(wù)管理SPI(Service Provider Interface)的抽象層主要包括3個(gè)接口,分別是PlatformTransactionManager、TransactionDefinition和TransactionStatus。 都在org.springframework.transaction包中。
TransactionDefinition用于描述事務(wù)的隔離級(jí)別、超時(shí)時(shí)間、是否為只讀事務(wù)和事務(wù)傳播規(guī)則等控制事務(wù)具體行為的事務(wù)屬性,這些事務(wù)屬性可以通過XML配置或注解描述提供,也可以通過手工編程的方式設(shè)置。
PlatformTransactionManager根據(jù)TransactionDefinition提供的事務(wù)屬性配置信息,創(chuàng)建事務(wù),并用TransactionStatus描述這個(gè)激活事務(wù)的狀態(tài)。
Spring事務(wù)管理的實(shí)現(xiàn)類
spring將事務(wù)管理委托底層具體的持久化實(shí)現(xiàn)框架去完成,因此針對(duì)不同的框架spring有的不同的接口實(shí)現(xiàn)類.
| org.springframework.orm.jpa.JpaTransactionManager | 使用JPA進(jìn)行持久化時(shí),使用該事務(wù)管理器 |
| org.springframework.orm.hibernateX.HibernateTransactionManager | 使用HibernateX版本時(shí)使用該事務(wù)管理器 |
| org.springframework.jdbc.datasource.DataSourceTransactionManager | 使用SpringJDBC或MyBatis等基于DataSource數(shù)據(jù)源的持久化技術(shù)時(shí),使用該事務(wù)管理器 |
| org.springframework.orm.jdo.JdoTransactionManager | 使用JDO進(jìn)行持久化時(shí),使用該事務(wù)管理器 |
| org.springframework.transaction.jta.JtaTransactionManager | 具有多個(gè)數(shù)據(jù)源的全局事務(wù)使用該事務(wù)管理器(不管采用何種持久化技術(shù)) |
要實(shí)現(xiàn)事務(wù)管理,首先要在Spring中配置好相應(yīng)的事務(wù)管理器,為事務(wù)管理器指定數(shù)據(jù)資源及一些其他事務(wù)管理控制屬性。
下面介紹一下幾個(gè)常見的事務(wù)管理器的配置
Spring JDBC 和MybBatis的事務(wù)管理器的配置
Spring JDBC 和MybBatis都是基于數(shù)據(jù)源的Connection訪問數(shù)據(jù)庫,所有都可以使用DataSourceTransactionManager, 配置如下
<!--引用外部的Properties文件--> <context:property-placeholder location="classpath:jdbc.properties"/><!--配置一個(gè)數(shù)據(jù)源--> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close"p:driverClassName="${jdbc.driverClassName}"p:url="${jdbc.url}"p:username="${jdbc.username}"p:password="${jdbc.password}"/><!--基于數(shù)據(jù)源的事務(wù)管理器,通過屬性引用數(shù)據(jù)源--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"p:dataSource-ref="dataSource"/>JPA的事務(wù)管理器的配置
要配置一個(gè)JPA事務(wù)管理器,必須現(xiàn)提供一個(gè)DataSource,然后配置一個(gè)EntityManagerFactory,最后才配置JpaTransationManager.
.......<!--通過dataSource-ref指定一個(gè)數(shù)據(jù)源--> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"p:dataSource-ref="dataSource"/>...... </bean><!--指定實(shí)體管理器--><bean id="transactionManger" class="org.springframework.orm.jpa.JpaTransactionManager"p:entityManagerFacotry-ref="entityManagerFactory"/>Hibernate的事務(wù)管理器的配置
Spring4.0已經(jīng)取消了對(duì)Hibernate3.6之前的版本支持,并全面支持Hibernate5.0. 因此,只為Hibernate3.6+提供事務(wù)管理器。
以Hibernate4.0為例
.... <!--通過dataSource-ref引用數(shù)據(jù)源 和 Hibernate配置文件 及其他屬性--> <bean id="sessionFactory"class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"p:dataSource-ref="dataSource"p:mappingResources="classpath:Artisan.hbm.xml"><property name="hibernateProperties"><props><prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop><prop key="hibernate.show_sql">true</prop><prop key="hibernate.generate_statistics">true</prop></props></property> </bean><bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"p:sessionFactory-ref="sessionFactory"/>JTA 的事務(wù)管理器的配置
如果希望在JavaEE容器中使用JTA,則將通過JNDI和Spring的JtaTransactionManager獲取一個(gè)容器的DataSource。
<!--通過jee命名空間獲取Java EE應(yīng)用服務(wù)器容器中的數(shù)據(jù)源--> <jee:jndi-lookup id="accountDs" jndi-name="java:comp/env/jdbc/account"/> <jee:jndi-lookup id="orderDs" jndi-name="java:comp/env/jdbc/account"/><!--指定JTA事務(wù)管理器。--> <bean id="transactionManager"class="org.springframework.transaction.jta.JtaTransactionManager"/>事務(wù)同步管理器
Spring將JDBC的Connection、Hibernate的Session等訪問數(shù)據(jù)庫的連接或者會(huì)話對(duì)象統(tǒng)稱為資源,這些資源在同一時(shí)刻是不能多線程共享的。
為了讓DAO、Service類可能做到singleton, Spring的事務(wù)同步管理類org.springframework.transaction.support.TransactionSynchronizationManager使用ThreadLocal為不同事務(wù)線程提供了獨(dú)立的資源副本,同時(shí)維護(hù)事務(wù)配置的屬性和運(yùn)行狀態(tài)信息。
事務(wù)同步管理器是Spring事務(wù)管理的基石,不管用戶使用的是編程式事務(wù)管理,還是聲明式事務(wù)管理,都離不開事務(wù)同步管理器。
Spring框架為不同的持久化技術(shù)提供了一套從TransactionSynchronizationManager中獲取對(duì)應(yīng)線程綁定資源的工具類
| Spring JDBC或者M(jìn)yBatis | org.springframework.jdbc.datasource.DataSourceUtils |
| HibernateX.0 | org.springframework.orm.hibernateC.SessionFactoryUtils |
| JPA | org.springframework.orm.jpa.EntityManagerFactoryUtils |
| JDO | org.springframework.orm.jdo.PersistenceManagerFactoryUtils |
這些工具類都提供了靜態(tài)的方法,通過這些方法可以獲取和當(dāng)前線程綁定的資源,如
DataSourceUtils.getConnection (DataSource
dataSource)可以從指定的數(shù)據(jù)源中獲取和當(dāng)前線程綁定的ConnectionHibernate的SessionFactoryUtils.getSession (SessionFactory
sessionFactory, boolean allowCreate)則從指定的SessionFactory中獲取和當(dāng)前線程綁定的Session。當(dāng)需要脫離模板類,手工操作底層持久技術(shù)的原生API時(shí),就需要通過這些工具類獲取線程綁定的資源,而不應(yīng)該直接從DataSource或SessionFactory中獲取。因?yàn)楹笳卟荒塬@得和本線程相關(guān)的資源,因此無法讓數(shù)據(jù)操作參與到本線程相關(guān)的事務(wù)環(huán)境中。
這些工具類還有另外一個(gè)重要的用途:將特定異常轉(zhuǎn)換為Spring的DAO異常。
Spring為不同的持久化技術(shù)提供了模板類,模板類在內(nèi)部通過資源獲取工具類間接訪問TransactionSynchronizationManager中的線程綁定資源。所以,如果Dao使用模板類進(jìn)行持久化操作,這些Dao就可以配置成singleton。如果不使用模板類,也可直接通過資源獲取工具類訪問線程相關(guān)的資源。
我們來開下TransactionSynchronizationManager的面紗:
TransactionSynchronizationManager將Dao、Service類中影響線程安全的所有“狀態(tài)”統(tǒng)一抽取到該類中,并用ThreadLocal進(jìn)行替換,從此Dao(必須基于模板類或資源獲取工具類創(chuàng)建的Dao)和Service(必須采用Spring事務(wù)管理機(jī)制)摘掉了非線程安全的帽子,完成了脫胎換骨式的身份轉(zhuǎn)變。
事務(wù)的傳播行為
當(dāng)我們調(diào)用一個(gè)基于Spring的Service接口方法(如UserService#addUser())時(shí),它將運(yùn)行于Spring管理的事務(wù) 環(huán)境中,Service接口方法可能會(huì)在內(nèi)部調(diào)用其它的Service接口方法以共同完成一個(gè)完整的業(yè)務(wù)操作,因此就會(huì)產(chǎn)生服務(wù)接口方法嵌套調(diào)用的情況, Spring通過事務(wù)傳播行為控制當(dāng)前的事務(wù)如何傳播到被嵌套調(diào)用的目標(biāo)服務(wù)接口方法中。
事務(wù)傳播是Spring進(jìn)行事務(wù)管理的重要概念,其重要性怎么強(qiáng)調(diào)都不為過。但是事務(wù)傳播行為也是被誤解最多的地方,在本文里,我們將詳細(xì)分析不同事務(wù)傳播行為的表現(xiàn)形式,掌握它們之間的區(qū)別。
Spring在TransactionDefinition接口中規(guī)定了7種類型的事務(wù)傳播行為,它們規(guī)定了事務(wù)方法和事務(wù)方法發(fā)生嵌套調(diào)用時(shí)事務(wù)如何進(jìn)行傳播:
| PROPAGATION_REQUIRED | 如果當(dāng)前沒有事務(wù),就新建一個(gè)事務(wù),如果已經(jīng)存在一個(gè)事務(wù)中,加入到這個(gè)事務(wù)中。這是最常見的選擇 |
| PROPAGATION_SUPPORTS | 支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就以非事務(wù)方式執(zhí)行。 |
| PROPAGATION_MANDATORY | 使用當(dāng)前的事務(wù),如果當(dāng)前沒有事務(wù),就拋出異常。 |
| PROPAGATION_REQUIRES_NEW | 新建事務(wù),如果當(dāng)前存在事務(wù),把當(dāng)前事務(wù)掛起 |
| PROPAGATION_NOT_SUPPORTED | 以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在事務(wù),就把當(dāng)前事務(wù)掛起 |
| PROPAGATION_NEVER | 以非事務(wù)方式執(zhí)行,如果當(dāng)前存在事務(wù),則拋出異常。 |
| PROPAGATION_NESTED | 如果當(dāng)前存在事務(wù),則在嵌套事務(wù)內(nèi)執(zhí)行。如果當(dāng)前沒有事務(wù),則執(zhí)行與PROPAGATION_REQUIRED類似的操作。 |
當(dāng)使用PROPAGATION_NESTED時(shí),底層的數(shù)據(jù)源必須基于JDBC 3.0,并且實(shí)現(xiàn)者需要支持保存點(diǎn)事務(wù)機(jī)制。
示例
當(dāng)服務(wù)接口方法分別使用表1中不同的事務(wù)傳播行為,且這些接口方法又發(fā)生相互調(diào)用的情況下,大部分組合都是一目了然,容易理解的。但是,也存在一些容易引起誤解的組合事務(wù)傳播方式。
下面,我們通過兩個(gè)具體的服務(wù)接口的組合調(diào)用行為來破解這一難點(diǎn)。這兩個(gè)服務(wù)接口分別是UserService和ForumService, UserSerice有一個(gè)addCredits()方法,ForumSerivce#addTopic()方法調(diào)用了 UserSerice#addCredits()方法,發(fā)生關(guān)聯(lián)性服務(wù)方法的調(diào)用:
@Service public class ForumService {private UserService userService;// ①調(diào)用其它服務(wù)接口的方法public void addTopic() {// ②被關(guān)聯(lián)調(diào)用的業(yè)務(wù)方法userService.addCredits();}public void setUserService(UserService userService) {this.userService = userService;}}嵌套調(diào)用的事務(wù)方法 : 對(duì)Spring事務(wù)傳播行為最常見的一個(gè)誤解是:當(dāng)服務(wù)接口方法發(fā)生嵌套調(diào)用時(shí),被調(diào)用的服務(wù)方法只能聲明為 PROPAGATION_NESTED。這種觀點(diǎn)犯了望文生義的錯(cuò)誤,誤認(rèn)為PROPAGATION_NESTED是專為方法嵌套準(zhǔn)備的。這種誤解遺害不 淺,執(zhí)有這種誤解的開發(fā)者錯(cuò)誤地認(rèn)為:應(yīng)盡量不讓Service類的業(yè)務(wù)方法發(fā)生相互的調(diào)用,Service類只能調(diào)用DAO層的DAO類,以避免產(chǎn)生嵌 套事務(wù)。
其實(shí),這種顧慮是完全沒有必要的,PROPAGATION_REQUIRED已經(jīng)清楚地告訴我們:事務(wù)的方法會(huì)足夠“聰明”地判斷上下文是否已經(jīng)存在一個(gè)事務(wù)中,如果已經(jīng)存在,就加入到這個(gè)事務(wù)中,否則創(chuàng)建一個(gè)新的事務(wù)。
依照上面的例子,假設(shè)我們將ForumService#addTopic()和UserSerice#addCredits()方法的事務(wù)傳播行為都設(shè)置為PROPAGATION_REQUIRED,這兩個(gè)方法將運(yùn)行于同一個(gè)事務(wù)中。
將ForumService#addTopic()設(shè)置為PROPAGATION_REQUIRED時(shí), UserSerice#addCredits()設(shè)置為PROPAGATION_REQUIRED、PROPAGATION_SUPPORTS、 PROPAGATION_MANDATORY時(shí),運(yùn)行的效果都是一致的(當(dāng)然,如果單獨(dú)調(diào)用addCredits()就另當(dāng)別論了)。
當(dāng)addTopic()運(yùn)行在一個(gè)事務(wù)下(如設(shè)置為PROPAGATION_REQUIRED),而addCredits()設(shè)置為 PROPAGATION_NESTED時(shí),如果底層數(shù)據(jù)源支持保存點(diǎn),Spring將為內(nèi)部的addCredits()方法產(chǎn)生的一個(gè)內(nèi)嵌的事務(wù)。如果 addCredits()對(duì)應(yīng)的內(nèi)嵌事務(wù)執(zhí)行失敗,事務(wù)將回滾到addCredits()方法執(zhí)行前的點(diǎn),并不會(huì)將整個(gè)事務(wù)回滾。內(nèi)嵌事務(wù)是內(nèi)層事務(wù)的一 部分,所以只有外層事務(wù)提交時(shí),嵌套事務(wù)才能一并提交。
嵌套事務(wù)不能夠提交,它必須通過外層事務(wù)來完成提交的動(dòng)作,外層事務(wù)的回滾也會(huì)造成內(nèi)部事務(wù)的回滾。
嵌套事務(wù)和新事務(wù)
PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED也是容易混淆的兩個(gè)傳播行為。PROPAGATION_REQUIRES_NEW 啟動(dòng)一個(gè)新的、和外層事務(wù)無關(guān)的“內(nèi)部”事務(wù)。該事務(wù)擁有自己的獨(dú)立隔離級(jí)別和鎖,不依賴于外部事務(wù),獨(dú)立地提交和回滾。當(dāng)內(nèi)部事務(wù)開始執(zhí)行時(shí),外部事務(wù) 將被掛起,內(nèi)務(wù)事務(wù)結(jié)束時(shí),外部事務(wù)才繼續(xù)執(zhí)行。
由此可見, PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大區(qū)別在于:
- PROPAGATION_REQUIRES_NEW 將創(chuàng)建一個(gè)全新的事務(wù),它和外層事務(wù)沒有任何關(guān)系,
- 而 PROPAGATION_NESTED 將創(chuàng)建一個(gè)依賴于外層事務(wù)的子事務(wù),當(dāng)外層事務(wù)提交或回滾時(shí),子事務(wù)也會(huì)連帶提交和回滾。
以下幾個(gè)問題值得注意:
1.當(dāng)業(yè)務(wù)方法被設(shè)置為PROPAGATION_MANDATORY時(shí),它就不能被非事務(wù)的業(yè)務(wù)方法調(diào)用。
如將ForumService#addTopic ()設(shè)置為PROPAGATION_MANDATORY,如果展現(xiàn)層的Action直接調(diào)用addTopic()方法,將引發(fā)一個(gè)異常。正確的情況是: addTopic()方法必須被另一個(gè)帶事務(wù)的業(yè)務(wù)方法調(diào)用(如ForumService#otherMethod())。所以 PROPAGATION_MANDATORY的方法一般都是被其它業(yè)務(wù)方法間接調(diào)用的。2 當(dāng)業(yè)務(wù)方法被設(shè)置為PROPAGATION_NEVER時(shí),它將不能被擁有事務(wù)的其它業(yè)務(wù)方法調(diào)用。
假設(shè)UserService#addCredits ()設(shè)置為PROPAGATION_NEVER,當(dāng)ForumService# addTopic()擁有一個(gè)事務(wù)時(shí),addCredits()方法將拋出異常。所以PROPAGATION_NEVER方法一般是被直接調(diào)用的。3 當(dāng)方法被設(shè)置為PROPAGATION_NOT_SUPPORTED時(shí),外層業(yè)務(wù)方法的事務(wù)會(huì)被掛起,當(dāng)內(nèi)部方法運(yùn)行完成后,外層方法的事務(wù)重新運(yùn)行。如果外層方法沒有事務(wù),直接運(yùn)行,不需要做任何其它的事。
在Spring聲明式事務(wù)管理的配置中,事務(wù)傳播行為是最容易被誤解的配置項(xiàng),原因在于事務(wù)傳播行為名稱(如 PROPAGATION_NESTED:嵌套式事務(wù))和代碼結(jié)構(gòu)的類似性上(業(yè)務(wù)類方法嵌套調(diào)用另一個(gè)業(yè)務(wù)類方法).
編程式的事務(wù)管理
在實(shí)際的應(yīng)用中很少通過編程來進(jìn)行事務(wù)管理,但是Spring還是為編程式事務(wù)管理提供了模板類 TransactionTemplate,以滿足一些特殊場(chǎng)合的要求。
TransactionTemplate是線程安全的,因此可以在多個(gè)類中共享TransactionTemplate實(shí)例進(jìn)行事務(wù)管理。
TransactionTemplate主要有兩個(gè)方法:
public void setTransactionManager(PlatformTransactionManager transactionManager) 設(shè)置事務(wù)管理器
public <T> T execute(TransactionCallback<T> action) throws TransactionException 在TransactionCallback回調(diào)接口中定義需要以事務(wù)方式組織的數(shù)據(jù)訪問邏輯
TransactionCallback接口中僅有一個(gè)方法
protected void doInTransaction(TransactionStatus status)如果操作不需要返回結(jié)果,可以使用TransactionCallback的子接口 TransactionCallbackWithoutResult。
示例
代碼已托管到Github—> https://github.com/yangshangwei/SpringMaster
POJO
package com.xgj.dao.transaction.programTrans;import org.springframework.stereotype.Component;/*** * * @ClassName: Artisan* * @Description: @Component標(biāo)注的Bean* * @author: Mr.Yang* * @date: 2017年9月18日 下午5:03:47*/@Component public class Artisan {private String userName;private String password;public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}} package com.xgj.dao.transaction.programTrans;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate;/*** * * @ClassName: ProgramTransService* * @Description: 在實(shí)際應(yīng)用中,很少通過編程的方式來進(jìn)行事務(wù)管理。* * @author: Mr.Yang* * @date: 2017年9月21日 下午3:48:10*/@Service public class ProgramTransService {private JdbcTemplate jdbcTemplate;private TransactionTemplate transactionTemplate;// 下面兩條SQL在一個(gè)事務(wù)中,第二條故意寫錯(cuò)了表名,會(huì)執(zhí)行失敗,第一條已經(jīng)成功的SQL也會(huì)回滾private static final String addArtisanSQL = "insert into artisan_user(user_name,password) values(?,?)";private static final String deleteOneArtisanSQL = "delete from artisan_user1 where user_name = 'ArtisanBatch0' ";@Autowiredpublic void setJdbcTemplate(JdbcTemplate jdbcTemplate) {this.jdbcTemplate = jdbcTemplate;}/*** * * @Title: setTransactionTemplate* * @Description: 通過AOP主動(dòng)注入transactionTemplate* * @param transactionTemplate* * @return: void*/@Autowiredpublic void setTransactionTemplate(TransactionTemplate transactionTemplate) {this.transactionTemplate = transactionTemplate;}public void operArtisanInTrans(final Artisan artisan) {transactionTemplate.execute(new TransactionCallbackWithoutResult() {@Overrideprotected void doInTransactionWithoutResult(TransactionStatus status) {// 需要在事務(wù)中執(zhí)行的邏輯jdbcTemplate.update(addArtisanSQL, artisan.getUserName(),artisan.getPassword());System.out.println("addArtisanSQL OK ");jdbcTemplate.update(deleteOneArtisanSQL);System.out.println("deleteOneArtisanSQL OK ");}});} }配置文件
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!-- 掃描類包,將標(biāo)注Spring注解的類自動(dòng)轉(zhuǎn)化Bean,同時(shí)完成Bean的注入 --><context:component-scan base-package="com.xgj.dao.transaction.programTrans" /><!-- 不使用context命名空間,則需要定義Bean <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations" value="classpath:spring/jdbc.properties" /> </bean> --><!-- 使用context命名空間,同上面的Bean等效.在xml文件中配置數(shù)據(jù)庫的properties文件 --><context:property-placeholder location="classpath:spring/jdbc.properties" /><bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close" p:driverClassName="${jdbc.driverClassName}"p:url="${jdbc.url}" p:username="${jdbc.username}" p:password="${jdbc.password}" /><!-- 配置Jdbc模板 --><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"p:dataSource-ref="dataSource" /><!--基于數(shù)據(jù)源的事務(wù)管理器,通過屬性引用數(shù)據(jù)源--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"p:dataSource-ref="dataSource"/><!-- 配置transactionTemplate模板 --> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"p:transactionManager-ref="transactionManager"/></beans>單元測(cè)試
package com.xgj.dao.transaction.programTrans;import org.junit.After; import org.junit.Before; import org.junit.Test; import org.springframework.context.support.ClassPathXmlApplicationContext;public class ProgramTransServiceTest {ClassPathXmlApplicationContext ctx = null;@Beforepublic void initContext() {// 啟動(dòng)Spring 容器ctx = new ClassPathXmlApplicationContext("classpath:com/xgj/dao/transaction/programTrans/conf_program_transaction.xml");System.out.println("initContext successfully");}@Testpublic void testProgramTransaction() {Artisan artisan = ctx.getBean("artisan", Artisan.class);artisan.setUserName("trans");artisan.setPassword("123");ProgramTransService programTransService = ctx.getBean("programTransService", ProgramTransService.class);programTransService.operArtisanInTrans(artisan);System.out.println("testProgramTransaction successsfully");}@Afterpublic void closeContext() {if (ctx != null) {ctx.close();}System.out.println("close context successfully");}}運(yùn)行結(jié)果
第二條因?yàn)閳?zhí)行失敗,第一條也回滾了,未插入數(shù)據(jù), OK。
總結(jié)
以上是生活随笔為你收集整理的Spring JDBC-Spring对事务管理的支持的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring-AOP 混合使用各种切面类
- 下一篇: Spring4.X系列之IOC