quartz负责定时,spring batch负责批量,mybatis负责持久化数据库,具体每个框架的介绍请参考其它文章,本节主要做spring boot + quartz + spring batch + mybatis的整合。

案例:指定距当前时间5s后,每隔3s时间执行一次批处理任务,批处理任务是读取数据库表记录并打印出来。

数据库采用DB2数据库,库表为users,记录为:

springboot批量更新或保存MySQL数据 springboot batch批量更新_spring

一、建立一个spring boot工程,并在pom.xml中引入依赖jar包

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.lzj</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.10.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-batch</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-oxm</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!-- <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> 
            <scope>runtime</scope> </dependency> -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.batch</groupId>
            <artifactId>spring-batch-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.9</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

二、配置定时

spring-context-support的jar包作了quartz和spring batch的整合。QuartzJobBean类起连接quartz和spring batch的作用。quartz定时执行QuartzJobBean的继承类,在继承类中去执行启动批量任务,达到定时启动批量的作用。
1、创建QuartzJobBean的继承类

package com.lzj.quartz;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.h2.util.New;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.configuration.JobLocator;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.scheduling.quartz.QuartzJobBean;

public class QuartzJobLauncher extends QuartzJobBean {
/*-------------方式一:获取jobName、jobLauncher和jobLocator*/
//  private String jobName;
//  private JobLauncher jobLauncher;
//  private JobLocator jobLocator;
//
//  public String getJobName() {
//      return jobName;
//  }
//
//  public void setJobName(String jobName) {
//      this.jobName = jobName;
//  }
//
//  public JobLauncher getJobLauncher() {
//      return jobLauncher;  
//  }
//
//  public void setJobLauncher(JobLauncher jobLauncher) {
//      this.jobLauncher = jobLauncher;
//  }
//
//  public JobLocator getJobLocator() {
//      return jobLocator;
//  }
//
//  public void setJobLocator(JobLocator jobLocator) {
//      this.jobLocator = jobLocator;
//  }
/*------------------------方式一获取结束------------------------------*/

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
/*-------------方式二:获取jobName、jobLauncher和jobLocator-------------------*/
        JobDetail jobDetail = context.getJobDetail();
        JobDataMap jobDataMap = jobDetail.getJobDataMap();
        String jobName = jobDataMap.getString("jobName");
        JobLauncher jobLauncher = (JobLauncher) jobDataMap.get("jobLauncher");
        JobLocator jobLocator = (JobLocator) jobDataMap.get("jobLocator");
        System.out.println("jobName : " + jobName);
        System.out.println("jobLauncher : " + jobLauncher);
        System.out.println("jobLocator : " + jobLocator);
/*-----------------------------方式二获取结束---------------------------------*/
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date = sf.format(new Date());
        System.out.println("Current Time : " + date);

        try {
            Job job = jobLocator.getJob(jobName);
            /*启动spring batch的批处理作业*/
            JobExecution jobExecution = jobLauncher.run(job, new JobParametersBuilder().addDate("date", new Date()).toJobParameters());
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}

2、配置定时任务

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="quartzJob" class="com.lzj.quartz.QuartzJobLauncher"></bean>
    <!-- 注册job -->
    <bean id="jobRegistry" class="org.springframework.batch.core.configuration.support.MapJobRegistry"></bean>

    <bean class="org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor">
        <property name="jobRegistry" ref="jobRegistry"></property>
    </bean>

    <!-- jobLauncher在batch-config.xml文件中定义了 -->
    <bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <property name="jobClass" value="com.lzj.quartz.QuartzJobLauncher"></property>
        <property name="jobDataMap">
            <map>
                <entry key="jobName" value="myJob"></entry>
                <entry key="jobLauncher" value-ref="jobLauncher"></entry>
                <entry key="jobLocator" value-ref="jobRegistry"></entry>
            </map>
        </property>
    </bean>

