成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Spring 事務失效了,怎么辦?

開發 項目管理
在 Spring 中,默認情況下,如果被代理的對象有接口,就使用 JDK 動態代理,如果被代理的對象沒有接口,則使用 CGLIB 動態代理。

這是小伙伴們在微信上問的一個問題:

圖片

這個問題比較典型,讓我想到面試時有一個 Spring 事務失效的問題,跟這個原因以及解決方案是一模一樣的,因此,抽空整篇文章和小伙伴們分享下。

1. AOP 的原理

小伙伴們知道,AOP 底層就是動態代理,動態代理有兩種實現方式:

  • JDK 動態代理:利用攔截器(必須實現 InvocationHandler)加上反射機制生成一個代理接口的匿名類,在調用具體方法前調用 InvokeHandler 來處理。舉個例子,假設有一個接口 A,A 有一個實現類 B,現在要給 B 生成代理對象,那么實際上是給 A 接口自動生成了一個匿名實現類,并且在這個匿名實現類中調用到 B 中的方法。
  • CGLIB 動態代理:利用 ASM 框架,對代理對象類生成的 class 文件加載進來,通過修改其字節碼生成子類來處理。舉個例子,現在有一個類 A,A 沒有接口,現在想給 A 生成一個代理對象,那么實際上是自動給 A 生成了一個子類,在這個子類中覆蓋了 A 中的方法,所以,小伙伴們要注意,A 類以及它里邊的方法不能是 final 類型的,否則無法生成代理。

如果被代理的對象有接口,則可以使用 JDK 動態代理,沒有接口就可以使用 CGLIB 動態代理。

在 Spring 中,默認情況下,如果被代理的對象有接口,就使用 JDK 動態代理,如果被代理的對象沒有接口,則使用 CGLIB 動態代理。

在 Spring Boot 中,2.0 之前也跟 Spring 中的規則一樣,2.0 之后則統一都使用 CGLIB 動態代理。

不過這些都是默認的規則,如果有接口,但是你又希望使用 CGLIB 動態代理,通過修改配置,也都是可以實現的:

如果是 XML 配置,想使用 CGLIB 動態代理,可以按如下方式實現:

<aop:config proxy-target-class="true">
<aop:pointcut id="pc1" expression="。。。"/>
<aop:aspect ref="logAdvice">
。。。
</aop:aspect>
</aop:config>

如果是 Java 配置,想使用 CGLIB 動態代理,可以按如下方式實現:

@Component
@Aspect
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class LogAspect {
}

當然,在新版 Spring Boot 項目中,有接口的類默認就是使用 CGLIB 動態代理的。但是此時如果有接口的類你又想使用 JDK 動態代理,那么可以通過如下配置:

spring.aop.proxy-target-class=false

關于 Spring Boot 中的 AOP 代理問題,可以參考去年松哥寫的文章:Spring Boot 中的 AOP,到底是 JDK 動態代理還是 Cglib 動態代理?。

2. 實際用的類

基于第一小節的講解,小伙伴們知道,當你在項目中用到了 AOP 之后,其實你所以見到的類,并不是原本的類了。

雖然是解決不同的問題,但是有一個共同的點,那就是都是通過自定義注解+ AOP 解決問題的。

現在我就以手把手教你玩多數據源動態切換!為例,來和大家說說這里的動態代理到底是咋回事,沒看過這篇文章的小伙伴可以先看下。

小伙伴們看下,我的 UserService 大致上是下面這樣:

@Service
public class UserService {

@Autowired
UserMapper userMapper;

@DS("master")
public Integer count() {
return userMapper.getCount();
}
}

小伙伴們看到,count() 方法上加了 @DS 注解,所以這個 count() 方法將來是要被自動代理的。換言之,當你在另外一個類中注入 UserService 的時候,其實不是這個 UserService,我 DEBUG 小伙伴們來看一下:

圖片

小伙伴們從圖中可以看到,此時我注入的 UserService 并不是真正的 UserService,而是一個通過 CGLIB 動態代理為 UserService 生成的子類,這個子類里邊的 count 方法大致邏輯類似下面這樣(其實就是 AOP 中的代碼,具體小伙伴們可以參考 手把手教你玩多數據源動態切換!一文):

