1. 程式人生 > >spring_(24)Spring_事務傳播屬性

spring_(24)Spring_事務傳播屬性

  • 當事務方法被另一個事務方法呼叫時,必須指定事務應該如何傳播。例如:方法可能繼續在現有事務中執行,也可能開啟一個新事務,並在自己的事務彙總執行。
  • 事務的傳播行為可以由傳播屬性指定。Spring定義了7種類傳播行為

Sping支援的事務傳播行為

傳播屬性 描述
REQUIRED 如果有事務在執行,當前的方法就在這個事務內執行,否則,就啟動一個新的事務,並在自己的事務內執行。
REQUIRED_NEW 當前的方法必須啟動新事務,並在它自己的事務內執行。如果有事務正在執行,應該將它掛起。
SUPPORTS 如果有事務在執行,當前的方法就在這個事務內執行,否則它可以不執行在事務中
NOT_SUPPORTED 當前的方法不應該執行在事務中,如果有執行的事務,將它掛起
MANDATORY 當前的方法必須執行在事務內部,如果沒有正在執行的事務,就丟擲異常。
NEVER 當前的方法不應該執行在事務中。如果有執行的事務,則丟擲異常。
NESTED 如果有事務在執行,當前的方法就應該在這個事務的巢狀事務內執行。否則,就啟動一個新的事務,並在它自己的事務內執行。

在這裡插入圖片描述

REQUIRED 傳播行為

  • 當bookService的purchase()方法被另一個事務方法checkout()呼叫時,它預設會在現有的事務內執行。這個預設的傳播行為就是REQUIRED。因此在checkout()方法的開始和終止邊界內只有一個事務。這個事務只在checkout()方法結束的時候被提交,結果使用者一本書都買不了
  • 事務傳播屬性可以在@Transactional註解的propagation屬性中定義

在這裡插入圖片描述

REQUIRES_NEW 傳播行為(實現買成功一本,第二本依然失敗)

  • 另一種常見的傳播行為是REQUIRES_NEW.它表示該方法必須啟動一個新事務,並在自己的事務內執行。如果有事務在執行,就應該先掛起它。

在這裡插入圖片描述

例子程式

這裡只貼出有差別的類,其他需要的檔案均在上一篇部落格

Cashier.java

package com.spring.tx;

import java.util.List;

public interface Cashier {

    public void checkout(String username,List<String> isbns);

}

CashierImpl.java

package com.spring.tx;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service("cashier")
public class CashierImpl implements Cashier{

    @Autowired
    private BookShopService bookShopService;


    @Override
    public void checkout(String username, List<String> isbns) {
        for(String isbn : isbns ){
            bookShopService.purchase(username,isbn);
        }
    }
}

BookShopServiceImpl.java

package com.spring.tx;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service("bookShopService")
public class BookShopServiceImpl implements BookShopService{

    @Autowired
    private BookShopDao bookShopDao;

    //新增事務註解
    //使用propagation 指定事務的傳播行為,即當前的事務方法被另外一個事務方法呼叫時
    //如何使用事務,預設取值為REQUIRED,即使用呼叫方法的事務
    //REQUIRES_NEW:事務自己的事務,呼叫的事務方法的事務被掛起
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public void purchase(String username, String isbn) {
        //1.獲取書的單價
        int price = bookShopDao.findBookPriceByIsbn(isbn);

        //2.更新書的庫存
        bookShopDao.updateBookStock(isbn);

        //3.更新使用者的餘額
        bookShopDao.updateUserAccount(username,price);
    }
}

SpringTransactionTest.java

package com.spring.tx;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.Arrays;

public class SpringTransactionTest {

    private ApplicationContext ctx = null;
    private BookShopDao bookShopDao = null;
    private BookShopService bookShopService = null;
    private Cashier cashier = null;

    {
        ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        bookShopDao = ctx.getBean(BookShopDao.class);
        bookShopService = ctx.getBean(BookShopService.class);
        cashier = ctx.getBean(Cashier.class);
    }

    public void testTransactionlPropagation(){
        cashier.checkout("AA",Arrays.asList("1001","1002"));
    }


    public void testBookShopService(){
        bookShopService.purchase("AA","1001");
    }

    public  void testBookShopDaoFindPriceByIsbn(){
        System.out.println(bookShopDao.findBookPriceByIsbn("1001"));
    }

    public void testBookShopDaoUpdateUserAccount(){
        bookShopDao.updateUserAccount("AA",200);
    }

    public void testBookShopDaoUpdateBookStock(){
        bookShopDao.updateBookStock("1001");
    }


    public static void main(String[] args){

        /*new SpringTransactionTest().testBookShopDaoFindPriceByIsbn();
        new SpringTransactionTest().testBookShopDaoUpdateBookStock();
        new SpringTransactionTest().testBookShopDaoUpdateUserAccount();*/

        //
        new SpringTransactionTest().testTransactionlPropagation();

    }

}

簡單的補充:

這樣的事務使得若買兩本書的時候,錢不夠,但是依然能夠完成支付一本書,第二本書支付失敗的情況。

而上一篇部落格的情況,則會兩本書都不能支付成功。