Spring事務(wù)管理實(shí)現(xiàn)方式之編程式事務(wù)與聲明式事務(wù)詳解

1.上篇文章講解了Spring事務(wù)的傳播級(jí)別與隔離級(jí)別讨勤,以及分布式事務(wù)的簡(jiǎn)單配置箭跳,點(diǎn)擊回看上篇文章

2.編程式事務(wù):編碼方式實(shí)現(xiàn)事務(wù)管理(代碼演示為JDBC事務(wù)管理)

Spring實(shí)現(xiàn)編程式事務(wù),依賴于2大類潭千,分別是上篇文章提到的PlatformTransactionManager谱姓,與模版類TransactionTemplate(推薦使用)。下面分別詳細(xì)介紹Spring是如何通過(guò)該類實(shí)現(xiàn)事務(wù)管理刨晴。

1)PlatformTransactionManager屉来,上篇文章已經(jīng)詳情解說(shuō)了該類所擁有的方法路翻,不記得可以回看上篇文章。

事務(wù)管理器配置

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
   <property name="jdbcUrl" value="${db.jdbcUrl}" />
   <property name="user" value="${user}" />
   <property name="password" value="${password}" />
   <property name="driverClass" value="${db.driverClass}" />
    <!--連接池中保留的最小連接數(shù)奶躯。 --> 
    <property name="minPoolSize"> 
        <value>5</value> 
    </property> 
    <!--連接池中保留的最大連接數(shù)。Default: 15 --> 
    <property name="maxPoolSize"> 
        <value>30</value> 
    </property> 
    <!--初始化時(shí)獲取的連接數(shù)亿驾,取值應(yīng)在minPoolSize與maxPoolSize之間嘹黔。Default: 3 --> 
    <property name="initialPoolSize"> 
        <value>10</value> 
    </property> 
    <!--最大空閑時(shí)間,60秒內(nèi)未使用則連接被丟棄。若為0則永不丟棄莫瞬。Default: 0 --> 
    <property name="maxIdleTime"> 
        <value>60</value> 
    </property> 
    <!--當(dāng)連接池中的連接耗盡的時(shí)候c3p0一次同時(shí)獲取的連接數(shù)儡蔓。Default: 3 --> 
    <property name="acquireIncrement"> 
        <value>5</value> 
    </property> 
    <!--JDBC的標(biāo)準(zhǔn)參數(shù),用以控制數(shù)據(jù)源內(nèi)加載的PreparedStatements數(shù)量疼邀。但由于預(yù)緩存的statements 屬于單個(gè)connection而不是整個(gè)連接池喂江。所以設(shè)置這個(gè)參數(shù)需要考慮到多方面的因素。  如果maxStatements與maxStatementsPerConnection均為0旁振,則緩存被關(guān)閉获询。Default: 0 --> 
    <property name="maxStatements"> 
        <value>0</value> 
    </property> 
    <!--每60秒檢查所有連接池中的空閑連接。Default: 0 --> 
    <property name="idleConnectionTestPeriod"> 
        <value>60</value> 
    </property> 
    <!--定義在從數(shù)據(jù)庫(kù)獲取新連接失敗后重復(fù)嘗試的次數(shù)拐袜。Default: 30 --> 
    <property name="acquireRetryAttempts"> 
        <value>30</value> 
    </property> 
    <!--獲取連接失敗將會(huì)引起所有等待連接池來(lái)獲取連接的線程拋出異常吉嚣。但是數(shù)據(jù)源仍有效 保留,并在下次調(diào)用getConnection()的時(shí)候繼續(xù)嘗試獲取連接蹬铺。如果設(shè)為true尝哆,那么在嘗試獲取連接失敗后該數(shù)據(jù)源將申明已斷開(kāi)并永久關(guān)閉。Default: false --> 
    <property name="breakAfterAcquireFailure"> 
        <value>true</value> 
    </property> 
    <!--因性能消耗大請(qǐng)只在需要的時(shí)候使用它甜攀。如果設(shè)為true那么在每個(gè)connection提交的 時(shí)候都將校驗(yàn)其有效性秋泄。建議使用idleConnectionTestPeriod或automaticTestTable等方法來(lái)提升連接測(cè)試的性能。Default: false --> 
    <property name="testConnectionOnCheckout"> 
        <value>false</value> 
    </property> 
