最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java同一個類中,一個無事務方法調用一個有事務方法時,事務失效問題

 更新時間:2024年12月10日 15:22:57   作者:linab112  
本文詳細介紹了Spring框架中事務管理的實現原理,包括@Transactional注解的使用、事務的開啟、提交和回滾機制,以及代理對象的兩種實現方式(JDK動態(tài)代理和CGLIB代理),文章還探討了在同一個類中調用有事務方法時事務失效的原因,并提供了解決方法

事務的使用

在spring項目的開發(fā)中,通過在方法上添加Transactional注解,實現事務的管理,在方法開始開啟事務,出現異常進行事務的回滾,方法結束前提交事務。

事務的實現原理

Transactional 注解是 Spring 框架用來實現聲明式事務管理的重要工具。其原理主要基于 AOP(面向切面編程),通過動態(tài)代理在方法執(zhí)行前、后以及異常情況下進行事務的處理。

當你在一個方法上使用 @Transactional 注解時,Spring 會在運行時生成一個代理對象,該對象會攔截對該方法的調用。

在調用之前,代理會開始一個新的事務;在方法執(zhí)行完成后,代理會提交或回滾事務,具體取決于方法是否拋出了未處理的異常。

具體流程如下:

  • spring使用jdk動態(tài)代理技術或者cglib代理來創(chuàng)建目標類的代理對象
  • 當方法被調用時,實際上調用的是代理類中的增強方法,而不是直接調用目標類中的方法
  • 在調用方法之前,代理會根據注解的屬性(傳播行為和隔離級別)從PlatformTransactionManager中獲取一個事務,在調用目標方法前開啟事務
  • 執(zhí)行目標方法
  • 目標方法執(zhí)行成功,則提交事務,執(zhí)行失敗,則回滾事務

代理的兩種方式:

  • JDK 動態(tài)代理:當目標類實現至少一個接口時,Spring會使用JDK動態(tài)代理。這種代理僅適用于基于接口的代理。原理是通過Java反射機制,在運行時生成一個實現了目標類接口的代理類。
  • CGLIB 代理:如果目標類沒有實現任何接口,或者您強制配置為使用CGLIB,那么Spring會使用CGLIB庫生成一個目標類的子類作為代理。原理是使用CGLIB庫,通過繼承目標類并重寫其方法來實現代理。

原因

在同一個類中,一個無事務方法直接調用有事務的方法時,是通過this.方法名的方式調用。

this方式:它直接訪問的是當前對象的實現,如果當前類被Spring AOP代理,那么使用this調用的方法將不會觸發(fā)AOP切面。也就是說,切面(如事務管理、日志記錄等)不會生效,因為你直接調用了目標對象的方法,而不是代理對象的方法。

通過Autowired注解注入的bean進行調用的方式:是通過spring容器管理的代理對象進行調用,這種情況下AOP特性可以正常工作,例如事務、日志等會生效。

Spring容器管理的代理對象的生成條件和時機

在Spring中,代理對象的生成通常與AOP(面向切面編程)相關,當類上使用@Component、@Service@Repository@Controller等注解,并且方法上使用AOP相關的注解時,Spring會創(chuàng)建代理對象,以便能夠在調用這些方法時執(zhí)行切面邏輯。

常見的AOP注解包括:

  • @Transactional
  • @Cacheable
  • @Async
  • @Scheduled

事務失效代碼

package com.ruoyi.system.service.impl;

import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.system.domain.SysConfig;
import com.ruoyi.system.mapper.SysConfigMapper;
import com.ruoyi.system.mapper.SysDeptMapper;
import com.ruoyi.system.service.TestTransactionalService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @Author linaibo
 * @Date 2024/8/3 15:36
 * @Version 1.0
 */
@Service
public class TestTransactionalServiceImpl implements TestTransactionalService {

    @Autowired
    private SysDeptMapper deptMapper;

    @Autowired
    private SysConfigMapper configMapper;


    @Override
    public int insertDept(SysDept dept) {
        dept.setAncestors("123123");
        deptMapper.insertDept(dept);
        insertConfig();
        return 1;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertConfig() {
        SysConfig config;
        for (int i = 0; i < 5; i++) {
            config = new SysConfig();
            config.setConfigName("配置" + i);
            configMapper.insertConfig(config);
            if (i == 2) {
                throw new RuntimeException();
            }
        }
        return 1;
    }
}

解決方法

①自己autowire自己(也可以將方法放到另外一個service中,然后注入該service進行調用)

package com.ruoyi.system.service.impl;

import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.system.domain.SysConfig;
import com.ruoyi.system.mapper.SysConfigMapper;
import com.ruoyi.system.mapper.SysDeptMapper;
import com.ruoyi.system.service.TestTransactionalService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @Author linaibo
 * @Date 2024/8/3 15:36
 * @Version 1.0
 */
@Service
public class TestTransactionalServiceImpl implements TestTransactionalService {