    <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="jobDetail" ref="jobDetail"></property>
        <property name="cronExpression" value="0/3 * * * * ?"></property>
        <property name="startDelay" value="3000"></property>
    </bean>

    <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers" ref="cronTrigger"></property>
    </bean>

</beans>

三、配置spring batch的job作业

1、首先创建batch的作业类,实现Tasklet接口即可
程序中用到的UserDao 与数据库打交道的接口在后面通过mybatis进行定义。

package com.lzj.springbatch.tasklet;
import java.util.List;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import com.lzj.mybatis.dao.UserDao;
import com.lzj.springbatch.model.User;

public class MyTasklet implements Tasklet {
    /*在配置文件batch-confi.xml中定义MyTasklet的bean时,传入UserDao 的属性*/
    private UserDao userDao;

    public UserDao getUserDao() {
        return userDao;
    }

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
        User user = new User();
        user.setId(1);
        List<User> users = userDao.select(user);
        for(User user1 : users){
            System.out.println(user1);
        }
        return RepeatStatus.FINISHED;
    }
}

2、配置job作业

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:batch="http://www.springframework.org/schema/batch"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch.xsd
        http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">

<!--    <context:property-placeholder location="classpath:db.properties"/> --> 

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <bean id="jobRepository" class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
        <property name="transactionManager" ref="transactionManager"></property>
    </bean>

    <bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
        <property name="jobRepository" ref="jobRepository"></property>
    </bean>

    <batch:job id="myJob" restartable="true">
        <batch:step id="myStep" allow-start-if-complete="true">
            <batch:tasklet ref="myTasklet">
            </batch:tasklet>
        </batch:step>
    </batch:job>

    <bean id="myTasklet" class="com.lzj.springbatch.tasklet.MyTasklet">
<!--        <property name="dataSource" ref="dataSource"></property>  -->
        <property name="userDao" ref="userDao"></property>
    </bean>

</beans>

四、配置mybatis的持久化层

