91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring @Transactional注解失效解決方案

發布時間:2020-10-16 18:23:05 來源:腳本之家 閱讀:183 作者:myseries 欄目:編程語言

這篇文章主要介紹了Spring @Transactional注解失效解決方案,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下

這幾天在項目里面發現我使用@Transactional注解事務之后,拋了異常居然不回滾。后來終于找到了原因。
如果你也出現了這種情況,可以從下面開始排查。

一、特性

先來了解一下@Transactional注解事務的特性吧,可以更好排查問題

1、service類標簽(一般不建議在接口上)上添加@Transactional,可以將整個類納入spring事務管理,在每個業務方法執行時都會開啟一個事務,不過這些事務采用相同的管理方式。

2、@Transactional 注解只能應用到 public 可見度的方法上。 如果應用在protected、private或者 package可見度的方法上,也不會報錯,不過事務設置不會起作用。

3、默認情況下,Spring會對unchecked異常進行事務回滾;如果是checked異常則不回滾。
辣么什么是checked異常,什么是unchecked異常

java里面將派生于Error或者RuntimeException(比如空指針,1/0)的異常稱為unchecked異常,其他繼承自java.lang.Exception得異常統稱為Checked Exception,如IOException、TimeoutException等

辣么再通俗一點:你寫代碼出現的空指針等異常,會被回滾,文件讀寫,網絡出問題,spring就沒法回滾了。然后我教大家怎么記這個,因為很多同學容易弄混,你寫代碼的時候有些IOException我們的編譯器是能夠檢測到的,說以叫checked異常,你寫代碼的時候空指針等死檢測不到的,所以叫unchecked異常。這樣是不是好記一些啦

4、只讀事務:

@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)

只讀標志只在事務啟動時應用,否則即使配置也會被忽略。

啟動事務會增加線程開銷,數據庫因共享讀取而鎖定(具體跟數據庫類型和事務隔離級別有關)。通常情況下,僅是讀取數據時,不必設置只讀事務而增加額外的系統開銷。

二:事務傳播模式

Propagation枚舉了多種事務傳播模式,部分列舉如下:

1、REQUIRED(默認模式):業務方法需要在一個容器里運行。如果方法運行時,已經處在一個事務中,那么加入到這個事務,否則自己新建一個新的事務。

2、NOT_SUPPORTED:聲明方法不需要事務。如果方法沒有關聯到一個事務,容器不會為他開啟事務,如果方法在一個事務中被調用,該事務會被掛起,調用結束后,原先的事務會恢復執行。

3、REQUIRESNEW:不管是否存在事務,該方法總匯為自己發起一個新的事務。如果方法已經運行在一個事務中,則原有事務掛起,新的事務被創建。

4、 MANDATORY:該方法只能在一個已經存在的事務中執行,業務方法不能發起自己的事務。如果在沒有事務的環境下被調用,容器拋出例外。

5、SUPPORTS:該方法在某個事務范圍內被調用,則方法成為該事務的一部分。如果方法在該事務范圍外被調用,該方法就在沒有事務的環境下執行。

6、NEVER:該方法絕對不能在事務范圍內執行。如果在就拋例外。只有該方法沒有關聯到任何事務,才正常執行。

7、NESTED:如果一個活動的事務存在,則運行在一個嵌套的事務中。如果沒有活動事務,則按REQUIRED屬性執行。它使用了一個單獨的事務,這個事務擁有多個可以回滾的保存點。內部事務的回滾不會對外部事務造成影響。它只對DataSourceTransactionManager事務管理器起效。

三:解決Transactional注解不回滾

1、檢查你方法是不是public的

2、你的異常類型是不是unchecked異常
如果我想check異常也想回滾怎么辦,注解上面寫明異常類型即可

@Transactional(rollbackFor=Exception.class) 

類似的還有norollbackFor,自定義不回滾的異常

3、數據庫引擎要支持事務,如果是MySQL,注意表要使用支持事務的引擎,比如innodb,如果是myisam,事務是不起作用的

4、是否開啟了對注解的解析

<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>

5、spring是否掃描到你這個包,如下是掃描到org.test下面的包

<context:component-scan base-package="org.test" ></context:component-scan>

6、檢查是不是同一個類中的方法調用(如a方法調用同一個類中的b方法)

7、異常是不是被你catch住了

問題: 為什么方法修飾符不是public就會出現事務注解失效?

這幾天,同事遇到一個問題,方向Aop 切入Controller,打請求日志,結果調Service層的方法報空指針錯誤,由于是service沒有注入進來。用了@Autowired和@Resource注解都注入不進來。一行一行的檢查代碼,都沒有發現錯誤,后來只能一個方法一個方法的刪除,看到哪里可以運行,結果發現是因為Controller方法是private私有類型的。后來改了成public就可以了。

貌似不能攔截私有方法?

試了很多次,都失敗了,是不是不行啊?

我想了一下,因為aop底層是代理,

jdk是代理接口,私有方法必然不會存在在接口里,所以就不會被攔截到;

cglib是子類,private的方法照樣不會出現在子類里,也不能被攔截。

我不是類內部直接調用方法,而是通過維護一個自身實例的代理

