日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

spring同类调用事务不生效-原因及三种解决方式

發布時間:2024/1/23 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 spring同类调用事务不生效-原因及三种解决方式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

spring提供的聲明式事務注解@Transactional,極大的方便了開發者管理事務,無需手動編寫開啟、提交、回滾事務的代碼。
但是也帶來了一些隱患,如果注解使用不當,可能導致事務不生效,最終導致臟數據也入庫。

如果在同一個類直接調用事務方法,就會導致事務不生效,示例如下

?

public class StudentServiceImpl implements StudentService {@Autowiredprivate StudentMapper studentMapper;@Overridepublic void insertStudent(){insert();}@Transactional(rollbackFor = Exception.class)public void insert() {StudentDO studentDO = new StudentDO();studentDO.setName("小民");studentDO.setAge(22);studentMapper.insert(studentDO);if (studentDO.getAge() > 18) {throw new RuntimeException("年齡不能大于18歲");}} }

?

事務不生效的原因在于,spring基于AOP機制實現事務的管理,@Authwired StudentService studentService這樣的方式,調用StudentService的方法時,實際上是通過StudentService的代理類調用StudentService的方法,代理類在執行目標方法前后,加上了事務管理的代碼。

image.png

?

因此,只有通過注入的StudentService調用事務方法,才會走代理類,才會執行事務管理;如果在同類直接調用,沒走代理類,事務就無效。
注意:除了@Transactional,@Async同樣需要代理類調用,異步才會生效

?

但是在實際的業務場景中,同類調用事務方法難以避免,怎么讓同類調用時事務依然生效呢?有以下三個方法

方法一

自己@Autowired自己,示例如下

?

@Service public class StudentServiceImpl implements StudentService {@Autowiredprivate StudentMapper studentMapper;@Autowiredprivate StudentService studentService;@Overridepublic void insertStudent(){studentService.insert();}@Override@Transactional(rollbackFor = Exception.class)public void insert() {StudentDO studentDO = new StudentDO();studentDO.setName("小民");studentDO.setAge(22);studentMapper.insert(studentDO);if (studentDO.getAge() > 18) {throw new RuntimeException("年齡不能大于18歲");}} }

可能有人會擔心這樣會有循環依賴的問題,事實上,spring通過三級緩存解決了循環依賴的問題,所以上面的寫法不會有循環依賴問題。
但是!!!,這不代表spring永遠沒有循環依賴的問題(@Async導致循環依賴了解下)

?

方法二

使用AopContext獲取到當前代理類,需要在啟動類加上@EnableAspectJAutoProxy(exposeProxy = true),
示例如下

?

@Service public class StudentServiceImpl implements StudentService {@Autowiredprivate StudentMapper studentMapper;@Overridepublic void insertStudent(){getService().insert();}@Override@Transactional(rollbackFor = Exception.class)public void insert() {StudentDO studentDO = new StudentDO();studentDO.setName("小民");studentDO.setAge(22);studentMapper.insert(studentDO);if (studentDO.getAge() > 18) {throw new RuntimeException("年齡不能大于18歲");}}/*** 通過AopContext獲取代理類* @return StudentService代理類*/private StudentService getService(){return Objects.nonNull(AopContext.currentProxy()) ? (StudentService)AopContext.currentProxy() : this;} }

exposeProxy = true用于控制AOP框架公開代理,公開后才可以通過AopContext獲取到當前代理類。(默認情況下不會公開代理,因為會降低性能)
注意:不能保證這種方式一定有效,使用@Async時,本方式可能失效。
(從@Async案例找到Spring框架的bug:exposeProxy=true不生效原因大剖析)

image.png

?

?

方式三(推薦)

通過spring上下文獲取到當前代理類,示例如下

?

@Component public class SpringBeanUtil implements ApplicationContextAware {private static ApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}/*** 通過class獲取Bean* @param clazz class* @param <T> 泛型* @return bean*/public static <T> T getBean(Class<T> clazz) {return applicationContext.getBean(clazz);} }

?

@Service public class StudentServiceImpl implements StudentService {@Autowiredprivate StudentMapper studentMapper;@Overridepublic void insertStudent(){StudentService bean = SpringBeanUtil.getBean(StudentService.class);if (null != bean) {bean.insert();}}@Override@Transactional(rollbackFor = Exception.class)public void insert() {StudentDO studentDO = new StudentDO();studentDO.setName("小民");studentDO.setAge(22);studentMapper.insert(studentDO);if (studentDO.getAge() > 18) {throw new RuntimeException("年齡不能大于18歲");}} }

當一個類實現ApplicationContextAware接口后,就可以方便的獲得ApplicationContext中的所有bean。



作者:修行者12138
鏈接:https://www.jianshu.com/p/083605986c8f
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

總結

以上是生活随笔為你收集整理的spring同类调用事务不生效-原因及三种解决方式的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。