Spring事務(wù)管理

事務(wù)

事務(wù)的基本概念
事務(wù)指的是邏輯上的一組操作医清,這組操作要么全部成功放可,要么全部失敗法褥。

事務(wù)的特性
原子性:事務(wù)是一個(gè)不可分割的工作單位茫叭,事務(wù)中的操作要么都發(fā)生,要么都不發(fā)生半等。

一致性:事務(wù)前后數(shù)據(jù)的完整性必須保持一致揍愁。

隔離性:多個(gè)用戶并發(fā)訪問(wèn)數(shù)據(jù)庫(kù)時(shí)呐萨,一個(gè)用戶的事務(wù)不能被其他用戶的事務(wù)所干擾,多個(gè)并發(fā)事務(wù)之間數(shù)據(jù)要相互隔離(數(shù)據(jù)庫(kù)中相應(yīng)的數(shù)據(jù)隔離級(jí)別莽囤,通過(guò)它避免事務(wù)間的沖突)谬擦。

持久性:一個(gè)事務(wù)一旦被提交,它對(duì)數(shù)據(jù)庫(kù)中數(shù)據(jù)的改變是永久性的朽缎,即使數(shù)據(jù)庫(kù)發(fā)生故障也不應(yīng)該對(duì)其有任何影響惨远。

Spring中的事務(wù)管理

Spring提供了一組接口進(jìn)行事務(wù)的管理。
Spring提供事務(wù)管理的3個(gè)接口:
【1】PlatformTransactionManager:事務(wù)管理器话肖,用來(lái)管理事務(wù)的接口北秽,定義了事務(wù)的提交、回滾等方法最筒。
【2】TransactionDefinition:事務(wù)定義信息(隔離級(jí)別羡儿、傳播行為、是否超時(shí)是钥、是否只讀)
【3】TransactionStatus:事務(wù)具體運(yùn)行狀態(tài)(事務(wù)是否提交掠归,事務(wù)是否有保存點(diǎn),事務(wù)是否是新事物等狀態(tài))悄泥。
Spring事務(wù)管理時(shí)虏冻,這三個(gè)接口是有聯(lián)系的,Spring首先會(huì)根據(jù)事務(wù)定義信息TransactionDefinition獲取信息,然后由事務(wù)管理器PlatformTransactionManager進(jìn)行管理弹囚,在事務(wù)管理過(guò)程中厨相,會(huì)產(chǎn)生一個(gè)事務(wù)的狀態(tài),這個(gè)狀態(tài)就保存在事務(wù)具體運(yùn)行狀態(tài)TransactionStatus中了鸥鹉。

PlatformTransactionManager接口介紹:
通過(guò)Spring的API可以知道該接口有許多實(shí)現(xiàn)類例如:DataSourceTransactionManager蛮穿、HibernateTransactionManager等。Spring會(huì)為不同的持久化框架提供了不同PlatformTransactionManager接口實(shí)現(xiàn)毁渗。
比如當(dāng)我們使用SpringJDBC或者iBatis進(jìn)行持久化數(shù)據(jù)時(shí)使用DataSourceTransactionManager践磅。

image.png

TransactionDefinition定義事務(wù)隔離級(jí)別
該接口還提供了一些方法,例如:獲得隔離級(jí)別灸异、獲得超時(shí)信息府适、獲得是否只是只讀的等。
如果不考慮隔離性肺樟,就會(huì)引發(fā)安全問(wèn)題:臟讀檐春、不可重復(fù)讀、以及虛讀或者叫做幻讀么伯。

臟讀:一個(gè)事務(wù)讀取了另一個(gè)事務(wù)改寫但還未提交的數(shù)據(jù)疟暖,如果這些數(shù)據(jù)被回滾,則讀到的數(shù)據(jù)是無(wú)效的。

不可重復(fù)讀:同一事務(wù)中俐巴,多次讀取同一數(shù)據(jù)返回的結(jié)果有所不同(讀取到另一個(gè)事務(wù)已經(jīng)提交的更新的數(shù)據(jù))朋贬。

幻讀:一個(gè)事務(wù)讀取了幾行記錄后,另一個(gè)事務(wù)插入一些記錄窜骄,幻讀就發(fā)生了锦募。再后來(lái)的查詢中,第一個(gè)事務(wù)就會(huì)發(fā)現(xiàn)有些原來(lái)沒(méi)有的記錄邻遏。

