springBoot+quartz-mybatis整合demo

Demo实现的功能

使用springBoot集成quartz分布式调度框架和mybatis, 实现定时用数据库做查询数据的功能。

github源码地址

https://github.com/mikewuhao/springBoot-quartz-demo

搭建详细步骤

项目结构
在这里插入图片描述
在idea开发工具里面新建maven类型的project, 命名为springBoot-quartz-demo按上图目录结构建包

pom.xml, 引入quartz相关依赖的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.wuhao.demo</groupId>
    <artifactId>springBoot-quartz-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.7.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- spring-boot整合mybatis -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.1.1</version>
        </dependency>

        <!-- mysql驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

       <!--quartz-->
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.2.3</version>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-api</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>

            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>

        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>


</project>

mysql数据库和mybatis相关配置

#数据库
spring.datasource.driver-class-name= com.mysql.jdbc.Driver
spring.datasource.url = jdbc:mysql://127.0.0.1:3306/boot?useUnicode=true&characterEncoding=utf-8
spring.datasource.username = root
spring.datasource.password = root

#mybatis
mybatis.type-aliases-package=com.wuhao.domain
mybatis.mapper-locations=classpath:mapper/*.xml

编写启动类QuartzApplication, 加上@EnableScheduling开启定时任务的注解

package com.wuhao;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

/**
 * @description: quartz启动类
 * @author: wuhao
 * @create: 2020-06-18 18:27
 **/
@SpringBootApplication
@EnableScheduling
public class QuartzApplication {
    public static void main(String[] args) {
        SpringApplication.run(QuartzApplication.class,args);
    }
}

编写Job类 ,自定义1个从数据库查数据的定时任务

package com.wuhao.job;

import com.wuhao.dao.UserMapper;
import com.wuhao.domain.User;
import lombok.extern.slf4j.Slf4j;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * @description: job类, 自定义任务
 * @author: wuhao
 * @create: 2020-06-18 21:34
 **/
@Slf4j
public class MyJob implements Job {

    @Autowired
    private UserMapper userMapper;

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        User user = userMapper.queryUserById(1L);
        log.info("job执行: ---job------->"+user.toString());
    }
}

编写quzrtz的核心配置类, 此处按每隔2秒, 重复5次触发定时任务

package com.wuhao.config;

import com.wuhao.job.MyJob;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;

/**
 * @description: quartz配置类
 * @author: wuhao
 * @create: 2020-06-19 10:38
 **/
@Configuration
public class QuartzConfig {

    //1.创建Job对象
    @Bean
    public JobDetailFactoryBean jobDetailFactoryBean(){
        JobDetailFactoryBean factory = new JobDetailFactoryBean();
        //关联自定义的job类
        factory.setJobClass(MyJob.class);
        return factory;
    }

    //2. 创建Trigger对象
    @Bean
    public SimpleTriggerFactoryBean simpleTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean){
        SimpleTriggerFactoryBean factory = new SimpleTriggerFactoryBean();
        // 关联jobDetail对象
        factory.setJobDetail(jobDetailFactoryBean.getObject());
        //任务间隔毫秒数
        factory.setRepeatInterval(2000);
        // 任务重复次数
        factory.setRepeatCount(5);
        return factory;
    }

    //3. 创建Scheduler对象
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(SimpleTriggerFactoryBean simpleTriggerFactoryBean, MyAdaptableJobFactory myAdaptableJobFactory){
        SchedulerFactoryBean factory= new SchedulerFactoryBean();
        //关联 trigger
        factory.setTriggers(simpleTriggerFactoryBean.getObject());
        factory.setJobFactory(myAdaptableJobFactory);
        return factory;
    }
}

**编写一个MyAdaptableJobFactory类, 继承父类AdaptableJobFactory, 重写AdaptableJobFactory方法, 目的是解决Dao层的注入时报空指针的问题 **

package com.wuhao.config;

import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;

