天天看點

Spring 事務失效的原因

目錄

一、方法使用try/catch。

二、同類中方法的互相調用。

一、方法使用try/catch。

      失效代碼

@Override
	@Transactional
	public RrcResponse addShopingCart(AddShopingCartModel addShopingCartModel) {
		RrcResponse response = new RrcResponse(CodeMsg.SUCCESS);
		//校驗參數
		OrderCart cart = OrderTransfModel.getOrderCart(addShopingCartModel);
		if (!validateForInsert(cart)) {
			return new RrcResponse(CodeMsg.POC_ERROR_PARAMETER);
		}
		try {
			cart.setStatus(ConstantsEnum.ORDERCART_STATUS_ADD.getIndexInt());
			EntityUtils.setCreatAndUpdatInfo(cart);
	        mapper.insertSelective(cart);
			int i = 1/0;
		} catch (Exception e) {
			return new RrcResponse(CodeMsg.POC_ERROR_ADDCART);
		}
		
		return response;
	}
           

      失效原因:被攔截的方法需顯式抛出異常,并不能經任何處理,這樣aop代理才能捕獲到方法的異常,才能進行復原,預設情況下aop隻捕獲runtimeexception的異常。

      解決方案

       1.在catch中手動throw new 你的異常。

throw new RuntimeException();
           

       2.手動執行復原。

try {
			cart.setStatus(ConstantsEnum.ORDERCART_STATUS_ADD.getIndexInt());
			EntityUtils.setCreatAndUpdatInfo(cart);
	        mapper.insertSelective(cart);
			int i = 1/0;
		} catch (Exception e) {
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			return new RrcResponse(CodeMsg.POC_ERROR_ADDCART);
		}
           

二、同類中方法的互相調用。

       失效代碼

@Service
public class TestService {
 
	@Override
	public RrcResponse addShopingCart(AddShopingCartModel addShopingCartModel) {
		RrcResponse response = new RrcResponse(CodeMsg.SUCCESS);
		test(cart);
		int i = 1/0;
		return response;
	}

	@Transactional
	public void test(OrderCart cart) {
		EntityUtils.setCreatAndUpdatInfo(cart);
        mapper.insertSelective(cart);
	}
}
           

      生效代碼 注解互換位置 或另外加一個service調用 不在同一類當中

@Service
public class TestService {
 
	@Override
    @Transactional
	public RrcResponse addShopingCart(AddShopingCartModel addShopingCartModel) {
		RrcResponse response = new RrcResponse(CodeMsg.SUCCESS);
		test(cart);
		int i = 1/0;
		return response;
	}

	public void test(OrderCart cart) {
		EntityUtils.setCreatAndUpdatInfo(cart);
        mapper.insertSelective(cart);
	}
}
           

      原因說明 動态代理的緣故(這裡是轉載的:https://blog.csdn.net/qq_34021712/article/details/75949779)

1.在需要事務管理的地方加@Transactional 注解。@Transactional 注解可以被應用于接口定義和接口方法、類定義和類的 public 方法上。

[email protected] 注解隻能應用到 public 可見度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不會報錯, 但是這個被注解的方法将不會展示已配置的事務設定。

3.注意僅僅 @Transactional 注解的出現不足于開啟事務行為,它僅僅 是一種中繼資料。必須在配置檔案中使用配置元素,才真正開啟了事務行為。(spring配置檔案中,開啟聲明式事務)

4.通過 元素的 “proxy-target-class” 屬性值來控制是基于接口的還是基于類的代理被建立。如果 “proxy-target-class” 屬值被設定為 “true”,那麼基于類的代理将起作用(這時需要CGLIB庫cglib.jar在CLASSPATH中)。如果 “proxy-target-class” 屬值被設定為 “false” 或者這個屬性被省略,那麼标準的JDK基于接口的代理将起作用。

5.Spring團隊建議在具體的類(或類的方法)上使用 @Transactional 注解,而不要使用在類所要實作的任何接口上。在接口上使用 @Transactional 注解,隻能當你設定了基于接口的代理時它才生效。因為注解是 不能繼承 的,這就意味着如果正在使用基于類的代理時,那麼事務的設定将不能被基于類的代理所識别,而且對象也将不會被事務代理所包裝。

[email protected]的事務開啟 ,或者是基于接口的 或者是基于類的代理被建立。是以在同一個類中一個無事務的方法調用另一個有事務的方法,事務是不會起作用的。