spring_(24)Spring_事務傳播屬性
阿新 • • 發佈:2018-12-09
- 當事務方法被另一個事務方法呼叫時,必須指定事務應該如何傳播。例如:方法可能繼續在現有事務中執行,也可能開啟一個新事務,並在自己的事務彙總執行。
- 事務的傳播行為可以由傳播屬性指定。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();
}
}
簡單的補充:
這樣的事務使得若買兩本書的時候,錢不夠,但是依然能夠完成支付一本書,第二本書支付失敗的情況。
而上一篇部落格的情況,則會兩本書都不能支付成功。