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

Posted Vashon_杨博程

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot+druid同时连接不同类型数据库及PageHelper支持多类型库查询分页功能相关的知识,希望对你有一定的参考价值。

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

 

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

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

pom.xml配置:

<?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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.ywx</groupId>
    <artifactId>springboot-bi</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-bi</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <mybatis.boot.version>1.3.2</mybatis.boot.version>
        <druid.version>1.1.13</druid.version>
        <poi.version>3.17</poi.version>
    </properties>


    <dependencies>
        <!--SpringBoot Web容器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- SpringBoot 拦截器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--常用工具类 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <!-- pagehelper 分页插件 -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.10</version>
        </dependency>
        <!-- SpringBoot集成mybatis框架 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>$mybatis.boot.version</version>
        </dependency>
        <!--阿里数据库连接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>$druid.version</version>
        </dependency>
        <!-- oracle数据库驱动 -->
        <dependency>
            <groupId>com.oracle</groupId>
            <artifactId>ojdbc14</artifactId>
            <version>10.2.0.1.0</version>
        </dependency>
        <!-- Mysql驱动包 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
        <!-- SpringBoot集成thymeleaf模板 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!-- yml解析器 -->
        <dependency>
            <groupId>org.yaml</groupId>
            <artifactId>snakeyaml</artifactId>
        </dependency>
        <!-- excel工具 -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>$poi.version</version>
        </dependency>
    </dependencies>

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

</project>

注: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<Object, Object> 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

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

 

以上是关于SpringBoot+druid同时连接不同类型数据库及PageHelper支持多类型库查询分页功能的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot整合Druid

SpringBoot 整合--Druid

SpringBoot学习--07配置Druid数据库连接池

springboot mybatis 后台框架平台 集成代码生成器 shiro 权限

SpringBoot 集成 Druid

好用的连接池-druid