    @Autowired
    private SysDeptMapper deptMapper;
    @Autowired
    private SysConfigMapper configMapper;
    @Autowired
    private TestTransactionalService testTransactionalService;


    @Override
    public int insertDept(SysDept dept) {
        dept.setAncestors("123123");
        deptMapper.insertDept(dept);
        testTransactionalService.insertConfig();
        return 1;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertConfig() {
        SysConfig config;
        for (int i = 0; i < 5; i++) {
            config = new SysConfig();
            config.setConfigName("配置" + i);
            configMapper.insertConfig(config);
            if (i == 2) {
                throw new RuntimeException();
            }
        }
        return 1;
    }
}

②通過spring上下文獲取到當前代理類

package com.ruoyi.system.service.impl;

import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.system.domain.SysConfig;
import com.ruoyi.system.mapper.SysConfigMapper;
import com.ruoyi.system.mapper.SysDeptMapper;
import com.ruoyi.system.service.TestTransactionalService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @Author linaibo
 * @Date 2024/8/3 15:36
 * @Version 1.0
 */
@Service
public class TestTransactionalServiceImpl implements TestTransactionalService {

    @Autowired
    private SysDeptMapper deptMapper;
    @Autowired
    private SysConfigMapper configMapper;
    @Autowired
    private TestTransactionalService testTransactionalService;
    @Autowired
    private ApplicationContext applicationContext;


    @Override
    public int insertDept(SysDept dept) {
        dept.setAncestors("123123");
        deptMapper.insertDept(dept);
        TestTransactionalService service = applicationContext.getBean(TestTransactionalService.class);
        service.insertConfig();
        return 1;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertConfig() {
        SysConfig config;
        for (int i = 0; i < 5; i++) {
            config = new SysConfig();
            config.setConfigName("配置" + i);
            configMapper.insertConfig(config);
            if (i == 2) {
                throw new RuntimeException();
            }
        }
        return 1;
    }
}

③使用AopContext獲取到當前代理類,需要在啟動類加上EnableAspectJAutoProxy(exposeProxy = true),exposeProxy = true用于控制AOP框架公開代理,公開后才可以通過AopContext獲取到當前代理類。

package com.ruoyi.system.service.impl;

import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.system.domain.SysConfig;
import com.ruoyi.system.mapper.SysConfigMapper;
import com.ruoyi.system.mapper.SysDeptMapper;
import com.ruoyi.system.service.TestTransactionalService;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Objects;

/**
 * @Author linaibo
 * @Date 2024/8/3 15:36
 * @Version 1.0
 */
@Service
public class TestTransactionalServiceImpl implements TestTransactionalService {

    @Autowired
    private SysDeptMapper deptMapper;
    @Autowired
    private SysConfigMapper configMapper;


    @Override
    public int insertDept(SysDept dept) {
        dept.setAncestors("123123");
        deptMapper.insertDept(dept);
        TestTransactionalService service = Objects.nonNull(AopContext.currentProxy()) ? (TestTransactionalService)AopContext.currentProxy() : this;
        service.insertConfig();
        return 1;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertConfig() {
        SysConfig config;
        for (int i = 0; i < 5; i++) {
            config = new SysConfig();
            config.setConfigName("配置" + i);
            configMapper.insertConfig(config);
            if (i == 2) {
                throw new RuntimeException();
            }
        }
        return 1;
    }
}

總結

使用 AOP 注解

  • 如果 TestTransactionalService 類上使用了 AOP 相關的注解(如 @Transactional, @Aspect, @Around 等)
  • 通過 applicationContext.getBean(TestTransactionalService.class) 獲取的對象將是一個代理對象

代理對象的創(chuàng)建是為了在方法調用前后加入額外的行為,比如事務管理、日志記錄等。

未使用 AOP 注解

  • 如果該類沒有任何 AOP 相關的注解
  • 獲取的對象就是普通的 Bean
  • 沒有經過 AOP 的增強

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

最新評論

汕尾市| 肇州县| 红原县| 女性| 柳河县| 阿巴嘎旗| 呼图壁县| 青川县| 天全县| 江源县| 卢湾区| 德昌县| 广水市| 永顺县| 林口县| 贡觉县| 习水县| 治多县| 历史| 雅江县| 晋宁县| 高阳县| 新平| 高密市| 海南省| 海晏县| 东乌| 呼和浩特市| 遵义市| 平谷区| 平舆县| 拉萨市| 枣强县| 吐鲁番市| 忻州市| 平顶山市| 那曲县| 满洲里市| 江陵县| 久治县| 西昌市|