</bean>
<!--DataSourceTransactionManager位于org.springframework.jdbc.datasource包下规阀,數(shù)據(jù)源事務(wù)管理類恒序,提供對(duì)單個(gè)javax.sql.DataSource數(shù)據(jù)源的事務(wù)管理,主要用于JDBC谁撼,Mybatis框架事務(wù)管理奸焙。 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
   <property name="dataSource" ref="dataSource" />
</bean>
業(yè)務(wù)中使用代碼(以測(cè)試類展示)

業(yè)務(wù)中使用代碼(以測(cè)試類展示)

import java.util.Map;
import javax.annotation.Resource;
import javax.sql.DataSource;
import org.apache.log4j.Logger;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:spring-public.xml" })
public class test {
   @Resource
   private PlatformTransactionManager txManager;
   @Resource
   private  DataSource dataSource;
   private static JdbcTemplate jdbcTemplate;
   Logger logger=Logger.getLogger(test.class);
   private static final String INSERT_SQL = "insert into testtranstation(sd) values(?)";
   private static final String COUNT_SQL = "select count(*) from testtranstation";
   @Test
   public void testdelivery(){
       //定義事務(wù)隔離級(jí)別,傳播行為彤敛,
       DefaultTransactionDefinition def = new DefaultTransactionDefinition();  
       def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);  
       def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);  
       //事務(wù)狀態(tài)類与帆,通過(guò)PlatformTransactionManager的getTransaction方法根據(jù)事務(wù)定義獲取墨榄;獲取事務(wù)狀態(tài)后玄糟,Spring根據(jù)傳播行為來(lái)決定如何開(kāi)啟事務(wù)
       TransactionStatus status = txManager.getTransaction(def);  
       jdbcTemplate = new JdbcTemplate(dataSource);
       int i = jdbcTemplate.queryForInt(COUNT_SQL);  
       System.out.println("表中記錄總數(shù):"+i);
       try {  
           jdbcTemplate.update(INSERT_SQL, "1");  
           txManager.commit(status);  //提交status中綁定的事務(wù)
       } catch (RuntimeException e) {  
           txManager.rollback(status);  //回滾
       }  
       i = jdbcTemplate.queryForInt(COUNT_SQL);  
       System.out.println("表中記錄總數(shù):"+i);
   }
   
}

2)使用TransactionTemplate,該類繼承了接口DefaultTransactionDefinition袄秩,用于簡(jiǎn)化事務(wù)管理阵翎,事務(wù)管理由模板類定義逢并,主要是通過(guò)TransactionCallback回調(diào)接口或TransactionCallbackWithoutResult回調(diào)接口指定,通過(guò)調(diào)用模板類的參數(shù)類型為TransactionCallback或TransactionCallbackWithoutResult的execute方法來(lái)自動(dòng)享受事務(wù)管理郭卫。

TransactionTemplate模板類使用的回調(diào)接口:

  • TransactionCallback:通過(guò)實(shí)現(xiàn)該接口的“T doInTransaction(TransactionStatus status) ”方法來(lái)定義需要事務(wù)管理的操作代碼砍聊;
  • TransactionCallbackWithoutResult:繼承TransactionCallback接口,提供“void doInTransactionWithoutResult(TransactionStatus status)”便利接口用于方便那些不需要返回值的事務(wù)操作代碼贰军。

還是以測(cè)試類方式展示如何實(shí)現(xiàn)

@Test
public void testTransactionTemplate(){
    jdbcTemplate = new JdbcTemplate(dataSource);
    int i = jdbcTemplate.queryForInt(COUNT_SQL);  
    System.out.println("表中記錄總數(shù):"+i);
    //構(gòu)造函數(shù)初始化TransactionTemplate
    TransactionTemplate template = new TransactionTemplate(txManager);
    template.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);  
    //重寫execute方法實(shí)現(xiàn)事務(wù)管理
    template.execute(new TransactionCallbackWithoutResult() {
        @Override
        protected void doInTransactionWithoutResult(TransactionStatus status) {
            jdbcTemplate.update(INSERT_SQL, "餓死");   //字段sd為int型玻蝌,所以插入肯定失敗報(bào)異常,自動(dòng)回滾词疼,代表TransactionTemplate自動(dòng)管理事務(wù)
        }}
    );
    i = jdbcTemplate.queryForInt(COUNT_SQL);  
    System.out.println("表中記錄總數(shù):"+i);
}

