SpringBoot+druid同时连接不同类型数据库及PageHelper支持多类型库查询分页功能

SpringBoot+druid同时连接不同类型数据库及PageHelper支持多类型库查询分页功能

 

例子及场景:最近使用SpringBoot+durid需要连接多个数据源:同时支持MySQL、Oracle,遇到问题及处理方法总结如下:

一、SpringBoot+druid支持同时连接MySQL和Oracle

pom.xml配置:



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.1.6.RELEASE
         
    
    com.ywx
    springboot-bi
    0.0.1-SNAPSHOT
    springboot-bi
    Demo project for Spring Boot

    
        1.8
        1.3.2
        1.1.13
        3.17
    


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

        
            org.springframework.boot
            spring-boot-starter-test
            test
        
        
        
            org.apache.commons
            commons-lang3
        
        
        
            com.github.pagehelper
            pagehelper-spring-boot-starter
            1.2.10
        
        
        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter
            ${mybatis.boot.version}
        
        
        
            com.alibaba
            druid-spring-boot-starter
            ${druid.version}
        
        
        
            com.oracle
            ojdbc14
            10.2.0.1.0
        
        
        
            mysql
            mysql-connector-java
            5.1.6
        
        
        
            org.springframework.boot
            spring-boot-starter-thymeleaf
        
        
        
            org.yaml
            snakeyaml
        
        
        
            org.apache.poi
            poi-ooxml
            ${poi.version}
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    


注:oracle驱动包在maven仓库中找不到,需下载手动导入到maven仓库。

yml配置文件:

spring:
  datasource:
    druid:
      datasource1:
        url: jdbc:oracle:thin:@10.xx.xx.xx:1521:orcl
        username: xxxx
        password: xxxx
        driverClassName: oracle.jdbc.OracleDriver

      datasource2:
        # 数据源开关/默认关闭
        url: jdbc:oracle:thin:@10.xx.xx.xx:1521:orcl
        username: xepacs
        password: xxx
        driverClassName: oracle.jdbc.driver.OracleDriver

      datasource3:
        url: jdbc:mysql://10.xx.xx.xx:3306/ecg
        username: ecg
        password: xxx
        driverClassName: com.mysql.jdbc.Driver

      # 初始连接数
      initialSize: 5
      # 最小连接池数量
      minIdle: 10
      # 最大连接池数量
      maxActive: 20
      # 配置获取连接等待超时的时间
      maxWait: 60000
      # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
      timeBetweenEvictionRunsMillis: 60000
      # 配置一个连接在池中最小生存的时间,单位是毫秒
      minEvictableIdleTimeMillis: 300000
      # 配置一个连接在池中最大生存的时间,单位是毫秒
      maxEvictableIdleTimeMillis: 900000
      # 配置检测连接是否有效
      validationQuery: SELECT 1 FROM DUAL
      testWhileIdle: true
      testOnBorrow: false
      testOnReturn: false
      statViewServlet:
        enabled: true
        url-pattern: /monitor/druid/*
      filter:
        stat:
          # 慢SQL记录
          log-slow-sql: true
          slow-sql-millis: 1000
          merge-sql: true
        wall:
          config:
            multi-statement-allow: true

数据源基本参数配置类:

package com.ywx.framework.config.properties;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

/**
 * 数据源配置文件封装类.
 *
 * @author ybc
 * @date 2019-06-25-10:17
 */
@Configuration
public class DruidProperties {
    @Value("${spring.datasource.druid.initialSize}")
    private int initialSize;

    @Value("${spring.datasource.druid.minIdle}")
    private int minIdle;

    @Value("${spring.datasource.druid.maxActive}")
    private int maxActive;

    @Value("${spring.datasource.druid.maxWait}")
    private int maxWait;

    @Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}")
    private int timeBetweenEvictionRunsMillis;

    @Value("${spring.datasource.druid.minEvictableIdleTimeMillis}")
    private int minEvictableIdleTimeMillis;

    @Value("${spring.datasource.druid.maxEvictableIdleTimeMillis}")
    private int maxEvictableIdleTimeMillis;

    @Value("${spring.datasource.druid.validationQuery}")
    private String validationQuery;

    @Value("${spring.datasource.druid.testWhileIdle}")
    private boolean testWhileIdle;

    @Value("${spring.datasource.druid.testOnBorrow}")
    private boolean testOnBorrow;

    @Value("${spring.datasource.druid.testOnReturn}")
    private boolean testOnReturn;

    public DruidDataSource dataSource(DruidDataSource datasource) {
        /** 配置初始化大小、最小、最大 */
        datasource.setInitialSize(initialSize);
        datasource.setMaxActive(maxActive);
        datasource.setMinIdle(minIdle);

        /** 配置获取连接等待超时的时间 */
        datasource.setMaxWait(maxWait);

        /** 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 */
        datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);

        /** 配置一个连接在池中最小、最大生存的时间,单位是毫秒 */
        datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis);

        /**
         * 用来检测连接是否有效的sql,要求是一个查询语句,常用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。
         */
        datasource.setValidationQuery(validationQuery);
        /** 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 */
        datasource.setTestWhileIdle(testWhileIdle);
        /** 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */
        datasource.setTestOnBorrow(testOnBorrow);
        /** 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */
        datasource.setTestOnReturn(testOnReturn);
        return datasource;
    }
}