execution(* test.aop.ServiceA.*(..))

public class ServiceA { 
 
  private ServiceA self; 
 
  public void setSelf(ServiceA self) { 
    this.self = self; 
  } 
 
  public String methodA(String str) { 
    System.out.println("methodA: args=" + str); 
    self.methodB("b"); 
    return "12345" + str; 
  } 
 
  private String methodB(String str) { 
    System.out.println("methodB: args=" + str); 
    self.methodC("c"); 
    return "12345" + str; 
  } 
 
  public String methodC(String str) { 
    System.out.println("methodC: args=" + str); 
    return "12345" + str; 
  } 
}

是不是這么回事?
但是stackoverflow上,有人說 it works fine

execution(public * test.aop.ServiceA.*(..))

還有個奇怪的現象,execution里如果不寫權限,那么public protected package的方法都能被攔截到

如果寫了public,那就只攔截public方法這個沒問題,

如果寫了protected,他就什么事情都不做,連protected的方法也不攔截。

分析

private方法 在Spring使用純Spring AOP(只能攔截public/protected/包)都是無法被攔截的 因為子類無法覆蓋;包級別能被攔截的原因是,如果子類和父類在同一個包中是能覆蓋的。

在cglib代理情況下, execution(* *(..)) 可以攔截 public/protected/包級別方法(即這些方法都是能代理的)。

private static boolean isOverridable(Method method, Class targetClass) { 
    if (Modifier.isPrivate(method.getModifiers())) { 
      return false; 
    } 
    if (Modifier.isPublic(method.getModifiers()) || Modifier.isProtected(method.getModifiers())) { 
      return true; 
    } 
    return getPackageName(method.getDeclaringClass()).equals(getPackageName(targetClass)); 
  }

如果想要實現攔截private方法的 可以使用 原生 AspectJ 編譯期/運行期織入。

引用

如果寫了protected,他就什么事情都不做,連protected的方法也不攔截;這個應該不會

原因基本分析明白了:

是否能應用增強的判斷代碼如下(org.springframework.aop.support.AopUtils):

public static boolean canApply(Pointcut pc, Class targetClass, boolean hasIntroductions) { 
  if (!pc.getClassFilter().matches(targetClass)) { 
    return false; 
  } 
 
  MethodMatcher methodMatcher = pc.getMethodMatcher(); 
  IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null; 
  if (methodMatcher instanceof IntroductionAwareMethodMatcher) { 
    introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher; 
  } 
 
  Set classes = new HashSet(ClassUtils.getAllInterfacesForClassAsSet(targetClass)); 
  classes.add(targetClass); 
  for (Iterator it = classes.iterator(); it.hasNext();) { 
    Class clazz = (Class) it.next(); 
    Method[] methods = clazz.getMethods(); 
    for (int j = 0; j < methods.length; j++) { 
      if ((introductionAwareMethodMatcher != null && 
          introductionAwareMethodMatcher.matches(methods[j], targetClass, hasIntroductions)) || 
          methodMatcher.matches(methods[j], targetClass)) { 
        return true; 
      } 
    } 
  } 
  return false; 
}

此處Method[] methods = clazz.getMethods();只能拿到public方法。。

場景1:execution(* *(..))

public class Impl2 { 
  protected/public String testAop2() { 
    System.out.println("234"); 
    return "1233"; 
  } 
}

因為切入點沒有訪問修飾符,即可以是任意,因此canApply方法能拿到如wait這種public方法,即可以實施代理。

場景2:execution(public * *(..))

public class Impl2 { 
   
  public String testAop2() { 
    System.out.println("234"); 
    return "1233"; 
  } 
}

因為攔截public的,因此canApply方法能拿到如wait這種public方法,即可以實施代理。

場景3:execution(protected * *(..))

public class Impl2 { 
   
  protected String testAop2() { 
    System.out.println("234"); 
    return "1233"; 
  } 
}

還記得之前說過,在canApply方法中 的 Method[] methods = clazz.getMethods();只能拿到public方法的,因此跟protected訪問修飾符是無法匹配的,所以如果“execution(protected * *(..))” 是 無法代理的。

這就是為什么execution(protected * *(..))在純Spring AOP環境下不行的原因。

注,@Transactional注解事務的特殊情況:

引用

方法的可見度和 @Transactional

在使用代理的時候,@Transactional 注解應該只被應用到 public 可見度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,系統也不會報錯, 但是這個被注解的方法將不會執行已配置的事務設置。如果你非要注解非公共方法的話,請參考使用AspectJ

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

东方市| 福建省| 许昌市| 长宁县| 海伦市| 永州市| 林甸县| 德兴市| 鄂托克旗| 积石山| 巴林左旗| 万宁市| 新和县| 玉环县| 平山县| 承德市| 资溪县| 伊宁市| 长白| 白水县| 静宁县| 中西区| 白朗县| 徐汇区| 高淳县| 铅山县| 左云县| 清新县| 乌拉特后旗| 搜索| 当雄县| 涪陵区| 夏邑县| 凉城县| 闻喜县| 高雄市| 郯城县| 廊坊市| 津市市| 法库县| 江北区|