基于SpringBoot的XXL-JOB集成mybatis-plus+druid多数据源配置

基于SpringBoot的XXL-JOB集成mybatis-plus+druid多数据源配置,第1张

基于SpringBoot的XXL-JOB集成mybatis-plus+druid多数据源配置 一、简介

xxl-job是通过一个中心式的调度平台,调度多个执行器执行任务,调度中心通过DB锁保证集群分布式调度的一致性,这样扩展执行器会增大DB的压力,但是如果实际上这里数据库只是负责任务的调度执行。但是如果没有大量的执行器的话和任务的情况,是不会造成数据库压力的。实际上大部分公司任务数,执行器并不多(虽然面试经常会问一些高并发的问题)。

相对来说,xxl-job中心式的调度平台轻量级,开箱即用, *** 作简易,上手快,与SpringBoot有非常好的集成,而且监控界面就集成在调度中心,界面又简洁,对于企业维护起来成本不高,还有失败的邮件告警等等。这就使很多企业选择xxl-job做调度平台。

二、过程
  • 新建一个SpringBoot项目,或使用现有的SpringBoot项目;
  • maven配置pom.xml,导入相关的依赖
  • 编写application.yml,如:项目路径名及端口,mybatisplus配置,mysql多数据源配置。
  • 新建DataSourceContextHolder 用于设置,获取,清空 当前线程内的数据源变量。
  • 新建 MultipleDataSource 实现 AbstractRoutingDataSource 类。重写determineCurrentLookupKey(),通过DataSourceContextHolder 获取数据源变量,用于当作lookupKey取出指定的数据源。
  • 新建DataSourceEnum 用于存放数据源名称。
  • 新建注解 DataSource,用于下面aop类中当作切入点来选择数据源。
  • 编写aop类 --> DataSourceAspect.java
  • 新建并配置以下的三个类

DruidConfiguration:

        StatViewServlet 和 WebStatFilter Druid监控配置和监控过滤器。

MybatisplusConfiguration:

        mybatisplus 分页插件,SQL执行效率插件;
        数据源Bean,MultipleDataSource 注入;
        SqlSessionFactory注入;

SwaggerConfiguration:

        自动生成的接口文档,不需要频繁更新接口文档,保证接口文档与代码的一致。

  • 测试mybatis-plus+多数据源配置。
三、项目结构

四、详细步骤

1.新建一个SpringBoot项目,或使用现有的SpringBoot项目;

2.maven配置pom.xml,导入相关的依赖


	1.1.22
	2.7.0





	mysql
	mysql-connector-java
	runtime


	org.projectlombok
	lombok
	true


	com.baomidou
	mybatis-plus-boot-starter
	3.1.0




	com.alibaba
	druid-spring-boot-starter
	${druid.version}



	io.springfox
	springfox-swagger2
	${swagger.version}


	io.springfox
	springfox-swagger-ui
	${swagger.version}



	org.springframework.boot
	spring-boot-starter-aop


	com.baomidou
	mybatis-plus-extension
	3.1.0

3.编写application.yml,如:项目路径名及端口,mybatisplus配置,mysql多数据源配置。

server:
  servlet:
    context-path: /ssm-zyy
spring:
  datasource:
    druid:
      db1:
        username: root
        password: root
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3306/student?serverTimezone=UTC
        initialSize: 5
        minIdle: 5
        maxActive: 20
      db2:
        username: root
        password: root
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3306/teacher?serverTimezone=UTC
        initialSize: 5
        minIdle: 5
        maxActive: 20
mybatis-plus:
  mapper-locations: classpath:/mapper
public class DataSourceContextHolder {

    private static final ThreadLocal contextHolder = new InheritableThreadLocal<>();

    
    public static void setDataSource(String db){
        contextHolder.set(db);
    }

    
    public static String getDataSource(){
        return contextHolder.get();
    }

    
    public static void clear(){
        contextHolder.remove();
    }
}

