springboot在集成多数据源+mybatis-plus无法进行分页的BUG

2023-11-08

1.springboot在集成多数据源

1.1引入依赖

<dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <scope>runtime</scope>
        </dependency>

1.2配置yml文件

其中请务必关注注释下面的不同的数据源的名字,因为下一步是手动获取yml文件的配置,并非自动配置。因为不一定会同时使用这两个数据库,所以我加了enabled开关,如果为true,才会加载数据库配置

spring:
  #mysql数据源
  mysqldb:
    enabled: false
    driver-class-name: com.mysql.cj.jdbc.Driver
    password: root
    url: jdbc:mysql://127.0.0.1:3306/test?characterEncoding=UTF-8&useUnicode=true&serverTimezone=Asia/Shanghai&allowMultiQueries=true&useAffectedRows=true&useSSL=false
    username: root
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
    filters: stat,wall,log4j
    initialSize: 5
    maxActive: 20
    maxPoolPreparedStatementPerConnectionSize: 20
    maxWait: 60000
    minEvictableIdleTimeMillis: 300000
    minIdle: 5
    poolPreparedStatements: true
    testOnBorrow: false
    testOnReturn: false
    testWhileIdle: true
    timeBetweenEvictionRunsMillis: 60000
    validationQuery: SELECT 1 FROM DUAL
  #psql数据源
  psqldb:
    enabled: true
    driver-class-name: org.postgresql.Driver
    url: jdbc:postgresql://127.0.0.1:9543/test
    username: postgres
    password: postgres
    # 初始化大小,最小,最大
    initialSize: 1
    minIdle: 3
    maxActive: 200
    # 配置获取连接等待超时的时间
    maxWait: 60000
    # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
    timeBetweenEvictionRunsMillis: 60000
    # 配置一个连接在池中最小生存的时间,单位是毫秒
    minEvictableIdleTimeMillis: 40000
    validationQuery: select 'x'
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false

1.3创建config包,这个只要让SpringBoot扫描到就行,并不需要在启动类上特别加注释

mysql的相关配置

import lombok.Data;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.io.Serializable;


@Component
@Data
@ConfigurationProperties(prefix = "spring.mysqldb")
public class MysqlDataSourceProperties implements Serializable {

    private String driverClassName;
    private String url;
    private String username;
    private String password;
    private String connectionProperties;
    private String filters;
    private Integer initialSize;
    private Integer maxActive;
    private Integer maxPoolPreparedStatementPerConnectionSize;
    private Integer maxWait;
    private Integer minEvictableIdleTimeMillis;
    private Integer minIdle;
    private boolean poolPreparedStatements;
    private boolean testOnBorrow;
    private boolean testOnReturn;
    private boolean testWhileIdle;
    private Integer timeBetweenEvictionRunsMillis;
    private String validationQuery;
    private boolean enabled;

}

加载MySQL


import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.autoconfigure.SpringBootVFS;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.mapping.DatabaseIdProvider;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
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 org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.sql.DataSource;
import java.util.List;

@Configuration
## ConditionalOnProperty指定enabled开启时,才会加载该数据库相关信息
@ConditionalOnProperty(prefix = "spring.mysqldb", name = "enabled", havingValue = "true")
@MapperScan(basePackages = "com.koal.ipsec.mapper", sqlSessionFactoryRef = "mysqlSqlSessionFactory")
public class MysqlDataSourceConfig {

    @Autowired
    private MysqlDataSourceProperties mysqlDataSourceProperties;