# 切換數據源
# 去數據庫查詢 count
# 清空 ThreadLocal 中的變量
# ...

但是,如果我的調用邏輯是這樣呢:

@Service
public class UserService {

@Autowired
UserMapper userMapper;

public Integer count2() {
return count();
}

@DS("master")
public Integer count() {
return userMapper.getCount();
}
}

小伙伴們來看,count2 方法,這個時候直接在 count2 方法中調用了 count 方法,當然,count2() 方法中的調用也可以寫作 this.count();,這樣看起來就更明確了,我們調用 count 方法,使用的是當前對象,而當前對象是不包含代理對象中的代碼的,我們通過 DEBUG 來看下:

圖片

所以,當我們在 count2 中直接調用 count 方法的時候,那么加在 count 方法上的注解就會失效。

3. 問題解決

這個問題存在于所有使用了 AOP 的地方,存在的原因第二小節已經分析的很清楚了。

解決辦法其實也有很多種,最為簡單省事的一種,就是在當前類中注入代理對象,然后通過代理對象去調用其他方法,如下:

@Service
public class UserService {

@Autowired
UserMapper userMapper;

@Autowired
UserService userService;

public Integer count2() {
return userService.count();
}

@Transactional
@DS("master")
public Integer count() {
return userMapper.getCount();
}

}

圖片

雖然問題解決了,不過這畢竟不是一個好的解決辦法(因為自己中注入自己,在新版 Spring Boot 中要開啟循環依賴才能實現),大家在實際開發中,還是要從設計上盡量避免這種問題。

好啦,這個問題搞明白了,那么事務失效這個問題,也不用我多說了吧!

責任編輯:武曉燕 來源: 江南一點雨
相關推薦

2022-12-19 11:31:57

緩存失效數據庫

2009-11-03 08:56:02

linux死機操作系統

2022-07-05 11:48:47

MySQL死鎖表鎖

2022-10-14 08:18:07

Guavaweb應用

2011-11-18 10:52:00

2011-11-16 10:02:48

DNSDNS記錄DNS記錄消失

2023-12-25 08:22:02

2018-01-30 15:08:05

2021-01-05 10:48:38

RedisAOF日志RDB快照

2020-07-10 08:46:26

HTTPS證書劫持網絡協議

2024-08-06 08:08:14

2022-02-14 16:53:57

Spring項目數據庫

2020-02-24 11:02:37

斷網網絡故障

2013-02-18 09:19:11

谷歌X PhoneNexus

2024-07-29 08:01:32

2024-08-06 12:29:23

2022-10-21 08:17:06

開源項目閉源

2021-09-04 07:56:44

Spring事務失效

2022-04-13 20:53:15

Spring事務管理

2018-08-15 15:20:00

Windows電腦藍屏錯誤代碼
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 黄色成人在线观看 | 国产精品99免费视频 | 羞羞视频网页 | 成人免费视频观看视频 | 亚洲精品久久久久国产 | 一级一级一级毛片 | 精品久久久久久久久久久 | 亚洲 日本 欧美 中文幕 | 久久国产精品免费一区二区三区 | 亚洲天堂网站 | 丁香婷婷成人 | 国产精品视频在线免费观看 | 国产精品一区二区三区免费观看 | 亚洲欧美日韩电影 | 午夜精品网站 | 亚洲69p| 国产一区二区三区在线看 | 亚洲精彩免费视频 | 91文字幕巨乱亚洲香蕉 | 超碰在线97国产 | 欧美韩一区二区三区 | 免费看黄色片 | 中国一级大毛片 | 请别相信他免费喜剧电影在线观看 | www.亚洲| 欧美精品久久久久久 | 午夜影院在线观看 | 男人天堂国产 | 精品中文在线 | 一级片免费视频 | 99久久精品国产一区二区三区 | 狠狠婷婷综合久久久久久妖精 | 国产精品视频在线播放 | 亚洲精品乱码久久久久久按摩观 | www.av7788.com| 中文字幕精品一区 | 国产精品国产成人国产三级 | 亚洲 自拍 另类 欧美 丝袜 | 91久久精品国产91久久 | 2020亚洲天堂| 久久亚洲精品久久国产一区二区 |