5.新建 MultipleDataSource 实现 AbstractRoutingDataSource 类。重写determineCurrentLookupKey(),通过DataSourceContextHolder 获取数据源变量,用于当作lookupKey取出指定的数据源。

package com.xxl.datasource.multiple;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;


public class MultipleDataSource extends AbstractRoutingDataSource {
   
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSource();
    }
}

6.新建DataSourceEnum 用于存放数据源名称。

package com.xxl.datasource.enums;

public enum DataSourceEnum {

    DB1("db1"),DB2("db2");

    private String value;

    DataSourceEnum(String value){this.value=value;}

    public String getValue() {
        return value;
    }
}

7.新建注解 DataSource,用于下面aop类中当作切入点来选择数据源。

package com.xxl.datasource.annotation;


import com.xxl.datasource.enums.DataSourceEnum;

import java.lang.annotation.*;

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@documented
public @interface DataSource {

    DataSourceEnum value() default DataSourceEnum.DB1;
}

8.编写aop类 --> DataSourceAspect.java

package com.xxl.datasource.aop;

import com.xxl.datasource.annotation.DataSource;
import com.xxl.datasource.multiple.DataSourceContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;


@Component
@Slf4j
@Aspect
@Order(-1)
public class DataSourceAspect {

    @Pointcut("@within(com.xxl.datasource.annotation.DataSource) || @annotation(com.xxl.datasource.annotation.DataSource)")
    public void pointCut(){

    }

    @Before("pointCut() && @annotation(dataSource)")
    public void doBefore(DataSource dataSource){
        log.info("选择数据源---"+dataSource.value().getValue());
        DataSourceContextHolder.setDataSource(dataSource.value().getValue());
    }

    @After("pointCut()")
    public void doAfter(){
        DataSourceContextHolder.clear();
    }
}

9.新建并配置以下的三个类

DruidConfiguration:

        StatViewServlet 和 WebStatFilter Druid监控配置和监控过滤器。

package com.xxl.config;

import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class DruidConfiguration {

   
    @Bean
    public ServletRegistrationBean startViewServlet(){
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(),"/druid
    @Bean
    public FilterRegistrationBean statFilter(){
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
        //添加过滤规则
        filterRegistrationBean.addUrlPatterns("
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        // 开启 PageHelper 的支持
//        paginationInterceptor.setLocalPage(true);
        return paginationInterceptor;
    }

    
    @Bean
    @Profile({"dev","qa"})// 设置 dev test 环境开启
    public PerformanceInterceptor performanceInterceptor() {
        PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
        performanceInterceptor.setMaxTime(1000);
        performanceInterceptor.setFormat(true);
        return performanceInterceptor;
    }

    @Bean(name = "db1")
    @ConfigurationProperties(prefix = "spring.datasource.druid.db1" )
    public DataSource db1() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name = "db2")
    @ConfigurationProperties(prefix = "spring.datasource.druid.db2" )
    public DataSource db2() {
        return DruidDataSourceBuilder.create().build();
    }

    
    @Bean
    @Primary
    public DataSource multipleDataSource(@Qualifier("db1") DataSource db1, @Qualifier("db2") DataSource db2) {
        MultipleDataSource multipleDataSource = new MultipleDataSource();
        Map< Object, Object > targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceEnum.DB1.getValue(), db1);
        targetDataSources.put(DataSourceEnum.DB2.getValue(), db2);
        //添加数据源
        multipleDataSource.setTargetDataSources(targetDataSources);
        //设置默认数据源
        multipleDataSource.setDefaultTargetDataSource(db1);
        return multipleDataSource;
    }

    @Bean("sqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
        sqlSessionFactory.setDataSource(multipleDataSource(db1(),db2()));
        //sqlSessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mapper/*/*Mapper.xml"));

        MybatisConfiguration configuration = new MybatisConfiguration();
        //configuration.setDefaultscriptingLanguage(MybatisXMLLanguageDriver.class);
        configuration.setJdbcTypeForNull(JdbcType.NULL);
        configuration.setMapUnderscoreToCamelCase(true);
        configuration.setCacheEnabled(false);
        sqlSessionFactory.setConfiguration(configuration);
        sqlSessionFactory.setPlugins(new Interceptor[]{ //PerformanceInterceptor(),OptimisticLockerInterceptor()
                paginationInterceptor() //添加分页功能
        });
        //sqlSessionFactory.setGlobalConfig(globalConfiguration());
        return sqlSessionFactory.getObject();
    }


}

