美文网首页SpringHome
spring 的 @Async 异步任务配置 及事务的说明

spring 的 @Async 异步任务配置 及事务的说明

作者: 天天向丶上 | 来源:发表于2018-09-19 16:42 被阅读204次

    最近涉及到了一些spring的异步任务的了解,虽然我没去写相关的代码,不过还是去了解了很多,此处做一些记录。

    spring异步任务配置

    在spring的配置文件之中,增加task的配置,包含相关的约束的引用和相关的设置。
    具体如下:在xmlns中添加task,在xsi中加入具体的约束地址。增加

     xmlns:task="http://www.springframework.org/schema/task"
    
     xsi:schemaLocation=http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd
    

    增加task的配置,这里可能有小伙伴配置过spring定时就会发现,配置是一个,其也确实是一个,看了下约束,里面说的很清楚,是给定时的注释和异步任务的注释使用的。

    Enables the detection of @Async and @Scheduled annotations on any Spring-managed
    object.

    <task:annotation-driven executor="threadPoolTaskExecutor" />
    

    这里说明下,连接池是自己配置的,因为有别的需求,官方的说明如下:

    Specifies the java.util.Executor instance to use when invoking asynchronous methods.
    If not provided, an instance of org.springframework.core.task.SimpleAsyncTaskExecutor
    will be used by default.

    然后具体的连接池配置如下:

     <bean id="threadPoolTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
        <!--核心线程数,默认为1 -->
        <property name="corePoolSize" value="10" />
        <!--最大线程数,默认为Integer.MAX_VALUE-->
        <property name="maxPoolSize" value="50" />
        <!--队列最大长度,一般需要设置值>=notifyScheduledMainExecutor.maxNum;默认为Integer.MAX_VALUE-->
        <property name="queueCapacity" value="1000" /> 
        <!--线程池维护线程所允许的空闲时间,默认为60s-->
        <property name="keepAliveSeconds" value="300" />
        <!-- 线程池对拒绝任务(无线程可用)的处理策略,目前只支持AbortPolicy、CallerRunsPolicy;默认为后者-->
        <property name="rejectedExecutionHandler">
            <!-- AbortPolicy:直接抛出java.util.concurrent.RejectedExecutionException异常-->
            <!-- CallerRunsPolicy:主线程直接执行该任务,执行完之后尝试添加下一个任务到线程池中,可以有效降低向线程池内添加任务的速度-->
            <!-- DiscardOldestPolicy:抛弃旧的任务、暂不支持;会导致被丢弃的任务无法再次被执行-->
            <!-- DiscardPolicy:抛弃当前任务、暂不支持;会导致被丢弃的任务无法再次被执行-->
            <bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />
        </property>
        <!-- 线程关闭策略,默认false,当值为true时,只有当子线程里面的任务完成时才会调用shutdown()来关闭现场 -->
        <property name="waitForTasksToCompleteOnShutdown" value="true" />
    </bean>
    

    到这里,配置方面已经说清楚了,下面说下使用吧。

    spring异步任务执行

    使用很简单 ,在service里面,需要异步执行的方法,添加@Async这个注释即可,,这个任务就会异步执行。
    代码如下:

    @Service
    public class TestServiceImpl implements TestService {
    
    @Async
    @Override
    public void runTheTest(){
            System.out.println("执行11111");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("执行22222");
        }    
    }
    

    spring异步任务的事务

    说到事务就毕竟麻烦,之前网上查了一下,说不能直接在这个异步任务里面直接加事务,需要引用其他service里面的加事务。项目本身是aop来进行事务的管理,然后再service里面引入了两个其他的service。
    代码入下:

    @Service
    public class TestServiceImpl implements TestService {
    
    @Autowired
    private BigDataMessageService bigDataMessageService;
    
    private SqCoursewareService sqCoursewareService;
    
    @Async
    @Override
    public void runTheTest(){
            System.out.println("执行11111");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        List<WarningMessage> messageList = new ArrayList<WarningMessage>();
        WarningMessage a = new WarningMessage();
        a.setUnitId("999");
        a.setUserId("000");
        a.setCreationTime(new Date());
        a.setMessage("999000");
        a.setType(1);
        a.setResult("000999");
        messageList.add(a);
        bigDataMessageService.insertWarningMessage(messageList);
        sqCoursewareService.selectByPrimaryKey(1);
    }
    }
    

    这里第二个service实际没有注入,所以运行实际这个方法会报空指针异常。首先屏蔽掉 sqCoursewareService.selectByPrimaryKey(1);
    这个方法,结果正常插入。
    之后解除屏蔽,抛出了空指针异常,同时插入的数据被回滚。

    本身单个没有引用有事务的service,测试结果实际也是被回滚了。
    代码如下:

    @Service
    public class TestServiceImpl implements TestService {
    
    @Autowired
    private BigDataMessageMapper bigDataMessageMapper;
    
    @Async
    @Override
    public void runTheTest(){
            System.out.println("执行11111");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        List<WarningMessage> messageList = new ArrayList<WarningMessage>();
        WarningMessage a = new WarningMessage();
        a.setUnitId("991");
        a.setUserId("001");
        a.setCreationTime(new Date());
        a.setMessage("991001");
        a.setType(1);
        a.setResult("001991");
        messageList.add(a);
        bigDataMessageMapper.insertWarningMessage(messageList);
        Integer.valueOf(testFunction());
        System.out.println("执行222222");
    }
    
    private String testFunction(){
        return null;
    }
    

    }

    这里直接引入Mapper,Mapper实际是没有事务的,然后
    Integer.valueOf(testFunction());
    这里会抛异常,结果是插入同样被回滚了。

    也许网上说的情况和我测试的不一致,也许是spring版本的原因,这里时间有限没有进一步的测试了。小伙伴如果知道是哪里有问题可以告诉我下,然后写的话,尽量本身不要涉及事务,然后引用的service里面加上事务吧。

    相关文章

      网友评论

        本文标题:spring 的 @Async 异步任务配置 及事务的说明

        本文链接:https://www.haomeiwen.com/subject/hkzbnftx.html