多线程事务处理问题

南笙酒味 提交于 2019-12-12 19:32:14

代码

EquipCollectServiceImpl.java
protected static final ExecutorService handleTaskPoolExecutor = Executors.newFixedThreadPool(3);
public void queryDataToUpload(){
    // 查询待上传信息
    List list = equipCollectDao.queryDataByParams();
    // 多线程 调用上传接口
    handleTaskPoolExecutor.submit(
        @Override
        new Runnable(){
            public void run(){
                // ... 接口调用 ...
                Json backInfo = {..};
                // 保存接口日志(方式 1) -> 报错
                interfaceDao.insertInterfaceBackLog(backInfo);
                // 保存接口日志(方式 2) -> 2.1报错 2.2成功
                saveInterfaceBackLog(backInfo);
                // 保存接口日志(方式 3) -> 成功
                interfaceService.insertInterfaceBackLog(backInfo);
            }
        }
    );
}
@Transactional
public void saveInterfaceBackLog(Json backInfo){
    // 方式 2.1
    interfaceDao.insertInterfaceBackLog(backInfo);
    // 方式 2.2
    interfaceService.insertInterfaceBackLog(backInfo);
}

报错说明
insertInterfaceBackLog()方法中使用 查询 报:

java.util.concurrent.ExecutionException: org.hibernate.HibernateException: 
Could not obtain transaction-synchronized Session for current thread

insertInterfaceBackLog()方法中使用 保存 报:

org.springframework.dao.InvalidDataAccessApiUsageException: 
Write operations are not allowed in read-only mode (FlushMode.MANUAL): 
Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.

问题分析
查询 this.getSessionFactory().getCurrentSession() 获取不到session,然后直接报错;
保存 this.getSessionFactory().getCurrentSession() 获取不到session,会创建新session,但是FlushMode.MANUAL < FlushMode.COMMIT,然后报错;
spring-orm-4.3.4.RELEASE.jar源码如下:

if (session == null) {
    session = this.getSessionFactory().openSession();
    session.setFlushMode(FlushMode.MANUAL);
    isNew = true;
}

总结
多线程内部不被事务控制,获取不到session,但是能够获取spring注入的bean;
多线程内部执行同类中方法,不会分配新事务(注解,AOP切面 均不生效);
方式 3,方式 2.2 每执行一次就会启动一个事务;不会影响到同线程的其他事务;

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!