Spring事務(wù)

一. 事務(wù)特性ACID

  • 原子性
  • 一致性
  • 隔離性
  • 持久性

二. 事務(wù)管理器

Spring并不直接管理事務(wù),而是提供事務(wù)管理器接口,讓框架自己(包括JDBC、hibernate、JPA、JTA等)實(shí)現(xiàn)具體的事務(wù)管理。

2.1 spring提供的事務(wù)管理器接口

包括3個(gè)接口:獲取事務(wù)狀態(tài)、提交、回滾

package org.springframework.transaction;

public interface PlatformTransactionManager {
    TransactionStatus getTransaction(TransactionDefinition var1) throws TransactionException;

    void commit(TransactionStatus var1) throws TransactionException;

    void rollback(TransactionStatus var1) throws TransactionException;
}

2.2 具體實(shí)現(xiàn)(以JDBC為例)

DataSourceTransactionManager通過(guò)DataSource獲取到j(luò)ava.sql.Connection,再調(diào)用java.sql.Connection來(lái)管理事務(wù)

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="具體數(shù)據(jù)源"></property>
</bean>

<tx:annotation-driven transaction-manager="transactionManager"/>

三. 事務(wù)基本屬性

上文提到的spring事務(wù)管理器接口中,用于獲取事務(wù)狀態(tài)的getTransaction方法參數(shù)定義了一個(gè)事務(wù)的基本屬性

TransactionStatus getTransaction(TransactionDefinition var1)

事務(wù)基本屬性包括5類(lèi):

  • 傳播行為
  • 隔離級(jí)別
  • 是否只讀
  • 超時(shí)時(shí)間
  • 回滾規(guī)則
public interface TransactionDefinition {

    int getPropagationBehavior();

    int getIsolationLevel();

    int getTimeout();

    boolean isReadOnly();

    String getName();
}

3.1 傳播行為 PROPAGATION

定義一個(gè)事務(wù)被另一個(gè)事務(wù)調(diào)用時(shí),兩個(gè)事務(wù)之間的關(guān)系,如:被調(diào)用事務(wù)合并到調(diào)用事務(wù)中運(yùn)行,或者獨(dú)立開(kāi)啟一個(gè)新事務(wù)運(yùn)行等。

Spring定義了七種傳播行為:

  • require_new(本身執(zhí)行時(shí)是事務(wù),被事務(wù)調(diào)用時(shí)也不合并為同一個(gè)事務(wù))
  • require(本身執(zhí)行時(shí)是事務(wù),被事務(wù)調(diào)用時(shí)可合并在同一個(gè)事務(wù)里)
  • support(本身執(zhí)行時(shí)不是事務(wù),被事務(wù)調(diào)用時(shí)可合并在同一個(gè)事務(wù)里)
  • not_support(總是非事務(wù)地執(zhí)行,并掛起任何存在的事務(wù))
  • mandatory(本身執(zhí)行時(shí)拋出異常,被事務(wù)調(diào)用時(shí)可合并在同一個(gè)事務(wù)里)
  • never(總是非事務(wù)地執(zhí)行,如果被其它事務(wù)調(diào)用則拋出異常)
  • nest(嵌套事務(wù),本身執(zhí)行時(shí)是事務(wù),被事務(wù)調(diào)用時(shí)也不合并為同一+ 個(gè)事務(wù),但是外層事務(wù)失敗時(shí)內(nèi)層事務(wù)也要回滾)

3.2 隔離級(jí)別

定義了一個(gè)事務(wù)可能受其他并發(fā)事務(wù)影響的程度

1.并發(fā)事務(wù)問(wèn)題:

  • 臟讀(一個(gè)事務(wù)讀取了另一個(gè)事務(wù)改寫(xiě)但尚未提交的數(shù)據(jù)時(shí),改寫(xiě)在稍后被回滾了,那么第一個(gè)事務(wù)獲取的數(shù)據(jù)就是無(wú)效的)
  • 不可重復(fù)讀
  • 幻讀(事務(wù)T1讀取了幾行數(shù)據(jù),接著另一個(gè)并發(fā)事務(wù)T2插入了一些數(shù)據(jù),故在隨后的查詢(xún)中,事務(wù)T1就會(huì)發(fā)現(xiàn)多了一些原本不存在的記錄)

不可重復(fù)讀的重點(diǎn)是同一個(gè)數(shù)據(jù)被修改了,幻讀的重點(diǎn)在于有數(shù)據(jù)新增或者刪除。

從結(jié)果看, 似乎不可重復(fù)讀和幻讀都表現(xiàn)為兩次讀取的結(jié)果不一致。但如果從控制的角度來(lái)看, 兩者的區(qū)別就比較大:

  • 對(duì)于前者, 只需要鎖住滿(mǎn)足條件的記錄
  • 對(duì)于后者, 要鎖住滿(mǎn)足條件及其相近的記錄