/**
 * @description: 继承AdaptableFactory类, 重写实例化方法, 把对象手动注入springIOC容器, 实现业务层service的注入
 * @author: wuhao
 * @create: 2020-06-19 11:15
 **/
@Component("myAdaptableJobFactory")
public class MyAdaptableJobFactory extends AdaptableJobFactory {

    @Autowired //將對象添加到springIOC的容器中並且完成對象的注入
    private AutowireCapableBeanFactory autowireCapableBeanFactory;

    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        Object obj = super.createJobInstance(bundle);
        //把obj對象加入到springIOC容器中,完成注入
        this.autowireCapableBeanFactory.autowireBean(obj);
        return obj;
    }
}

User用户实体类

package com.wuhao.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @description: User 实体类
 * @author: wuhao
 * @create: 2020-06-19 11:47
 **/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {

    private Long id;

    private String username;

    private String birthday;

    private String sex;

    private String address;
}

Dao层的UserMapper接口

package com.wuhao.dao;

import com.wuhao.domain.User;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

@Mapper
@Repository
public interface UserMapper {

    User queryUserById(Long id);

    int addUser(User user);

    int modifyUser(User user);

    int deleteUserById(Long id);
}

执行sql的xml文件

<?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.wuhao.dao.UserMapper">

    <!--按id查询用户-->
    <select id="queryUserById" resultType="com.wuhao.domain.User">
        select * from `user` where id = #{id}
    </select>

    <!--用户更新-->
    <update id="modifyUser" parameterType="com.wuhao.domain.User" >
        update `user` set username=#{username},birthday=#{birthday},sex=#{sex}, address=#{address} where id=#{id}
    </update>

    <!--删除用户-->
    <delete id="deleteUserById" parameterType="long">
        delete from `user` where id=#{id}
    </delete>

    <!--用户添加-->
    <insert id="addUser" parameterType="com.wuhao.domain.User">
        insert into `user` (username,birthday,sex,address)
             values(#{username},#{birthday},#{sex},#{address})
    </insert>

</mapper>

演示效果

启动项目, 观察控制台的运行日志, 系统会按每隔2秒, 重复5次执行查数据库操作的定时任务(项目刚启动时执行的不算)
在这里插入图片描述

遇到的问题

刚开始在Job任务类里注入Dao层的UserMapper时, 启动报空指针异常, 发现UserMapper没注入进来, 后来查资料得知, Job类实例化是通过AdaptableJobFactory类的createJobInstance方法用反射实体化的, 没被Spring的IOC容器管理
在这里插入图片描述
springIOC实例化要求 : 必须是注入对象(UserMapper)和被注入对象(Job类)都在springIOC容器中, 解决方法就是: 自定义MyAdaptableJobFactory类继承父类AdaptableJobFactory, 重写createJobInstance方法, 把Job类對象添加到springIOC容器中並且完成對象的注入

后续优化点

可用quartz实现数据库任务的持久化, 这里时间原因就不再叙述了

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,针对你的问题,我可以给你提供一些思路和建议。 首先,你可以使用 Spring Boot 作为你整个应用的基础框架,它提供了丰富的功能和插件,使得整合 Quartz 和 PostgreSQL 变得更加简单。 其次,对于数据库连接池,你可以使用 HikariCP,它是一个非常轻量级的连接池实现,性能非常出色,适合用于高并发场景。 最后,对于 Quartz整合,你可以参考 Spring Boot 官方提供的 Quartz Starter,这个 Starter 已经将 Quartz 集成到了 Spring Boot 中,并提供了自动配置和一些默认的设置,使得整合变得更加简单。 下面是一个简单的示例,演示如何使用 Spring Boot、HikariCP 和 Quartz 整合 PostgreSQL: 1. 首先,在你的 pom.xml 中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> ``` 2. 在 application.properties 文件中添加以下配置: ```properties spring.datasource.url=jdbc:postgresql://localhost:5432/mydatabase spring.datasource.username=myusername spring.datasource.password=mypassword spring.datasource.driver-class-name=org.postgresql.Driver spring.datasource.hikari.maximum-pool-size=10 spring.datasource.hikari.minimum-idle=5 spring.quartz.properties.org.quartz.jobStore.dataSource=myDataSource spring.quartz.properties.org.quartz.dataSource.myDataSource.driver=org.postgresql.Driver spring.quartz.properties.org.quartz.dataSource.myDataSource.URL=jdbc:postgresql://localhost:5432/mydatabase spring.quartz.properties.org.quartz.dataSource.myDataSource.user=myusername spring.quartz.properties.org.quartz.dataSource.myDataSource.password=mypassword spring.quartz.properties.org.quartz.dataSource.myDataSource.maxConnections=10 ``` 3. 在你的代码中配置 Quartz: ```java @Configuration public class QuartzConfig { @Autowired private DataSource dataSource; @Bean public SchedulerFactoryBean schedulerFactoryBean() { SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(); schedulerFactoryBean.setDataSource(dataSource); schedulerFactoryBean.setApplicationContextSchedulerContextKey("applicationContext"); Properties quartzProperties = new Properties(); quartzProperties.setProperty("org.quartz.scheduler.instanceName", "QuartzScheduler"); quartzProperties.setProperty("org.quartz.scheduler.instanceId", "AUTO"); quartzProperties.setProperty("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX"); quartzProperties.setProperty("org.quartz.jobStore.driverDelegateClass", "org.quartz.impl.jdbcjobstore.PostgreSQLDelegate"); quartzProperties.setProperty("org.quartz.jobStore.useProperties", "true"); quartzProperties.setProperty("org.quartz.jobStore.dataSource", "myDataSource"); quartzProperties.setProperty("org.quartz.jobStore.tablePrefix", "QRTZ_"); quartzProperties.setProperty("org.quartz.jobStore.isClustered", "false"); quartzProperties.setProperty("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool"); quartzProperties.setProperty("org.quartz.threadPool.threadCount", "10"); quartzProperties.setProperty("org.quartz.threadPool.threadPriority", "5"); schedulerFactoryBean.setQuartzProperties(quartzProperties); return schedulerFactoryBean; } @Bean public JobDetail sampleJobDetail() { return JobBuilder.newJob(SampleJob.class) .withIdentity("sampleJob") .usingJobData("name", "World") .storeDurably() .build(); } @Bean public Trigger sampleJobTrigger() { SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(10) .repeatForever(); return TriggerBuilder.newTrigger() .forJob(sampleJobDetail()) .withIdentity("sampleTrigger") .withSchedule(scheduleBuilder) .build(); } } ``` 这个配置类定义了一个 SchedulerFactoryBean,它使用我们之前配置的数据源,并设置了 Quartz 的一些属性。同时,我们还定义了一个 SampleJob,它会每隔 10 秒钟执行一次,并输出一条日志信息。 4. 编写 SampleJob 类: ```java public class SampleJob implements Job { private static final Logger LOGGER = LoggerFactory.getLogger(SampleJob.class); @Override public void execute(JobExecutionContext context) throws JobExecutionException { LOGGER.info("Hello, {}!", context.getMergedJobDataMap().get("name")); } } ``` 这个类实现了 Quartz 的 Job 接口,定义了一个 execute 方法,它会在每次调度时被执行。 5. 运行应用程序,你应该会看到类似如下的输出: ``` 2021-10-14 15:31:00.001 INFO 25508 --- [pool-1-thread-1] o.s.s.quartz.SampleJob : Hello, World! 2021-10-14 15:31:10.002 INFO 25508 --- [pool-1-thread-1] o.s.s.quartz.SampleJob : Hello, World! 2021-10-14 15:31:20.001 INFO 25508 --- [pool-1-thread-1] o.s.s.quartz.SampleJob : Hello, World! ... ``` 这个示例演示了如何使用 Spring Boot、HikariCP 和 Quartz 整合 PostgreSQL。当然,这只是一个简单的示例,你可以根据自己的需求进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值