Fork me on GitHub

Spring事物this调用当前类中的带事务方法导致事物失效

ApplicationContext获取代理后的当前类

调用当前类的事物方法时,如果使用this会导致获取的MainService这个对象本身,而非事物AOP后的MainService代理对象,所以一定要用ApplicationContext从IOC容器中获取。

MainService事务调用A和B方法

package com.example.transactiondemo.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationManager;

@Service
public class MainService {

    @Autowired
    private AService aService;

    @Autowired
    private BService bService;

    @Autowired
    private ApplicationContext applicationContext;

    /**
     * this.processAB(String data, String log);不会使用事物
     */
    @Transactional(rollbackFor = Exception.class)
    public void processMain(String data, String log) {
        //这里一定不能使用this调用!!!this会导致获取的MainService这个对象,而非AOP后的MainService代理对象
        //this.processAB(String data, String log);

        //需要通过ApplicationContext从IOC容器中获取AOP代理后的对象
        MainService mainService = applicationContext.getBean(MainService.class);
        mainService.
    }

    /**
     * 使用 ApplicationContext 获取代理对象或者直接使用DI注入的对象,保证事务生效
     */
    @Transactional(rollbackFor = Exception.class)
    public void processAB(String data, String log) {
        System.out.println("Main类事务名称(代理调用):" + TransactionSynchronizationManager.getCurrentTransactionName());

        // 通过IOC获取 A 和 B 的代理对象
        //AService aService = applicationContext.getBean(AService.class);
        //BService bService = applicationContext.getBean(BService.class);

        //或者直接使用DI注入的对象
        aService.saveOrUpdate(data);
        bService.saveLog(log);
    }


}

A类

package com.example.transactiondemo.service;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class AService {

    //@Transactional(rollbackFor = Exception.class) save(insert或者update)不需要事物
    public void saveOrUpdate(String data) {
        System.out.println("A类事务名称:" + org.springframework.transaction.support.TransactionSynchronizationManager.getCurrentTransactionName());
        System.out.println("A类保存或更新数据:" + data);

        // 模拟抛出异常
        if ("errorA".equals(data)) {
            throw new RuntimeException("A类抛出异常,事务回滚!");
        }
    }
}

B类

package com.example.transactiondemo.service;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class BService {

    //@Transactional(rollbackFor = Exception.class) 单个insert不用事物
    public void saveLog(String log) {
        System.out.println("B类事务名称:" + org.springframework.transaction.support.TransactionSynchronizationManager.getCurrentTransactionName());
        System.out.println("B类插入日志:" + log);

        // 模拟抛出异常
        if ("errorB".equals(log)) {
            throw new RuntimeException("B类抛出异常,事务回滚!");
        }
    }
}

Spring中事务测试代码

建立两张事务测试表

CREATE TABLE trancation_a (
     id INT AUTO_INCREMENT PRIMARY KEY,
     ta INT NOT NULL
);

CREATE TABLE trancation_b (
     id INT AUTO_INCREMENT PRIMARY KEY,
     tb INT NOT NULL
);

Spring代码

    @Autowired
    private JdbcTemplate jdbcTemplate;

    /**
     * 事务处理A和B
     * 只需要在这个方法上添加即可,不需要在trancationA()和trancationB()上分别加事务
     * 注意:如果调用processAB()方法是在当前类中,则也需要使用applicationContext对象获取当前类的代理对象
     */
    @Transactional(rollbackFor = Exception.class)
    public void processAB() throws Exception {
        MqttLeakageFactory proxy = applicationContext.getBean(MqttLeakageFactory.class);
        proxy.trancationA();
        proxy.trancationB();
    }

    /**
     * 操作A
     * 单条表操作语句不用加事务
     */
    public void trancationA() {
        // Insert into table a
        String insertA = "INSERT INTO trancation_a (ta) VALUES (11111)";
        jdbcTemplate.update(insertA);
    }

    /**
     * 操作B
     * 单条表操作语句不用加事务
     */
    public void trancationB() throws Exception {
        // Insert into table b
        String insertB = "INSERT INTO trancation_b (tb) VALUES (222222)";
        jdbcTemplate.update(insertB);
        throw new Exception("事务B异常");
    }
posted @   秋夜雨巷  阅读(110)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
历史上的今天:
2019-12-25 宝塔安装
2019-12-25 js判断浏览器版本
2019-12-25 JS打开url的几种方法
2018-12-25 计算机存储单位及网络传输单位
点击右上角即可分享
微信分享提示