背景:
最近项目有个批量导入的需求需要优化——当导入数量过大时,后端对导入数据的校验和数据库操作时间过长,会导致前端请求超时,用户体验也极差。所以要将数据校验等耗时操作进行异步处理。此处异步处理采用的是多线程的方式实现,然后就有了以下的问题。
一、多线程服务调用导致token失效
在多线程开发过程中,主线程的上下文信息默认并不会继承到子线程中,所以需要手动设置,一些特殊的请求头信息(如:token信息),可能无法直接通过上下文获得,此时就需要用到InheritableThreadLocal:可继承的线程级全局变量。
开可在controller层获取请求头信息,并赋值到 InheritableThreadLocal中,此处可以封装一个工具类来操作InheritableThreadLocal。
将token信息放到共享类中后,需要在Feign配置类中(实现feign.RequestInterceptor)配置服务调用时需要附带的信息,代码示例已给出。至此问题就解决了。
二、多线程开发中事务的优雅处理
在多线程开发中,Spring自带的事务注解的方式无法对子线程的数据库操作进行回滚。但在Spring提供了手动控制的事务的优雅的结局方案:org.springframework.transaction.support.TransactionTemplate;
此类可以优雅的控制事务提交操作。为方便起见,事务维护的代码已整合到MyService的异步处理中。
<!--Spring手动事务提交jar-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.3.12</version>
</dependency>
<!--feign pom-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.7.RELEASE</v