正常情況下糠亩,數(shù)據(jù)庫(kù)提供了四種隔離級(jí)別:
READ_UNCOMMITED:安全級(jí)別最低,如果設(shè)置為該級(jí)別准验,就可能會(huì)發(fā)生臟讀赎线、不可重復(fù)讀、幻讀等糊饱。

READ_COMMITED:如果設(shè)置該級(jí)別垂寥,可以避免臟讀的發(fā)生,但是可能會(huì)發(fā)生不可重復(fù)讀和幻讀另锋。

REPEATABLE_READ:如果設(shè)置該級(jí)別滞项,可以避免臟讀和不可重復(fù)讀,但是可能會(huì)發(fā)生幻讀夭坪。

SERIALIZABLE:事務(wù)是串行的文判,不會(huì)發(fā)生并發(fā)訪問(wèn)這種情況
Spring提供了DEFAULT,它代表使用數(shù)據(jù)庫(kù)默認(rèn)的隔離級(jí)別(例如:Mysql默認(rèn)采用REPEATABLE_READ隔離級(jí)別,Oracle默認(rèn)采用READ_COMMITTED隔離級(jí)別)室梅。

TransactionDefinition定義事務(wù)傳播行為
事務(wù)的傳播行為:解決業(yè)務(wù)層方法之間相互調(diào)用的問(wèn)題(一個(gè)service層里的方法調(diào)用另一個(gè)service里中的方法戏仓,這兩個(gè)service中又分屬于兩個(gè)不同的事務(wù),傳播行為就是為了解決方法調(diào)用時(shí)事務(wù)的傳遞)亡鼠。

事務(wù)的傳播行為有7種赏殃,可以為3類:


image.png

第一類為前三個(gè),重點(diǎn)掌握第一個(gè)(在相同事務(wù)里):支持當(dāng)前事務(wù)(Service中bbb()調(diào)用Service中aaa()方法時(shí)间涵,如果aaa()有事務(wù)仁热,則使用該事務(wù)。如果沒(méi)有事務(wù)浑厚,則使用bbb()當(dāng)前事務(wù)股耽,如果當(dāng)前bbb()也沒(méi)有事務(wù),就會(huì)新創(chuàng)建一個(gè)事務(wù))

第二類為接下來(lái)三個(gè)钳幅,重點(diǎn)掌握第一個(gè)(在不同事務(wù)中):如果aaa()有事務(wù)存在,掛起當(dāng)前事務(wù)炎滞,創(chuàng)建一個(gè)新的事務(wù)(aaa()和bbb()不在一個(gè)事務(wù)中)敢艰。
第三類:如果當(dāng)前事務(wù)存在,則嵌套事務(wù)執(zhí)行(執(zhí)行aaa()完后册赛,會(huì)使用事務(wù)的保存點(diǎn)钠导,在執(zhí)行bbb()時(shí)如果發(fā)生異常震嫉,可以回滾到設(shè)置的保存點(diǎn),也可以回滾到最初始的狀態(tài))牡属。

TransactionStatus接口介紹
TransactionStatus接口:提供了獲取事務(wù)狀態(tài)的方法(例如:hasSavepoint()事務(wù)是否有保存點(diǎn)票堵,isCompleted()事務(wù)是否已經(jīng)完成,isNewTransaction()是否是新的事務(wù))逮栅。

Spring事務(wù)管理的兩種方式

【1】編程式的事務(wù)管理:手動(dòng)在程序中編寫代碼實(shí)現(xiàn)事務(wù)管理悴势,實(shí)際應(yīng)用中很少使用,通過(guò)TransactionTemplate管理事務(wù)措伐。

【2】聲明式的事務(wù)管理:使用XML配置實(shí)現(xiàn)事務(wù)管理特纤,推薦使用(代碼侵入性最小)侥加,Spring的聲明式事務(wù)管理是通過(guò)AOP實(shí)現(xiàn)的(沒(méi)有代碼之前開(kāi)啟事務(wù)捧存,代碼完成后提交事務(wù))。

使用聲明式事務(wù)管理實(shí)現(xiàn)轉(zhuǎn)賬示例

搭建事務(wù)管理環(huán)境(模擬轉(zhuǎn)賬環(huán)境)
【a】創(chuàng)建表及插入記錄


