@Transactional 注解在多线程环境下不生效问题

本文探讨了在多线程环境中使用Spring的@Transactional注解时遇到的问题,通过具体代码示例展示事务在异步调用中为何未能生效,并分析了TransactionAspectSupport.currentTransactionStatus().flush()方法的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

@Transactional 注解在多线程环境下不生效问题

直接上代码

package com.linzi.risk.indicator.service.impl;

import com.linzi.risk.common.utils.threadpool.ThreadPoolManager;
import com.linzi.risk.indicator.dao.AsyncCommandDao;
import com.linzi.risk.indicator.entity.AsyncCommandEntity;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.Resource;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Date;

/**
 * @author chentiefeng
 * @date 2018/10/11 14:47
 */
@Component
public class TestTrans {

    @Resource
    private AsyncCommandDao asyncCommandDao;

    @Transactional
    public void test() {
        AsyncCommandEntity command = new AsyncCommandEntity();
        command.setType("test");
        command.setBsnNo("1");
        command.setBsnType("1");
        command.setContent("");
        try {
            command.setAddIp(InetAddress.getLocalHost().getHostName());
            command.setUpdateIp(InetAddress.getLocalHost().getHostName());
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        command.setAddTime(new Date());
        command.setUpdateTime(new Date());
        command.setState("INIT");
        asyncCommandDao.insert(command);
        TransactionAspectSupport.currentTransactionStatus().flush();
        ThreadPoolManager.getInstance().execute(new Runnable() {
            @Override
            public void run() {
                AsyncCommandEntity entity = asyncCommandDao.selectById(command.getId());
                System.out.println("Transactional 事务下异步线程查询:" + entity);
                if (entity.getId() != null) {
                    asyncCommandDao.delete(entity.getId());
                }
            }
        });
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

因为插入后睡眠了500毫秒,所以运行结果就是报空指针异常。
不了解的情况下以为TransactionAspectSupport.currentTransactionStatus().flush();方法能手动commit事务,原来不行

多线程环境中使用@Transactional注解可能会导致事务失效。因为@Transactional注解默认只对当前线程的方法调用生效,而不会对其他线程中调用的方法生效。所以在多线程环境中,如果想要保证事务的一致性,需要使用其他手段来处理。 在引用中的示例代码中,使用了ThreadLocal来记录当前线程产生的异常,并在主线程中进行异常捕获和事务的回滚。这种方式通过在子线程中将异常信息保存到ThreadLocal中,然后在主线程中判断是否有异常,并进行相应的回滚操作。这样可以保证在多线程环境中的事务一致性。 而在引用中的示例代码中,虽然使用了事务注解@Transactional,但是由于子线程的运行并不会影响主线程的运行,所以事务对子线程是没有任何约束力的。因此,在多线程环境中,不建议使用@Transactional注解来处理事务。 总结来说,多线程环境下的事务管理需要特殊处理。可以通过使用ThreadLocal来记录异常信息,并在主线程中进行异常捕获和事务的回滚来保证事务的一致性。123 #### 引用[.reference_title] - *1* *3* [@Transactional注解下使用多个线程进行异步操作数据,如果产生异常,事务是否回滚?](https://blog.csdn.net/weixin_42541479/article/details/130528106)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}} ] [.reference_item] - *2* [@Transactional多线程](https://blog.csdn.net/weixin_43935720/article/details/114262244)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}} ] [.reference_item] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值