Could not obtain transaction-synchronized Session for current thread问题及解决

参考过文章工作笔记-Spring5的坑

 他方法里提到的解决办法是

然鹅这样并不根本解决办法,因为我的程序还会因为session 为空导致后续的查询或者数据库操作报错

我的 ======>>>>>>Hibernate  5.4.21.Final  |  Spring 5.2.9.RELEASE

出现的地方大概在:

ImportService  加了 @Transactional的注解,里面有个方法叫 importExcelAsync ,

然后方法里面Thread 调用了ExcelHandler的方法,ExcelHandler 一个方法叫saveBatch(从一开始就加了注解@Transactional)

一个方法叫doAfterAllAnalysed 一开始没加

我的项目需求就是上传文件,会创建一条记录,初始化状态为1 ;当读取完数据之后,这条数据的状态会变成2;同样需要实现异步读取文件,所以用到的是Thread

详细可查阅另一篇文章关于FastExcel 的使用

实现的代码大概如下:

@Transactional
public class ImportSheetService extends BaseHibernateDao {
    private ExecutorService executorService = Executors.newFixedThreadPool(20);
    @Resource
    private ExcelHandler alipayExcelHandler; 
    public  Map<String, Object> importExcelAsync(Long userId, MultipartFile file) throws IOException, BaseException {
        //此处省略一部分代码…………
        //执行异步读取表格数据
       executorService.submit(() -> {
            FastExcel.read(inputStream, AlipayImportDetailStat.class, alipayExcelHandler).headRowNumber(headRowNumber.get())
                    .charset(Charset.forName(charset)) .sheet().doRead();
            logger.info("read Excel");
        });
        try {
            //等待所有任务完成
            Map<String, Object> map = new HashMap<>();
            //……
            return map;
        } finally {
//            return null;
        }

    }
//读取完成后更新
public void finished(ImportSheet sheet,Long totalRows)  {
        if (sheet != null) {
            try {
               
                //此处省略保存代码……
            } catch (BaseException e) {
                throw new PersistentException(ErrorCode.OBJECT_ADD_ERROR,"增加对象失败!",e);
            }
        }else{
            logger.error("sheet empty");
        }
    }
}

@Component
public class ExcelHandler  extends AnalysisEventListener<ImportDetailStat> {

    private static final Log logger = LogFactory.getLog(AlipayExcelHandler.class);

    //创建一个线程池,用于异步保存数据
    private ExecutorService executorService = Executors.newFixedThreadPool(20);

    //创建一个线程安全的list,用于存储读取到的数据,使用ThreadLocal保证线程安全
    private ThreadLocal<ArrayList<ImportDetailStat>> sheetDataList = ThreadLocal.withInitial(ArrayList::new);

    //用于统计是第几次插入
    private static AtomicInteger count = new AtomicInteger(1);
    private static AtomicInteger totalCount = new AtomicInteger(0);
 
    @Resource
    private ExcelHandler ExcelHandler; 
    @Resource
   private ImportSheetService importSheetService;

    public  Long getTotalCount() {
        return totalCount.longValue();
    }

    
    @Transactional
    public void saveBatch(List<AlipayImportDetailStat> sheetDetailsList) throws BaseException {
            if (!sheetDetailsList.isEmpty()) {
                  //省略保存代码……
            }
        } 
    //在这个方法上也需要加上@Transactional  就是正确的
    @Override
    @Transactional  
    public void doAfterAllAnalysed(AnalysisContext context) { 
        asyncSaveData();
        try {
            sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        //处理结束之后,更新数据
        importSheetService.finished(); 
    }

处理的方式就是

在ExcelHandler 两个数据保存的方法上都需要加上@Transactional 的注解

此处用到的Transactional   是import javax.transaction.Transactional;

至于org.springframework.transaction.annotation.Transactional  与 javax.transaction.Transactional 差别,我就不赘述了;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值