image.png

【b】創(chuàng)建項(xiàng)目并引入jar包


image.png

【c】引入log4j.properties担败、applicationContext.xml昔穴、jdbc.properties配置文件。

【e】創(chuàng)建包結(jié)構(gòu)提前,編寫Dao及Service

package spring.demo3;
/*
 * 轉(zhuǎn)賬案例Dao層接口
 */
public interface AccountDao {
    
    public void outMoney(String out,Double money);
    
    public void inMoney(String in,Double money);

}
package spring.demo3;
/*
 * 轉(zhuǎn)賬案例的業(yè)務(wù)層接口
 */
public interface AccountService {

    public void transfer(String out,String in,Double money);
}

【f】spring配置文件編寫

<?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:context="http://www.springframework.org/schema/context"  
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.xsd  
http://www.springframework.org/schema/context  
http://www.springframework.org/schema/context/spring-context.xsd  
http://www.springframework.org/schema/aop  
http://www.springframework.org/schema/aop/spring-aop.xsd  
http://www.springframework.org/schema/tx  
http://www.springframework.org/schema/tx/spring-tx.xsd">  

    <!-- 引入外部的屬性文件 --> 
    <context:property-placeholder location="classpath:jdbc.properties"/>
    
    <!-- 配置c3p0連接池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driverClassName}"></property>
        <property name="jdbcUrl" value="${jdbc.url}"></property>
        <property name="user" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
    
    <!--配置業(yè)務(wù)層類 -->
    <bean id="accountService" class="spring.demo3.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
        
    </bean>
    
    <!-- 配置DAO的類 -->
    <bean id="accountDao" class="spring.demo3.AccountDapImpl">
        <!-- 注入連接池  -->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

【g】Dao中獲取JDBC模板
首先Dao實(shí)現(xiàn)類需要繼承JdbcDaoSupport類傻咖,該類中就會(huì)注入JDBC模板,該類中定義了JDBC模板岖研,并提供set方法只要Dao中注入模板就可以卿操。也可以通過(guò)注入連接池獲取JDBC模板。
【h】Dao方法具體編寫


import org.springframework.jdbc.core.support.JdbcDaoSupport;



public class AccountDapImpl extends JdbcDaoSupport implements AccountDao {

    public void outMoney(String out, Double money) {
        // TODO Auto-generated method stub
        String sql="update acount set acount =acount - ? where name = ?";
        this.getJdbcTemplate().update(sql,money,out);

    }

    public void inMoney(String in, Double money) {
        // TODO Auto-generated method stub
        String sql="update acount set acount =acount + ? where name = ?";
        this.getJdbcTemplate().update(sql,money,in);
    }

}

【i】Service中注入Dao孙援,并調(diào)用Dao中的方法

    package spring.demo3;

import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

/*
 * 業(yè)務(wù)層實(shí)現(xiàn)類
 */
public class AccountServiceImpl implements AccountService
{
    //注入轉(zhuǎn)賬的Dao的類
    private AccountDao accountDao;
    

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }
    
    

    public void transfer( String out,  String in,  Double money) {
        
        accountDao.outMoney(out, money);
        int i=1/0;
        accountDao.inMoney(in, money);
    }

}

【k】測(cè)試:由于Junit4和spring整合的包已經(jīng)引入害淤,所以通過(guò)注解@ContextConfiguration注解加載配置文件,這里使用注解@Resource(name="")方式注入AccountService拓售。


import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/*
 * Spring的聲明事務(wù)管理的方式二:基于AspectJ的xml方式配置
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext3.xml")
public class TestDemo3 {

    @Resource(name="accountService")
    private AccountService accountService;
    @Test
    /*
     * 轉(zhuǎn)賬案例測(cè)試
     */
    public void demo3(){
        accountService.transfer("aaa", "bbb", 100d);
    }
}

聲明式事物管理方式:基于AspectJ的XML方式

【1】引入AspectJ的jar包和整合AspectJ的包窥摄。
AspectJ簡(jiǎn)介:Spring在開(kāi)發(fā)AOP時(shí),為了簡(jiǎn)化編程而建立的础淤。(AspectJ實(shí)際是開(kāi)源的崭放、第三方的AOP開(kāi)發(fā)框架,Spring為簡(jiǎn)化自身開(kāi)發(fā)鸽凶,就引入了AspectJ的包)
【2】配置事物管理器币砂,并注入數(shù)據(jù)源dataSource。