2.隔離級(jí)別

  • defaul(使用數(shù)據(jù)庫(kù)默認(rèn)隔離級(jí)別)
  • read_uncommit(允許讀取未commit數(shù)據(jù),會(huì)導(dǎo)致上面3種問(wèn)題)
  • read_commit(允許讀取commit數(shù)據(jù),僅可避免臟讀)
  • repeatable_read(數(shù)據(jù)只可被自身事務(wù)修改,可避免臟讀、不可重復(fù)讀)
  • Serializable(完全滿(mǎn)足ACID,通常是鎖表實(shí)現(xiàn))

3.3 是否只讀

如果事務(wù)只對(duì)數(shù)據(jù)庫(kù)進(jìn)行讀操作,則數(shù)據(jù)庫(kù)可以進(jìn)行一些特定的優(yōu)化。通過(guò)將事務(wù)設(shè)置為只讀,你就可以給數(shù)據(jù)庫(kù)一個(gè)機(jī)會(huì),讓它應(yīng)用它認(rèn)為合適的優(yōu)化措施。

3.4 超時(shí)時(shí)間

事務(wù)超時(shí)就是事務(wù)的一個(gè)定時(shí)器,在特定時(shí)間內(nèi)事務(wù)如果沒(méi)有執(zhí)行完畢,那么就會(huì)自動(dòng)回滾,而不是一直等待其結(jié)束。

3.5 回滾規(guī)則

默認(rèn)情況下,事務(wù)只有遇到運(yùn)行期異常時(shí)才會(huì)回滾,而在遇到檢查型異常時(shí)不會(huì)回滾(這一行為與EJB的回滾行為是一致的)

但是你可以聲明事務(wù)在遇到特定的檢查型異常時(shí)像遇到運(yùn)行期異常那樣回滾。同樣,你還可以聲明事務(wù)遇到特定的異常不回滾,即使這些異常是運(yùn)行期異常。

四. spring事務(wù)實(shí)現(xiàn)方式

  • 編程式事務(wù)(侵入到業(yè)務(wù)代碼里,但提供了更加詳細(xì)的事務(wù)管理)
  • 聲明式事務(wù)(基于A(yíng)OP,不影響業(yè)務(wù)代碼的具體實(shí)現(xiàn))

4.1 編程式事務(wù)

  • 使用TransactionTemplate
  • 直接使用PlatformTransactionManager

4.2 聲明式事務(wù)

  • 每個(gè)Bean都有一個(gè)代理
  • 所有Bean共享一個(gè)代理基類(lèi)
  • 使用攔截器
  • 使用tx標(biāo)簽配置的攔截器
  • 全注解

4.3 demo(聲明式事務(wù),全注解方式)

使用@Transactional注解

/**
     * 1.propagation 指定事務(wù)的傳播行為
     * 默認(rèn)取值為REQUIRED,即使用調(diào)用方法的事務(wù)
     * 設(shè)置為REQUIRES_NEW,即使用自己的事務(wù),調(diào)用方法的事務(wù)被掛起
     * 2.isolation 指定事務(wù)的隔離級(jí)別,最常用的取值為READ_COMMITTED
     * 3.Spring 的聲明式事務(wù)默認(rèn)對(duì)所有運(yùn)行時(shí)異常進(jìn)行回滾,也可以通過(guò)對(duì)應(yīng)的屬性進(jìn)行自行設(shè)置
     * 4.readOnly 指定事務(wù)是否為只讀,若這個(gè)事務(wù)只讀取數(shù)據(jù)則設(shè)置為true,可幫助數(shù)據(jù)庫(kù)引擎優(yōu)化事務(wù)
     * 5.timeOut 指定強(qiáng)制回滾之前事務(wù)可以占用的時(shí)間
     */
    @Transactional(propagation=Propagation.REQUIRES_NEW,
            isolation=Isolation.READ_COMMITTED,
            noRollbackFor={UserAccountException.class},
            readOnly=true, timeout=3)
    @Override
    public void purchase(String username, String isbn) {
        //1.獲取書(shū)的單價(jià)
        int price = bookShopDao.findBookPriceByIsbn(isbn);
        //2.更新書(shū)的庫(kù)存
        bookShopDao.updateBookStock(isbn);
        //3.更新用戶(hù)余額
        bookShopDao.updateUserAccount(username, price);
    }

測(cè)試事務(wù)的傳播行為

@Transactional
    @Override
    public void checkout(String username, List<String> isbns) {
        for(String isbn : isbns) {
            bookShopService.purchase(username, isbn);
        }
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容