    @Bean(name = "mysqlDataSource")
    public DataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(mysqlDataSourceProperties.getDriverClassName());
        dataSource.setUrl(mysqlDataSourceProperties.getUrl());
        dataSource.setUsername(mysqlDataSourceProperties.getUsername());
        dataSource.setPassword(mysqlDataSourceProperties.getPassword());
        dataSource.setInitialSize(mysqlDataSourceProperties.getInitialSize());
        dataSource.setMinIdle(mysqlDataSourceProperties.getMinIdle());
        dataSource.setMaxActive(mysqlDataSourceProperties.getMaxActive());
        return dataSource;
    }

    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        paginationInterceptor.setDialectType(DbType.MYSQL.getDb());
        return paginationInterceptor;
    }

    @Bean(name = "mysqlSqlSessionFactory")
    @Primary
    public SqlSessionFactory sqlSessionFactory(@Qualifier("mysqlDataSource") DataSource dataSource) throws Exception {
      ##注意: Mybatis plus分页插件配置必须使用MybatisSqlSessionFactoryBean ,否则分页失效
      ## MybatisSqlSessionFactoryBean 是为了解决扫包的时候无法扫描mybatis-plus的mapper的问题。
        final MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
       ## 重点
        MybatisConfiguration mybatisConfiguration = new MybatisConfiguration();
        mybatisSqlSessionFactoryBean.setConfiguration(mybatisConfiguration);
        mybatisSqlSessionFactoryBean.setDataSource(dataSource);
        mybatisSqlSessionFactoryBean.setPlugins(new Interceptor[]{paginationInterceptor()});
        ## 指定enum类的扫描
        mybatisSqlSessionFactoryBean.setTypeEnumsPackage("com.test.constant");
        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        Resource[] resources = resourcePatternResolver.getResources("classpath*:mapper/*Mapper.xml");
        mybatisSqlSessionFactoryBean.setMapperLocations(resources);
        return mybatisSqlSessionFactoryBean.getObject();
    }
    @Bean(name = "mysqlSqlSessionTemplate")
    @Primary
    public SqlSessionTemplate sqlSessionTemplate(@Qualifier("mysqlSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
    @Bean(name = "mysqlTransactionManager")
    public DataSourceTransactionManager dataSourceTransactionManager(@Qualifier("mysqlDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

}

psql相关配置


import lombok.Data;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.io.Serializable;

@Component
@Data
@ConfigurationProperties(prefix = "spring.psqldb")
public class PsqlDataSourceProperties implements Serializable {

    private String driverClassName;
    private String url;
    private String username;
    private String password;
    private Integer initialSize;
    private Integer maxActive;
    private Integer maxWait;
    private Integer minIdle;
    private Integer timeBetweenEvictionRunsMillis;
    private Integer minEvictableIdleTimeMillis;
    private String validationQuery;
    private boolean testOnBorrow;
    private boolean testOnReturn;
    private boolean testWhileIdle;

}


import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;

@Configuration
@ConditionalOnProperty(prefix = "spring.psqldb", name = "enabled", havingValue = "true")
@MapperScan(basePackages = "com.koal.ipsec.mapper", sqlSessionFactoryRef = "psqlSqlSessionFactory")
public class PsqlDataSourceConfig {

    @Autowired
    private PsqlDataSourceProperties psqlDataSourceProperties;

    @Bean(name = "psqlDataSource")
    public DataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(psqlDataSourceProperties.getDriverClassName());
        dataSource.setUrl(psqlDataSourceProperties.getUrl());
        dataSource.setUsername(psqlDataSourceProperties.getUsername());
        dataSource.setPassword(psqlDataSourceProperties.getPassword());
        dataSource.setInitialSize(psqlDataSourceProperties.getInitialSize());
        dataSource.setMinIdle(psqlDataSourceProperties.getMinIdle());
        dataSource.setMaxActive(psqlDataSourceProperties.getMaxActive());
        return dataSource;
    }

    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        paginationInterceptor.setDialectType(DbType.POSTGRE_SQL.getDb());
        return paginationInterceptor;
    }

    @Bean(name = "psqlSqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(@Qualifier("psqlDataSource") DataSource dataSource) throws Exception {
        final MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
        MybatisConfiguration mybatisConfiguration = new MybatisConfiguration();
        mybatisSqlSessionFactoryBean.setConfiguration(mybatisConfiguration);
        mybatisSqlSessionFactoryBean.setDataSource(dataSource);
        mybatisSqlSessionFactoryBean.setPlugins(new Interceptor[]{paginationInterceptor()});
       // mybatisSqlSessionFactoryBean.setPlugins(new Interceptor[]{psqlMybatisPlusConfig.paginationInterceptor()});
        mybatisSqlSessionFactoryBean.setTypeEnumsPackage("com.koal.ipsec.constant");
        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        Resource[] resources = resourcePatternResolver.getResources("classpath*:mapper/*Mapper.xml");
        mybatisSqlSessionFactoryBean.setMapperLocations(resources);
        return mybatisSqlSessionFactoryBean.getObject();
    }
    @Bean(name = "psqlSqlSessionTemplate")
    public SqlSessionTemplate sqlSessionTemplate(@Qualifier("psqlSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
    @Bean(name = "psqlTransactionManager")
    public DataSourceTransactionManager dataSourceTransactionManager(@Qualifier("psqlDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }



}

1.MapperScan内的basePackages 是扫描MyBatis提供的mapper接口所在位置,sqlSessionTemplateRef 里面随意起名,对下面的注解没有影响,但是注意,要和其余几个配置类所起的名字要不同。

2.MysqlDataSourceConfig 类每个方法前面都有@Primary注解,而PsqlDataSourceConfig 类方法就变成了@Qualifier(这里面的名字也是随意,只要这几个类不同就行),这个是防止SpringBoot自动装配的时候,发现存在多个数据源,不知道该使用哪个而在启动时报错。 如有两个以上的数据源,就在其余的配置类的方法上和PsqlDataSourceConfig 一样使用@Qualifier注解。

2.解决多数据源mybatis-plus无法进行分页的BUG

问题:
项目配置单数据源的时候,mybatis-plus分页插件正常使用,配置多数据源的时候,mybatis-plus分页插件失效。

2.1注入mybatis-plus分页插件

   @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        paginationInterceptor.setDialectType(DbType.POSTGRE_SQL.getDb());
        return paginationInterceptor;
    }

2.2多数据源下的配置

 @Bean(name = "mysqlSqlSessionFactory")
    @Primary
    public SqlSessionFactory sqlSessionFactory(@Qualifier("mysqlDataSource") DataSource dataSource) throws Exception {
      ##注意: Mybatis plus分页插件配置必须使用MybatisSqlSessionFactoryBean ,否则分页失效
      ## MybatisSqlSessionFactoryBean 是为了解决扫包的时候无法扫描mybatis-plus的mapper的问题。
        final MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
       ## 重点
        MybatisConfiguration mybatisConfiguration = new MybatisConfiguration();
        mybatisSqlSessionFactoryBean.setConfiguration(mybatisConfiguration);
        mybatisSqlSessionFactoryBean.setDataSource(dataSource);
        mybatisSqlSessionFactoryBean.setPlugins(new Interceptor[]{paginationInterceptor()});
        ## 指定enum类的扫描
        mybatisSqlSessionFactoryBean.setTypeEnumsPackage("com.test.constant");
        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        Resource[] resources = resourcePatternResolver.getResources("classpath*:mapper/*Mapper.xml");
        mybatisSqlSessionFactoryBean.setMapperLocations(resources);
        return mybatisSqlSessionFactoryBean.getObject();
    }

多数据源的配置需要用代码实现,而不是使用默认的properties配置。这里我用了
MybatisSqlSessionFactoryBean配置SqlSessionFactory,而MybatisSqlSessionFactoryBean刚好有个方法就是
setPlugins:用于配置插件。

使用MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();是为了解决扫包的时候无法扫描mybatis-plus的mapper的问题。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

springboot在集成多数据源+mybatis-plus无法进行分页的BUG 的相关文章

随机推荐

  • matlab_一组数据元素随机排列

    如何生成一组数据元素随机排列 随机打乱顺序 产生新的排列 1 使用的matlab函数 randperm 1 语法格式 R randperm n 2 函数功能 将数字1 n进行随机排列 排列结果存储在行向量内 3 EX 输入 randperm
  • 网页端扫码通过公众号实现微信授权登录

    1 参考开发文档 https developers weixin qq com doc offiaccount OA Web Apps Wechat webpage authorization html 0 2 先调起微信授权页面 获取co
  • Java学习心得2——构造函数

    1 什么是构造函数 构造函数顾名思义 就是对象被构造的时候就会被调用的函数 例如当你new一个Cat对象的时候 Cat对象的构造函数就会被调用 public static void main String args Cat c new Ca
  • (如何读写文件)流-------输入流

    流 流是一组有序的数据序列 通过流来读写文件 流从方向分输入 输出流 流从单位份字节 字符流 字节输入流 InputStream 抽象父类 基类 常用方法 read 几个重载方法作用不同 int read 输入流一个字节一个字节的读 返回的
  • U3D中对象的自动销毁

    很多游戏中都会重用同一个游戏对象 比如说Dota 一波兵一波兵的被对方消灭 如果尸体不会自动销毁 恐怕地图中的尸体堆积如山不说 配置再厉害的电脑也架不住 这样游戏的性能太低了 需要自动销毁的情形有 游戏对象已经并且永远消失在视野中了 天空中
  • Java基础篇——集合

    活动地址 CSDN21天学习挑战赛 1 为什么使用集合 集合与数组类似 都是容器 我们为什么不用数组而还要使用集合呢 数组的特点 数组定义完成并启动后 类型确定 长度固定 不适合元素的个数和类型不确定的业务场景 更不适合做需要增删的操作 数
  • 如何在手机上运行c语言,各位前辈这两个程序怎么在手机上运行

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 made by ebhrz include include include include include include include global define int cfd 文件描述符
  • Python mailmerge库

    Python mailmerge库 本文使用环境 win10 python3 7 office2016 第0步 按装mailmerge pip install mailmerge 第1步 引用库 from mailmerge import
  • 测试用例设计(增量测试)

    增量测试 在执行模块测试过程中 我们主要有两点考虑 第一 如何设计一个有效的测试用例集 第二 将模块组装成工作程序的方式 第二点考虑很重要 因为它涉及模块测试用例编写的形式 可能用到的测试工具类型 模块编码和测试的顺序 生成测试用例的成本以
  • Markdown的十个常用标志符号

    Markdown 是一种轻量级的 标记语言 它的优点很多 目前也被越来越多的写作爱好者 撰稿者广泛使用 看到这里请不要被 标记 语言 所迷惑 Markdown 的语法十分简单 常用的标记符号也不超过十个 这种相对于更为复杂的HTML 标记语
  • Flutter开发之数据存储-2-文件存储(33)

    数据存储部分在移动开发中是非常重要的部分 无论是一些轻量级的数据 如用户信息 APP配置信息等 还是把需要长期存储的数据写入本地文件或者Sqlite3 都离不开数据存储 上一篇SharedPreferences的使用 今天就练习一下文件存储
  • python求平均数、方差、中位数

    CalStatistics py def getNum 获取用户不定长度的输入 nums iNumStr input 请输入数字 回车退出 while iNumStr nums append eval iNumStr iNumStr inp
  • java mysql差异导出_java 如何从零实现一个数据库差异对比工具?

    对比数据的痛苦 不知道你是否也像我一样 在快乐编写代码的时候 必须进行一些数据库的数据对比工作 诚然 一般的数据差异 比如是每一行的内容不同 市场上有比较成熟的 compare2 等对比工具 但是如果是对比数据的每一列是否相同 这个就会变得
  • 机器人教育和编程教育,家长纠结发问:该选哪一个?

    机器人教育和编程教育 家长纠结发问 该选哪一个 很多家长对于机器人教育和编程教育二者之间的关系都不太懂 究竟二者有何不同 学机器人和学编程有冲突吗 孩子要如何选择呢 我们来一一剖析 1机器人教育与编程教育的区别 涵盖范围不一 机器人教育 机
  • eclipse创建webapp 类型的maven项目

    Eclipse配置maven 配置maven的安装目录 打开Eclipse属性设置面板 Window gt Preferences gt Maven 展开Maven配置界面 选择Installations 如下图 add已经下载好的mave
  • 虚拟机配置之系统网络及防火墙配置

    1 查看网络IP和网关 一般不用修改 在此不作说明 2 配置网络IP地址 1 修改IP地址 root hadoop102 vim etc sysconfig network scripts ifcfg eth0 修改并添加为 3 配置主机名
  • C#中的数据库配置

    初用C 做项目的时候将数据库连接字符串放在注册表中 并且专门写一个窗体让用户能够修改 因为用户不可能自己到注册表中去设置 现在想来 其实没必要 在工程中添加新项 选择 应用程序配置文件 默认名是App config 里面的代码如下
  • PAT-1059 C语言竞赛

    1059 C语言竞赛 20 分 C 语言竞赛是浙江大学计算机学院主持的一个欢乐的竞赛 既然竞赛主旨是为了好玩 颁奖规则也就制定得很滑稽 0 冠军将赢得一份 神秘大奖 比如很巨大的一本学生研究论文集 1 排名为素数的学生将赢得最好的奖品 小黄
  • ECCV22 最新论文汇总(目标检测、图像分割、监督学习、GAN等)

    强烈感谢极市平台提供的论文资源 ECCV 2022 已经放榜 共有1629篇论文中选 录用率还不到20 为了让大家更快地获取和学习到计算机视觉前沿技术 作者对ECCV2022最新论文进行追踪 包括分研究方向的论文及代码汇总 本次更新的 EC
  • springboot在集成多数据源+mybatis-plus无法进行分页的BUG

    springboot在集成多数据源 mysql psql 解决多数据源mybatis plus无法进行分页的BUG 1 springboot在集成多数据源 1 1引入依赖 1 2配置yml文件 1 3创建config包 这个只要让Sprin