<!-- 配置事務(wù)管理器  -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

【3】配置事物的通知
(事物的增強(qiáng),通過(guò)<tx:advice id="" transaction-manager="事物管理器Id"></tx:advice>玻侥,這個(gè)標(biāo)簽中需要配置事物相關(guān)的一些屬性<tx:attributes></tx:attributes>决摧,該屬性的作用就是哪些方法執(zhí)行事務(wù),<tx:method="方法名"></tx:method>如果多個(gè)方法可以用英文單詞*,該標(biāo)簽中還定義了事物的傳播行為、隔離級(jí)別、超時(shí)信息掌桩、只讀等等屬性)

    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!--
              PROPAGATION:事務(wù)的傳播行為 
              ISOLATION:事務(wù)的隔離級(jí)別
              readOnly:只讀 
              rollback-for:發(fā)生哪些異潮咚回滾
              no-rollback-for:發(fā)生哪些異常不回滾
              timeout:過(guò)期信息
               -->
        <tx:attributes>
            <tx:method name="transfer" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

【4】配置AOP的切面
(通過(guò)<aop:config></aop:config>,在<aop:config>下需要配置切入點(diǎn)<aop:point-cut expression="" id=""></aop:point-cut>,其中表達(dá)式最前面的表示方法返回值為任意的,+號(hào)表示及其子類波岛,.表示任意的方法茅坛,(..)表示任意的參數(shù),接下來(lái)需要配置切面其中<aop:aspect>代表多個(gè)切入點(diǎn)则拷,多個(gè)通知贡蓖,而<aop:advisor>是一個(gè)切入點(diǎn),一個(gè)通知的隔躲。這里使用它即可摩梧。因?yàn)楝F(xiàn)在只有一個(gè)增強(qiáng)即事物增強(qiáng),這樣AccountService即其子類的任意方法都會(huì)事物增強(qiáng)了)

    <aop:config>
        <!--配置切入點(diǎn)  -->
        <aop:pointcut expression="execution(* spring.demo3.AccountService+.*(..))" id="pointcut1"/>
        <!-- 配置切面  -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
    </aop:config>

使用事務(wù)管理方式,一旦發(fā)生異常,整個(gè)事務(wù)不會(huì)執(zhí)行,不會(huì)出現(xiàn)錢轉(zhuǎn)丟的現(xiàn)象

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末宣旱,一起剝皮案震驚了整個(gè)濱河市仅父,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌浑吟,老刑警劉巖笙纤,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異组力,居然都是意外死亡省容,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門燎字,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)腥椒,“玉大人,你說(shuō)我怎么就攤上這事候衍×耄” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵蛉鹿,是天一觀的道長(zhǎng)滨砍。 經(jīng)常有香客問(wèn)我,道長(zhǎng)妖异,這世上最難降的妖魔是什么惋戏? 我笑而不...
    開(kāi)封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮他膳,結(jié)果婚禮上响逢,老公的妹妹穿的比我還像新娘。我一直安慰自己矩乐,他們只是感情好龄句,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布回论。 她就那樣靜靜地躺著散罕,像睡著了一般分歇。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上欧漱,一...
    開(kāi)封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天职抡,我揣著相機(jī)與錄音,去河邊找鬼误甚。 笑死缚甩,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的窑邦。 我是一名探鬼主播擅威,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼冈钦!你這毒婦竟也來(lái)了郊丛?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤瞧筛,失蹤者是張志新(化名)和其女友劉穎厉熟,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體较幌,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡揍瑟,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了乍炉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绢片。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖岛琼,靈堂內(nèi)的尸體忽然破棺而出底循,到底是詐尸還是另有隱情,我是刑警寧澤衷恭,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布此叠,位于F島的核電站,受9級(jí)特大地震影響随珠,放射性物質(zhì)發(fā)生泄漏灭袁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一窗看、第九天 我趴在偏房一處隱蔽的房頂上張望茸歧。 院中可真熱鬧,春花似錦显沈、人聲如沸软瞎。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)涤浇。三九已至鳖藕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間只锭,已是汗流浹背著恩。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蜻展,地道東北人喉誊。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像纵顾,于是被迫代替她去往敵國(guó)和親伍茄。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

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