Springboot integriert mehrere Datenquellen mysql/psql+, um den Fehler zu beheben, dass mehrere Datenquellen mybatis-plus kein Paging durchführen können
1. Springboot integriert mehrere Datenquellen
1.1 Einführung in Abhängigkeiten
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
1.2 Konfigurieren Sie die YML-Datei
Achten Sie unbedingt auf die Namen der verschiedenen Datenquellen unter den Kommentaren, da der nächste Schritt darin besteht, die Konfiguration der YML-Datei manuell und nicht automatisch abzurufen. Da diese beiden Datenbanken möglicherweise nicht gleichzeitig verwendet werden, habe ich den aktivierten Schalter hinzugefügt. Wenn er wahr ist, wird die Datenbankkonfiguration geladen
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 Erstellen Sie ein Konfigurationspaket. Solange SpringBoot es scannt, müssen der Startklasse keine besonderen Kommentare hinzugefügt werden
Verwandte Konfiguration von 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 laden
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-bezogene Konfiguration
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
Im Inneren basePackages
wird der Speicherort der von MyBatis bereitgestellten Mapper-Schnittstelle gescannt. Das sqlSessionTemplateRef kann nach Belieben benannt werden und hat keinen Einfluss auf die folgenden Anmerkungen. Beachten Sie jedoch, dass es sich von den Namen der anderen Konfigurationsklassen unterscheiden sollte.
2. Vor jeder Methode der MysqlDataSourceConfig-Klasse befinden sich Anmerkungen @Primary
, und die Methode der PsqlDataSourceConfig-Klasse wird zu @Qualifier (der Name hier ist auch willkürlich, solange diese Klassen unterschiedlich sind). Dies soll verhindern, dass SpringBoot automatisch zusammengebaut wird . Mehrere Datenquellen, Sie wissen nicht, welche Sie verwenden sollen, und melden beim Start einen Fehler. Wenn mehr als zwei Datenquellen vorhanden sind, verwenden Sie die Annotation @Qualifier wie PsqlDataSourceConfig für die übrigen Methoden der Konfigurationsklasse.
2. Beheben Sie den Fehler, dass mybatis-plus bei mehreren Datenquellen keine Paginierung durchführen kann
Problem:
Wenn das Projekt eine einzelne Datenquelle konfiguriert, funktioniert das mybatis-plus-Paging-Plugin normal. Bei der Konfiguration mehrerer Datenquellen schlägt das mybatis-plus-Paging-Plugin fehl.
2.1 Mybatis-plus-Paging-Plugin injizieren
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
paginationInterceptor.setDialectType(DbType.POSTGRE_SQL.getDb());
return paginationInterceptor;
}
2.2 Konfiguration unter mehreren Datenquellen
@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();
}
Die Konfiguration mehrerer Datenquellen muss per Code implementiert werden, anstatt die Standardeigenschaftenkonfiguration zu verwenden. Hier verwende ich
MybatisSqlSessionFactoryBean, um SqlSessionFactory zu konfigurieren, und MybatisSqlSessionFactoryBean verfügt lediglich über eine Methode namens
setPlugins:, die zum Konfigurieren von Plugins verwendet wird.
Mit MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean(); soll das Problem gelöst werden, dass der Mapper von mybatis-plus beim Scannen von Paketen nicht gescannt werden kann.