SwaggerConfiguration:

        自动生成的接口文档,不需要频繁更新接口文档,保证接口文档与代码的一致。

package com.xxl.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.documentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

//http://localhost:8083/ssm-zyy/swagger-ui.html
@Configuration
@EnableSwagger2
public class SwaggerConfiguration {

    @Bean
    public Docket createRestApi() {
        return new Docket(documentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.xxl.controller"))
                .paths(PathSelectors.any())
                .build()
                .apiInfo(apiInfo());
    }
    private ApiInfo apiInfo(){
        return new ApiInfoBuilder()
                .title("多数据源 SpringBoot+MyBatis-PLUS 测试服务")
                .description("多数据源 SpringBoot+MyBatis-PLUS 测试文档")
                .termsOfServiceUrl("http://www.baidu.com")
                .version("1.0")
                .build();
    }

}

10.测试mybatis-plus+多数据源配置。

实体类

package com.xxl.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

@Api("学生实体对象")
@Data
@TableName("t_student")
public class Student {

    @ApiModelProperty("学生id")
    @TableId(type = IdType.AUTO)
    private Integer id;

    @ApiModelProperty("学生姓名")
    private String name;

    @ApiModelProperty("学生年龄")
    private Integer age;

    @ApiModelProperty("学生班级")
    private String classname;

}

package com.xxl.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

@Api("老师实体对象")
@Data
@TableName("t_teacher")
public class Teacher {

    @ApiModelProperty("老师id")
    @TableId(type = IdType.AUTO)
    private Integer id;

    @ApiModelProperty("老师姓名")
    private String name;

    @ApiModelProperty("老师年龄")
    private Integer age;

    @ApiModelProperty("老师所教学科")
    private String subject;
}

Mapper

package com.xxl.mapper;


import com.baomidou.mybatisplus.core.mapper.baseMapper;
import com.xxl.entity.Student;

public interface StudentMapper extends baseMapper {
}





package com.xxl.mapper;


import com.baomidou.mybatisplus.core.mapper.baseMapper;
import com.xxl.entity.Teacher;

public interface TeacherMapper extends baseMapper {
}




Service

package com.xxl.service;


import com.baomidou.mybatisplus.extension.service.IService;
import com.xxl.entity.Student;

public interface StudentService extends IService {

}

package com.xxl.service.impl;


import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xxl.entity.Student;
import com.xxl.mapper.StudentMapper;
import com.xxl.service.StudentService;
import org.springframework.stereotype.Service;

@Service
public class StudentServiceImpl extends ServiceImpl implements StudentService {
}

package com.xxl.service;


import com.baomidou.mybatisplus.extension.service.IService;
import com.xxl.entity.Teacher;

public interface TeacherService extends IService {
}

package com.xxl.service.impl;


import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xxl.datasource.annotation.DataSource;
import com.xxl.datasource.enums.DataSourceEnum;
import com.xxl.entity.Teacher;
import com.xxl.mapper.TeacherMapper;
import com.xxl.service.TeacherService;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.util.List;


@Service
public class TeacherServiceImpl extends ServiceImpl implements TeacherService {

    @Override
    @DataSource(DataSourceEnum.DB2)
    public boolean save(Teacher entity) {
        return super.save(entity);
    }

    @Override
    @DataSource(DataSourceEnum.DB2)
    public boolean removeById(Serializable id) {
        return super.removeById(id);
    }

    @Override
    @DataSource(DataSourceEnum.DB2)
    public boolean updateById(Teacher entity) {
        return super.updateById(entity);
    }

