這篇文章將為大家詳細講解有關(guān)Spring中事務機制的示例分析,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
具體如下。
JAVA EE傳統(tǒng)事務機制通常有兩種事務策略:全局事務和局部事務。全局事務可以跨多個事務性資源(即數(shù)據(jù)源,典型的是數(shù)據(jù)庫和消息隊列),通常都需要J2EE應用服務器的管理,其底層需要服務器的JTA支持。而局部事務則與底層采用的持久化技術(shù)有關(guān),如果底層直接使用JDBC,需要用Connection對象來操事務。如果采用Hibernate持久化技術(shù),則需要使用session對象來操作事務。
通常的,使用JTA事務,JDBC事務及Hibernate事務的編程流程大致如下,
上圖也可以看出,采用傳統(tǒng)事務編程,程序代碼必須和具體的事務策略的API耦合,如果應用需要切換一種策略,意味著需要大幅修改代碼。但是如果使用Spring事務的話,就不會有這個問題了。
Spring事務機制Sring沒有提供任何事務支持,它只是負責包裝底層的事務,而在Spring層面,對外提供統(tǒng)一的編程API。Spring事務的核心是PlatformTransactionManager接口,
PlatformTransactionManager代表與具體類型無關(guān)的事務接口,可以代表任何事務,包括JDBC事務,Hibernate事務,甚至是JTA事務。
Springa事務機制是一種典型的策略模式,PlatformTransactionManager代表事務管理接口,但它并不知道到底如何管理事務,它只要求事務管理提供開始事務getTransaction(),
提交事務commit()
和回滾事務rollback()
這三個方法,但具體如何實現(xiàn)則交給其實現(xiàn)類完成。編程人員只需要在配置文件中根據(jù)具體需要使用的事務類型做配置,Spring底層就自動會使用具體的事務實現(xiàn)類進行事務操作,而對于程序員來說,完全不需要關(guān)心底層過程,只需要面向PlatformTransactionManager接口進行編程即可。PlatformTransactionManager接口中提供了如下方法:getTransaction(..), commit(); rollback();
這些都是與平臺無關(guān)的事務操作。
getTransaction()
的完整寫法為 TransactionStatus getTransaction(TransactionDefinition definiton)
這個方法用來返回一個事務對象,其中的參數(shù)TransactionDefinition 則可以為事務對象指定各種屬性,通常可以指定 事務的隔離屬性, 傳播屬性, 超時,只讀 這幾個屬性。
Spring具體的事務管理需要在配置文件中配置好PlatformTransactionManager,下面是不同類型的事務對應的Spring配置。
JDBC數(shù)據(jù)源的局部事務管理器的配置如下,
<!-- 定義數(shù)據(jù)源Bean,使用C3P0數(shù)據(jù)源實現(xiàn),并注入數(shù)據(jù)源的必要信息 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSrouce" destroy-method="close" p:driverClass="com.mysql.jdbc.Driver" p:jdbcUrl="jdbc:mysql://localhost/test" p:user="root" p:password="" p:maxPoolSize="40" p:minPoolSize="2" p:initialPoolSize="2" p:maxIdleTime="30" /> <!-- 配置JDBC數(shù)據(jù)源的局部數(shù)據(jù)管理器,使用DataSourceTransactionManager類 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" p:dataSource-ref="dataSource" />
容器管理的JTA全局事務管理器的配置如下,
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean" p:jndiName="jdbc/jpetstore" /> <!-- 使用JtaTransactionManager類, 該類實現(xiàn)了PlatformTransactionManager接口 --> <!-- 使用JTA全局事務,Spring容器可以自行從Java EE服務器中獲取事務性資源,無需依賴注入 --> <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" />
對于JTA全局事務,只需要指定事務管理器的實現(xiàn)類JtaTransactionManager即可,Spring容器會自行從J2EE服務器獲取數(shù)據(jù)源,無需顯式注入進事務管理器。
基于Hibernate持久化技術(shù)的Spring局部事務配置如下,
<!-- 定義數(shù)據(jù)源Bean,使用C3P0數(shù)據(jù)源實現(xiàn),并注入數(shù)據(jù)源的必要信息 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSrouce" destroy-method="close" p:driverClass="com.mysql.jdbc.Driver" p:jdbcUrl="jdbc:mysql://localhost/test" p:user="root" p:password="" p:maxPoolSize="40" p:minPoolSize="2" p:initialPoolSize="2" p:maxIdleTime="30" /> <!-- 定義Hibernate的SessionFactory, SessionFactory需要依賴數(shù)據(jù)源,注入dataSource --> <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" p:dataSource-ref="dataSource"> <!-- annotatedClasses用來列出全部持久化類 --> <property name="annotatedClasses"> <list> <!-- 以下用來列出所有PO類 --> <value>com.entity.User</value> </list> </property> <!-- 定義Hibernate的sessionFactory屬性 --> <property name="hibernateProperties"> <props> <!-- 指定Hibernate的連接方言 --> <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop> <!-- 是否根據(jù)Hibernate映射表創(chuàng)建數(shù)據(jù)表 --> <prop key="hibernate.hbm2ddl.auto">update</prop> </props> </property> </bean> <!-- 配置Hibernate的局部數(shù)據(jù)管理器,使用HibernateTransactionManager類 --> <!-- 該類是PlatformTransactionManager接口針對Hibernate的特定實現(xiàn) --> <!-- 配置HibernateTransactionManager需要注入sessionFactory --> <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager" p:sessionFactory-ref="sessionFactory" />
Spring事務如果采用Hibernate策略,一般需要配置三點:數(shù)據(jù)源, sessionFactory, 事務管理器。
如果底層采用Hibernate持久層技術(shù),而事務采用JTA全局事務時,配置如下,
<!-- 配置JTA數(shù)據(jù)源--> <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean" p:jndiName="jdbc/jpetstore" /> <!-- 定義Hibernate的SessionFactory, SessionFactory需要依賴數(shù)據(jù)源,注入dataSource --> <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" p:dataSource-ref="dataSource"> <!-- annotatedClasses用來列出全部持久化類 --> <property name="annotatedClasses"> <list> <!-- 以下用來列出所有PO類 --> <value>com.entity.User</value> </list> </property> <!-- 定義Hibernate的sessionFactory屬性 --> <property name="hibernateProperties"> <props> <!-- 指定Hibernate的連接方言 --> <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop> <!-- 是否根據(jù)Hibernate映射表創(chuàng)建數(shù)據(jù)表 --> <prop key="hibernate.hbm2ddl.auto">update</prop> </props> </property> </bean> <!-- 使用JtaTransactionManager類,該類是PlatformTransactionManager接口的實現(xiàn)類 --> <!-- 針對全局事務管理的特定實現(xiàn) --> <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" />
這與前面的基于Hibernate的Spring事務比起來,就是將數(shù)據(jù)源換成了JNDI數(shù)據(jù)源, 將事務管理器換成了JtaTransactionManager.
對于JTA全局事務,因為需要底層應用服務器的支持,而不同應用服務器所提供的JTA全局事務可能存在細節(jié)上的差異,因此實際配置全局事務管理器時可能需要使用JtaTransactionManager的子類,例如Oracle的JavaEE應用服務器提供的OC4JJtaTransactionManager,Oracle為WebLogic提供的WebLogicJtaTransactionManager, IBM為WebSphere提供的WebSphereUowTransactionManager等。
從上面各種事務類型的Spring配置可以看出,當應用程序采用Spring事務管理時,應用程序無需與具體的事務API耦合,應用程序只需要面向PlatormTransactionManager接口編程即可,ApplicationContext會根據(jù)配置文件選擇合適的事務策略實現(xiàn)類(即PlatormTransactionManager的實現(xiàn)類)。
那么在具體在Spring中如何進行事務控制編程呢,通常有兩種方式,
編程式事務管理:就是直接在代碼中使用PlatormTransactionManager提供的三個抽象方法進行事務流程控制。也可以在Spring容器中獲取PlatormTransactionManager類型的Bean,該Bean總是PlatormTransactionManager的具體實現(xiàn)類的實例,具體的實現(xiàn)類則由ApplicationContext按照策略模式進行選擇,編程人員無需關(guān)心,只需要面向接口編程即可。
聲明式事務管理:這種方式不需要講事務控制流程寫入代碼中,而是通過AOP的方式,完全由配置文件完成事務的織入。即XML配置文件可以為業(yè)務組件配置事務代理,事務代理為業(yè)務組件提供事務控制?,F(xiàn)在這種方式是最好的,源碼侵入性最低。
使用聲明式事務管理-使用XML Schema配置事務策略當使用聲明式事務時,只需要寫好配置文件,配置需要事務控制的組件種類,業(yè)務組件就會在AOP機制下被織入事務控制,而編程人員不需要寫任何事務管理代碼,可以專注于業(yè)務組件的開發(fā)。因此通常都推薦使用聲明式事務管理。
Spring的XML Schema方式提供了簡潔的事務配置策略,通過命名空間 <tx:advice>
來配置一個事務增強處理,其中可以指定事務的各種屬性(例如隔離屬性, 傳播屬性, 超時,只讀屬性等等),然后通過<aop:config>標簽可以將事務的增強與AOP的切入點(即Bean的執(zhí)行方法)進行綁定,從而實現(xiàn)對Bean的方法織入事務操作。下面是一個簡單的例子,配置一個NewsDaoImpl bean進行數(shù)據(jù)操作,使用c3p0數(shù)據(jù)源,Spring的JDBC事務管理器,在<tx:advice對事務設(shè)置屬性。
完整的Spring配置如下,
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd"> <!-- 定義數(shù)據(jù)源Bean,使用C3P0數(shù)據(jù)源實現(xiàn),并注入數(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/test?useUnicode=true&characterEncoding=UTF-8" p:user="root" p:password="" p:maxPoolSize="40" p:minPoolSize="2" p:initialPoolSize="2" p:maxIdleTime="30" /> <!-- 配置JDBC數(shù)據(jù)源的局部數(shù)據(jù)管理器,使用DataSourceTransactionManager類 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" p:dataSource-ref="dataSource" /> <!-- 配置一個業(yè)務邏輯Bean --> <bean id="newsDao" class="com.dao.impl.NewsDaoImpl" p:ds-ref="dataSource" /> <!-- 配置事務增強處理, 指定事務管理器 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!-- 用于配置詳細的事務定義 --> <tx:attributes> <!-- 所有以get開頭的方法都是只讀的 --> <tx:method name="get*" read-only="true" /> <!-- 其他方法默認都適用事務,指定超時5秒 --> <tx:method name="*" isolation="DEFAULT" propagation="REQUIRED" timeout="5" /> </tx:attributes> </tx:advice> <aop:config> <!-- 配置一個切入點,匹配impl包下所有以impl結(jié)尾的類里的所有方法的執(zhí)行 --> <aop:pointcut expression="execution(* com.dao.impl.*Impl.*(..))" id="myPointcut" /> <!-- 將切入點myPointcut和增強txAdvice綁定--> <aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut" /> <!-- 再配置一個切入點,匹配impl包下所有以abc開頭類里的所有方法的執(zhí)行 --> </aop:config> </beans>
NewsDaoImpl代碼中,則是插入重復數(shù)據(jù)到表中,
package com.dao.impl; import javax.sql.DataSource; import org.springframework.jdbc.core.JdbcTemplate; import com.dao.NewsDao; public class NewsDaoImpl implements NewsDao { private DataSource ds; public void setDs(DataSource ds) { this.ds = ds; } @Override public void insert(String title, String content) { //c3p0數(shù)據(jù)池的用法 JdbcTemplate jt = new JdbcTemplate(ds); jt.update("insert into news_inf" + " values(100,?,?)", title, content); jt.update("insert into news_inf" + " values(100,?,?)", title, content); //如果沒有事務控制,則第一條記錄可以被插入 //如果增加事務控制,將發(fā)現(xiàn)第一條記錄也插不進去 } }
下面是測試方法,
public static void test3() { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans4JDBC.xml"); //獲取事務代理Bean NewsDao dao = (NewsDao)ctx.getBean("newsDao", NewsDao.class); dao.insert("java編程核心思想", "輕量級Java EE開發(fā)"); System.out.println("執(zhí)行完畢"); }
執(zhí)行測試方法會發(fā)現(xiàn)拋出異常(因為有重復數(shù)據(jù)),而又因為事務控制,數(shù)據(jù)庫中講不會有數(shù)據(jù)插入。
可以看到上面例子中,通常對于XML Schema的配置中,其實就是對一個普通的Bean做了AOP配置,織入一個advice增強,而advice增強中則配置一個事務管理器,事務管理器又依賴數(shù)據(jù)源。
對于<aop:advisor>中,將advice和切入點的綁定,而在Spring底層是由Bean后處理器完成(例如BeanNameAutoProxyCreator, DefaultAdvisorAutoProxyCreator),其本質(zhì)就是動態(tài)代理。
另外,在<tx:advice>配置增強中,還可以為事務指定再遇到特定異常時,進行強制rollback和強制不rollback,即rollback-for="xxxException", no-rollback-for="xxxException"
使用@Transactionl除了使用XML Schema的方法之外,也可以直接在方法上添加@Transaction注解,使這個方法具有事務屬性。 在@Transaction中可以為事務配置各種屬性(例如隔離屬性, 傳播屬性, 超時,只讀屬性等等),此外,還需要在在XML配置中加入<tx:annotation-triven配置表明Spring會根據(jù)注解來配置事務代理,這樣,事務的屬性配置和AOP切入配置就可以只通過一步(直接通過注解配置在方法名上)完成了。
<tx:annotation-driven transaction-manager="transactionManager" />
NewsDaoImpl.
@Transactional(propagation=Propagation.REQUIRED, isolation=Isolation.DEFAULT, timeout=5) @Override public void insert(String title, String content) {
關(guān)于“Spring中事務機制的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
當前名稱:Spring中事務機制的示例分析-創(chuàng)新互聯(lián)
轉(zhuǎn)載注明:http://aaarwkj.com/article0/gisoo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供關(guān)鍵詞優(yōu)化、小程序開發(fā)、靜態(tài)網(wǎng)站、網(wǎng)站營銷、動態(tài)網(wǎng)站、標簽優(yōu)化
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容