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