    @Override
    @DataSource(DataSourceEnum.DB2)
    public Teacher getById(Serializable id) {
        return super.getById(id);
    }

    @Override
    @DataSource(DataSourceEnum.DB2)
    public List list(Wrapper queryWrapper) {
        return super.list(queryWrapper);
    }

    @Override
    @DataSource(DataSourceEnum.DB2)
    public List list() {
        return super.list();
    }

    @Override
    @DataSource(DataSourceEnum.DB2)
    public IPage page(IPage page, Wrapper queryWrapper) {
        return super.page(page,queryWrapper);
    }

    @Override
    @DataSource(DataSourceEnum.DB2)
    public IPage page(IPage page) {
        return super.page(page);
    }
}

VO

package com.xxl.vo;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

@Data
@ApiModel("学生vo")
public class StudentVo {

    @ApiModelProperty("学生姓名")
    private String name;

    @ApiModelProperty("学生年龄")
    private Integer age;

    @ApiModelProperty("学生班级")
    private String classname;
}

package com.xxl.vo;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

@Data
@ApiModel("老师vo")
public class TeacherVo {

    @ApiModelProperty("老师姓名")
    private String name;

    @ApiModelProperty("老师年龄")
    private Integer age;

    @ApiModelProperty("老师教的学科")
    private String subject;
}

Controller

package com.xxl.controller;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xxl.entity.Student;
import com.xxl.service.StudentService;
import com.xxl.vo.StudentVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@Api("对学生表CRUD")
@RestController
@RequestMapping("/student")
public class StudentController {

    @Autowired
    private StudentService studentService;

    @ApiOperation("添加学生")
    @PostMapping("/add")
    public String add(@RequestBody StudentVo student){
        Student stu = new Student();
        stu.setName(student.getName());
        stu.setAge(student.getAge());
        stu.setClassname(student.getClassname());
        return studentService.save(stu)?"添加成功":"添加失败";
    }

    @ApiOperation("删除学生")
    @DeleteMapping("/delete/{id}")
    public String delete(@ApiParam("学生的主键id")@PathVariable(value = "id") Integer id){
        return studentService.removeById(id)?"删除成功":"删除失败";
    }

    @ApiOperation("修改学生")
    @PostMapping("/update")
    public String update(@RequestBody Student student){
        return studentService.updateById(student)?"修改成功":"修改失败";
    }

    @ApiOperation(value = "查询学生")
    @GetMapping("/list")
    public List list(){
        Wrapper wrapper = new QueryWrapper<>();
        return studentService.list(wrapper);
    }
}

package com.xxl.controller;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xxl.entity.Teacher;
import com.xxl.service.TeacherService;
import com.xxl.vo.TeacherVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@Api("对老师表CRUD")
@RestController
@RequestMapping("/teacher")
public class TeacherController {

    @Autowired
    private TeacherService teacherService;

    @ApiOperation(value = "添加老师")
    @PostMapping("/add")
    public String add(@RequestBody TeacherVo teacher){
        Teacher tea = new Teacher();
        tea.setName(teacher.getName());
        tea.setAge(teacher.getAge());
        tea.setSubject(teacher.getSubject());
        return teacherService.save(tea)?"添加成功":"添加失败";
    }

    @ApiOperation("删除老师")
    @DeleteMapping("/delete/{id}")
    public String delete(@ApiParam("老师的主键id")@PathVariable(value = "id") Integer id){
        return teacherService.removeById(id)?"删除成功":"删除失败";
    }

    @ApiOperation("修改老师")
    @PostMapping("/update")
    public String update(@RequestBody Teacher teacher){
        return teacherService.updateById(teacher)?"修改成功":"修改失败";
    }

    @ApiOperation(value = "查询老师")
    @GetMapping("/list")
    public List list(){
        Wrapper wrapper = new QueryWrapper<>();
        return teacherService.list(wrapper);
    }
}

11.效果

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/zaji/5671388.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-12-16
下一篇2022-12-17

发表评论

登录后才能评论

评论列表(0条)

    保存