3.聲明式事務(wù):可知編程式事務(wù)每次實(shí)現(xiàn)都要單獨(dú)實(shí)現(xiàn)俯树,但業(yè)務(wù)量大功能復(fù)雜時(shí),使用編程式事務(wù)無(wú)疑是痛苦的贰盗,而聲明式事務(wù)不同许饿,聲明式事務(wù)屬于無(wú)侵入式,不會(huì)影響業(yè)務(wù)邏輯的實(shí)現(xiàn)舵盈。

聲明式事務(wù)實(shí)現(xiàn)方式主要有2種陋率,一種為通過(guò)使用Spring的<tx:advice>定義事務(wù)通知與AOP相關(guān)配置實(shí)現(xiàn),另為一種通過(guò)@Transactional實(shí)現(xiàn)事務(wù)管理實(shí)現(xiàn)秽晚,下面詳細(xì)說(shuō)明2種方法如何配置翘贮,已經(jīng)相關(guān)注意點(diǎn)

1)方式一,配置文件如下


<!-- 
<tx:advice>定義事務(wù)通知爆惧,用于指定事務(wù)屬性狸页,其中“transaction-manager”屬性指定事務(wù)管理器,并通過(guò)<tx:attributes>指定具體需要攔截的方法
    <tx:method>攔截方法扯再,其中參數(shù)有:
    name:方法名稱芍耘,將匹配的方法注入事務(wù)管理,可用通配符
    propagation:事務(wù)傳播行為熄阻,
    isolation:事務(wù)隔離級(jí)別定義斋竞;默認(rèn)為“DEFAULT”
    timeout:事務(wù)超時(shí)時(shí)間設(shè)置,單位為秒秃殉,默認(rèn)-1坝初,表示事務(wù)超時(shí)將依賴于底層事務(wù)系統(tǒng);
    read-only:事務(wù)只讀設(shè)置钾军,默認(rèn)為false鳄袍,表示不是只讀;
    rollback-for:需要觸發(fā)回滾的異常定義吏恭,可定義多個(gè)拗小,以“,”分割樱哼,默認(rèn)任何RuntimeException都將導(dǎo)致事務(wù)回滾哀九,而任何Checked Exception將不導(dǎo)致事務(wù)回滾剿配;
    no-rollback-for:不被觸發(fā)進(jìn)行回滾的 Exception(s);可定義多個(gè)阅束,以“呼胚,”分割;
 -->
<tx:advice id="advice" transaction-manager="transactionManager">
    <tx:attributes>
        <!-- 攔截save開(kāi)頭的方法息裸,事務(wù)傳播行為為:REQUIRED:必須要有事務(wù), 如果沒(méi)有就在上下文創(chuàng)建一個(gè) -->
        <tx:method name="save*" propagation="REQUIRED" isolation="READ_COMMITTED" timeout="" read-only="false" no-rollback-for="" rollback-for=""/>
        <!-- 支持,如果有就有,沒(méi)有就沒(méi)有 -->
        <tx:method name="*" propagation="SUPPORTS"/>
    </tx:attributes>
</tx:advice>
<!-- 定義切入點(diǎn)蝇更,expression為切人點(diǎn)表達(dá)式,如下是指定impl包下的所有方法界牡,具體以自身實(shí)際要求自定義  -->
<aop:config>
    <aop:pointcut expression="execution(* com.kaizhi.*.service.impl.*.*(..))" id="pointcut"/>
    <!--<aop:advisor>定義切入點(diǎn)簿寂,與通知漾抬,把tx與aop的配置關(guān)聯(lián),才是完整的聲明事務(wù)配置 -->
    <aop:advisor advice-ref="advice" pointcut-ref="pointcut"/>

關(guān)于事務(wù)傳播行為與隔離級(jí)別宿亡,可參考http://blog.csdn.net/liaohaojian/article/details/68488150

注意點(diǎn):

  1. 事務(wù)回滾異常只能為RuntimeException異常,而Checked Exception異常不回滾纳令,捕獲異常不拋出也不會(huì)回滾挽荠,但可以強(qiáng)制事務(wù)回滾:TransactionAspectSupport.currentTransactionStatus().isRollbackOnly();
  2. 解決“自我調(diào)用”而導(dǎo)致的不能設(shè)置正確的事務(wù)屬性問(wèn)題,可參考http://www.iteye.com/topic/1122740

2)方式二通過(guò)@Transactional實(shí)現(xiàn)事務(wù)管理

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">   
     <property name="dataSource" ref="dataSource"/>
</bean>    
<tx:annotation-driven transaction-manager="txManager"/> //開(kāi)啟事務(wù)注解

@Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.READ_COMMITTED)平绩,具體參數(shù)跟上面<tx:method>中一樣

Spring提供的@Transaction注解事務(wù)管理圈匆,內(nèi)部同樣是利用環(huán)繞通知TransactionInterceptor實(shí)現(xiàn)事務(wù)的開(kāi)啟及關(guān)閉。
使用@Transactional注意點(diǎn):

  1. 如果在接口捏雌、實(shí)現(xiàn)類或方法上都指定了@Transactional 注解跃赚,則優(yōu)先級(jí)順序?yàn)榉椒?gt;實(shí)現(xiàn)類>接口;
  2. 建議只在實(shí)現(xiàn)類或?qū)崿F(xiàn)類的方法上使用@Transactional性湿,而不要在接口上使用纬傲,這是因?yàn)槿绻褂肑DK代理機(jī)制(基于接口的代理)是沒(méi)問(wèn)題;而使用使用CGLIB代理(繼承)機(jī)制時(shí)就會(huì)遇到問(wèn)題肤频,因?yàn)槠涫褂没陬惖拇矶皇墙涌谔纠ǎ@是因?yàn)榻涌谏系腀Transactional注解是“不能繼承的”;
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末宵荒,一起剝皮案震驚了整個(gè)濱河市汁雷,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌报咳,老刑警劉巖侠讯,帶你破解...
    沈念sama閱讀 222,807評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異暑刃,居然都是意外死亡继低,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門稍走,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)袁翁,“玉大人柴底,你說(shuō)我怎么就攤上這事×皇ぃ” “怎么了柄驻?”我有些...
    開(kāi)封第一講書人閱讀 169,589評(píng)論 0 363
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)焙压。 經(jīng)常有香客問(wèn)我鸿脓,道長(zhǎng),這世上最難降的妖魔是什么涯曲? 我笑而不...
    開(kāi)封第一講書人閱讀 60,188評(píng)論 1 300
  • 正文 為了忘掉前任野哭,我火速辦了婚禮,結(jié)果婚禮上幻件,老公的妹妹穿的比我還像新娘拨黔。我一直安慰自己,他們只是感情好绰沥,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,185評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布篱蝇。 她就那樣靜靜地躺著,像睡著了一般徽曲。 火紅的嫁衣襯著肌膚如雪零截。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 52,785評(píng)論 1 314
  • 那天秃臣,我揣著相機(jī)與錄音涧衙,去河邊找鬼。 笑死奥此,一個(gè)胖子當(dāng)著我的面吹牛弧哎,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播得院,決...
    沈念sama閱讀 41,220評(píng)論 3 423
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼傻铣,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了祥绞?” 一聲冷哼從身側(cè)響起非洲,我...
    開(kāi)封第一講書人閱讀 40,167評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蜕径,沒(méi)想到半個(gè)月后两踏,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,698評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡兜喻,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,767評(píng)論 3 343
  • 正文 我和宋清朗相戀三年梦染,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,912評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡帕识,死狀恐怖泛粹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情肮疗,我是刑警寧澤晶姊,帶...
    沈念sama閱讀 36,572評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站伪货,受9級(jí)特大地震影響们衙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜碱呼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,254評(píng)論 3 336
  • 文/蒙蒙 一蒙挑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧愚臀,春花似錦忆蚀、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,746評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)梦皮。三九已至炭分,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間剑肯,已是汗流浹背捧毛。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,859評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留让网,地道東北人呀忧。 一個(gè)月前我還...
    沈念sama閱讀 49,359評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像溃睹,于是被迫代替她去往敵國(guó)和親而账。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,922評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理因篇,服務(wù)發(fā)現(xiàn)泞辐,斷路器,智...
    卡卡羅2017閱讀 134,716評(píng)論 18 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,867評(píng)論 6 342
  • Spring 事務(wù)屬性分析 事務(wù)管理對(duì)于企業(yè)應(yīng)用而言至關(guān)重要竞滓。它保證了用戶的每一次操作都是可靠的咐吼,即便出現(xiàn)了異常的...
    壹點(diǎn)零閱讀 1,306評(píng)論 0 2
  • PartV.TransactiomManagement github 地址 https://github.com/...
    天幕_bc1a閱讀 1,127評(píng)論 2 0
  • 李先生, 今天回家了 回來(lái)看爸爸 最近你也應(yīng)該回去看你爸了吧 還好嗎 ...
    L離城閱讀 99評(píng)論 0 0