数据源配置类:

package com.ywx.framework.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.ywx.framework.common.enums.DataSourceType;
import com.ywx.framework.config.properties.DruidProperties;
import com.ywx.framework.datasource.DynamicDataSource;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * @author ywx
 * @date 2019-06-25-10:16
 */
@Configuration
public class DruidConfig {
    @Bean
    @ConfigurationProperties("spring.datasource.druid.datasource1")
    public DataSource tmsDataSource(DruidProperties druidProperties) {
        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
        return druidProperties.dataSource(dataSource);
    }

    @Bean
    @ConfigurationProperties("spring.datasource.druid.datasource2")
    //@ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")
    public DataSource pacsDataSource(DruidProperties druidProperties) {
        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
        return druidProperties.dataSource(dataSource);
    }

    @Bean
    @ConfigurationProperties("spring.datasource.druid.datasource3")
    public DataSource ecgDataSource(DruidProperties druidProperties) {
        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
        return druidProperties.dataSource(dataSource);
    }

    @Bean(name = "dynamicDataSource")
    @Primary
    public DynamicDataSource dataSource(DataSource tmsDataSource, DataSource pacsDataSource, DataSource ecgDataSource) {
        Map targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceType.FIRST.name(), tmsDataSource);
        targetDataSources.put(DataSourceType.SECOND.name(), pacsDataSource);
        targetDataSources.put(DataSourceType.THIRD.name(), ecgDataSource);
        return new DynamicDataSource(tmsDataSource, targetDataSources);
    }
}

以上,已经完成了MySQL和Oracle数据源的配置了,数据源可以正常连接,但是查询数据后如果需要通过PageHelper实现分页的话,还需要配置PageHelper支持不同类型数据库分页sql的切换。

二、PageHelper配置自动支持不同类型数据库分页的切换

 

如果使用单库连接,可以使用以下配置:

# PageHelper分页插件
pagehelper: 
  helperDialect: mysql
  reasonable: true
  supportMethodsArguments: true
  params: count=countSql

可以参考PageHelper官网文档

(1) helperDialect:分页插件会自动检测当前的数据库链接,自动选择合适的分页方式。 你可以配置helperDialect属性来指定分页插件使用哪种方言。配置时,可以使用下面的缩写值:
oracle,mysql,mariadb,sqlite,hsqldb,postgresql,db2,sqlserver,informix,h2,sqlserver2012,derby
特别注意:使用 SqlServer2012 数据库时,需要手动指定为 sqlserver2012,否则会使用 SqlServer2005 的方式进行分页。
你也可以实现 AbstractHelperDialect,然后配置该属性为实现类的全限定名称即可使用自定义的实现方法。
(2) offsetAsPageNum:默认值为 false,该参数对使用 RowBounds 作为分页参数时有效。 当该参数设置为 true 时,会将 RowBounds 中的 offset 参数当成 pageNum 使用,可以用页码和页面大小两个参数进行分页。
(3) rowBoundsWithCount:默认值为false,该参数对使用 RowBounds 作为分页参数时有效。 当该参数设置为true时,使用 RowBounds 分页会进行 count 查询。
(4) pageSizeZero:默认值为 false,当该参数设置为 true 时,如果 pageSize=0 或者 RowBounds.limit = 0 就会查询出全部的结果(相当于没有执行分页查询,但是返回结果仍然是 Page 类型)。
(5) reasonable:分页合理化参数,默认值为false。当该参数设置为 true 时,pageNum<=0 时会查询第一页, pageNum>pages(超过总数时),会查询最后一页。默认false 时,直接根据参数进行查询。
(6) params:为了支持startPage(Object params)方法,增加了该参数来配置参数映射,用于从对象中根据属性名取值, 可以配置 pageNum,pageSize,count,pageSizeZero,reasonable,不配置映射的用默认值, 默认值为pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero=pageSizeZero。
 (7) supportMethodsArguments:支持通过 Mapper 接口参数来传递分页参数,默认值false,分页插件会从查询方法的参数值中,自动根据上面 params 配置的字段中取值,查找到合适的值时就会自动分页。 使用方法可以参考测试代码中的 com.github.pagehelper.test.basic 包下的 ArgumentsMapTest 和 ArgumentsObjTest。
(8) autoRuntimeDialect:默认值为 false。设置为 true 时,允许在运行时根据多数据源自动识别对应方言的分页 (不支持自动选择sqlserver2012,只能使用sqlserver)

如果使用多数据源,需要修改pagehelper配置项,配置如下:

# PageHelper分页插件
pagehelper:
  #  helperDialect: mysql
  reasonable: false
  supportMethodsArguments: true
  params: count=countSql
  # 默认false,当为true时,自动检验适合的数据库
  auto-dialect: true
  # 这个一定要加上,不然mysql和oracle分页两个只能用一个,另一个会报错,加上后,两中数据库分页都可以用了
  auto-runtime-dialect: true

以上,已经完成支持不同类型数据库多数据源的连接已经分页实现了。

 

你可能感兴趣的:(SpringCloud,java)