1、在spring boot中整合mybatis的配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd">

    <bean id="propertyConfigure"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:db.properties</value>
            </list>
        </property>
    </bean>

    <!--spring batch和mybatis共用一个数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${jdbc.jdbcUrl}" />
        <property name="username" value="${jdbc.user}" />
        <property name="password" value="${jdbc.password}" />
        <property name="driverClassName" value="${jdbc.driverClass}" />
        <property name="initialSize" value="3" />
        <property name="minIdle" value="3" />
        <property name="maxActive" value="3" />
        <!-- 配置获取连接等待超时的时间 -->
        <property name="maxWait" value="60000" />
        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="60000" />
        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="300000" />
        <property name="testWhileIdle" value="true" />
        <property name="testOnBorrow" value="false" />
        <property name="testOnReturn" value="false" />
    </bean>


    <!-- 申明式事务 -->
    <tx:annotation-driven transaction-manager="transactionManager" />

    <!--mybatis-config.xml为mybatis的一些属性配置,如无必须要求,可不配置-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation" value="classpath:mybatis-config.xml" /> 
        <!-- <property name="typeAliasesPackage" value="domain.bean" /> -->
        <property name="mapperLocations">
            <array>
                <value>classpath:mapper/*.xml</value>
            </array>
        </property>
    </bean>

    <!-- 配置加载Dao -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.lzj.mybatis.dao"></property>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
    </bean>

</beans>

mybatis-config.xml中只配置了开启mybatis的二级缓存功能

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
    <settings>
        <setting name="cacheEnabled" value="true" />
    </settings>
</configuration>

数据库的properties文件db.properties为:

jdbc.user=my_name
jdbc.password=my_password
jdbc.driverClass=com.ibm.db2.jcc.DB2Driver
jdbc.jdbcUrl=jdbc:db2:xx.xxx.xx.xxx:50000/database_name

2、创建mybatis的接口,程序通过接口来操作mybatis与数据库交互

package com.lzj.mybatis.dao;
import java.util.List;
import com.lzj.springbatch.model.User;
public interface UserDao {
    public List<User> select(User user);
}

3、编写mybatis的mapper文件,接口操作mapper文件,

mapper文件与数据库交互
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lzj.mybatis.dao.UserDao">
    <resultMap type="com.lzj.springbatch.model.User" id="ResultMap">
        <result column="ID" property="id"/>
        <result column="NAME" property="name"/>
        <result column="AGE" property="age"/>
    </resultMap>

    <select id="select" resultMap="ResultMap">
        select * from SQLJ.users
        <where>
            <if test="id != null">ID > #{id}</if>
        </where>
    </select>
</mapper>

五、run

测试方法如下:

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException, JobParametersInvalidException {

        Set<Object> set = new HashSet<>();
        set.add("classpath:batch-config.xml");
        set.add("classpath:quartz-config.xml");
        set.add("applicationContext.xml");
        SpringApplication app = new SpringApplication(DemoApplication.class);
        app.setSources(set);
        ApplicationContext context = app.run(args);
    }
}

启动测试方法,输出日志如下:

……
jobName : myJob
jobLauncher : org.springframework.batch.core.launch.support.SimpleJobLauncher@4ba309ec
jobLocator : org.springframework.batch.core.configuration.support.MapJobRegistry@4564eee8
Current Time : 2018-04-13 19:48:00
2018-04-13 19:48:00.032  INFO 4788 --- [eduler_Worker-2] o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=myJob]] launched with the following parameters: [{date=1523620080009}]
2018-04-13 19:48:00.090  INFO 4788 --- [eduler_Worker-2] o.s.batch.core.job.SimpleStepHandler     : Executing step: [myStep]
User [id=2, name=huwei, age=28]
User [id=3, name=lijie, age=26]
2018-04-13 19:48:00.140  INFO 4788 --- [eduler_Worker-2] o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=myJob]] completed with the following parameters: [{date=1523620080009}] and the following status: [COMPLETED]
jobName : myJob
jobLauncher : org.springframework.batch.core.launch.support.SimpleJobLauncher@4ba309ec
jobLocator : org.springframework.batch.core.configuration.support.MapJobRegistry@4564eee8
Current Time : 2018-04-13 19:48:03
2018-04-13 19:48:03.017  INFO 4788 --- [eduler_Worker-3] o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=myJob]] launched with the following parameters: [{date=1523620083000}]
2018-04-13 19:48:03.057  INFO 4788 --- [eduler_Worker-3] o.s.batch.core.job.SimpleStepHandler     : Executing step: [myStep]
User [id=2, name=huwei, age=28]
User [id=3, name=lijie, age=26]
2018-04-13 19:48:03.089  INFO 4788 --- [eduler_Worker-3] o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=myJob]] completed with the following parameters: [{date=1523620083000}] and the following status: [COMPLETED]
jobName : myJob
jobLauncher : org.springframework.batch.core.launch.support.SimpleJobLauncher@4ba309ec
jobLocator : org.springframework.batch.core.configuration.support.MapJobRegistry@4564eee8
Current Time : 2018-04-13 19:48:06
2018-04-13 19:48:06.019  INFO 4788 --- [eduler_Worker-4] o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=myJob]] launched with the following parameters: [{date=1523620086001}]
2018-04-13 19:48:06.058  INFO 4788 --- [eduler_Worker-4] o.s.batch.core.job.SimpleStepHandler     : Executing step: [myStep]
User [id=2, name=huwei, age=28]
User [id=3, name=lijie, age=26]
2018-04-13 19:48:06.094  INFO 4788 --- [eduler_Worker-4] o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=myJob]] completed with the following parameters: [{date=1523620086001}] and the following status: [COMPLETED]
……

通过日志可以看出,每3s执行一次job任务

工程目录为:

springboot批量更新或保存MySQL数据 springboot batch批量更新_quartz_02

源码下载位置: https://github.com/shuniversity/-springboot-quartz-springbatch-mybatis