仓库地址:
https://gitee.com/jiulititi/Springbootmultidatasouce_druid.git
1、添加依赖
要使用druid,这三个依赖必不可少:
<!-- alibaba的druid数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.21</version>
</dependency>
<!--Druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.6</version>
</dependency>
<!--log4j-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
至于其他的依赖,像lombok、mysql、mybatis等数据库的依赖自行添加。
2、编辑application.properties
配置文件
数据库的内容自行准备好,我这里使用的是我MySQL数据库里的world
和sakila
两个数据库做演示。
#配置应用的端口
server.port=8004
jdbc.test1.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.test1.url=jdbc:mysql://localhost:3306/sakila?useSSL=false&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&serverTimezone=Asia/Shanghai
jdbc.test1.username=root
jdbc.test1.password=123456
#切换到Druid数据源
jdbc.test1.type=com.alibaba.druid.pool.DruidDataSource
jdbc.test1.initialSize=2
jdbc.test1.minIdle=2
jdbc.test1.maxActive=3
#配置获取连接等待超时的时间
jdbc.test1.maxWait=6000
#配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
jdbc.test1.timeBetweenEvictionRunsMillis=60000
#配置一个连接在池中最小生存的时间,单位是毫秒
jdbc.test1.minEvictableIdleTimeMillis=300000
jdbc.test1.validationQuery=SELECT 1 FROM DUAL
jdbc.test1.testWhileIdle=true
jdbc.test1.testOnBorrow=false
jdbc.test1.testOnReturn=false
#打开PSCache,并且指定每个连接上PSCache的大小
jdbc.test1.poolPreparedStatements=true
jdbc.test1.maxPoolPreparedStatementPerConnectionSize=20
#配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
jdbc.test1.filters=stat,wall,log4j
#通过connectProperties属性来打开mergeSql功能;慢SQL记录
jdbc.test1.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
#-----------------------------------------------------------------------------------------------------------------------------------------------------------
jdbc.test2.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.test2.url=jdbc:mysql://localhost:3306/world?useSSL=false&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&serverTimezone=Asia/Shanghai
jdbc.test2.username=root
jdbc.test2.password=123456
#切换到Druid数据源
jdbc.test2.type=com.alibaba.druid.pool.DruidDataSource
jdbc.test2.initialSize=2
jdbc.test2.minIdle=2
jdbc.test2.maxActive=3
#配置获取连接等待超时的时间
jdbc.test2.maxWait=6000
#配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
jdbc.test2.timeBetweenEvictionRunsMillis=60000
#配置一个连接在池中最小生存的时间,单位是毫秒
jdbc.test2.minEvictableIdleTimeMillis=300000
jdbc.test2.validationQuery=SELECT 1 FROM DUAL
jdbc.test2.testWhileIdle=true
jdbc.test2.testOnBorrow=false
jdbc.test2.testOnReturn=false
#打开PSCache,并且指定每个连接上PSCache的大小
jdbc.test2.poolPreparedStatements=true
jdbc.test2.maxPoolPreparedStatementPerConnectionSize=20
#配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
jdbc.test2.filters=stat,wall,log4j
#通过connectProperties属性来打开mergeSql功能;慢SQL记录
jdbc.test2.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
#------------------------------------------------------------------------------------------------------------------------------------------------------------
spring.application.name=springboot-logback
spring.profiles.active=dev
#修改thymeleaf访问根路径,访问localhost:8004后默认打开/static/下的index.html
spring.thymeleaf.prefix=classpath:/static/
#开启内置Tomcat请求日志 access.log
server.tomcat.accesslog.enabled=true
#日志格式
server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b
#日志输出目录
server.tomcat.accesslog.directory=${user.home}/log/accesslog/${spring.application.name}
#日志文件名
server.tomcat.accesslog.prefix=access_log
server.tomcat.accesslog.file-date-format=_yyyy-MM-dd
server.tomcat.accesslog.suffix=.log
3、完善其他配置文件和目录结构
3.1、resource文件夹下的目录结构
mybatis-config.xml的内容如下,主要是用于开启驼峰规则,不想要可以不要:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 由于Spring Boot自动配置缘故,此处不必配置,只用来做做样。-->
<!--开启驼峰命名规则自动转换-->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true" />
</settings>
</configuration>
log4j.properties的内容如下:
log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
4、多数据源配置
src的目录如下:
对于多数据源的配置及druid的配置主要在MultiDataSourceConfig
中进行:
package com.example.demo.datasource.multi.config;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
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;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Configuration
public class MultiDataSourceConfig {
//(1) 配置数据源
/*
@Bean : 将其表示为spring的bean,让spring进行管理
@Primary : 指定同一个接口有多个实现类可以注入的时候 , 默认注入哪一个
@ConfigurationProperties : 绑定配置文件中的属性到bean中
*/
@Bean
@ConfigurationProperties(prefix = "jdbc.test1")
public DataSource test1DataSource(){
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "jdbc.test2")
public DataSource test2DataSource(){
return DruidDataSourceBuilder.create().build();
}
/* 实现WEB监控的配置处理
http://127.0.0.1:xxxx/druid/index.html
*/
@Bean
public ServletRegistrationBean druidServlet() {
// 现在要进行druid监控的配置处理操作
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(
new StatViewServlet(), "/druid/*");
// 白名单,多个用逗号分割, 如果allow没有配置或者为空,则允许所有访问
servletRegistrationBean.addInitParameter("allow", "");
// 黑名单,多个用逗号分割 (共同存在时,deny优先于allow)
servletRegistrationBean.addInitParameter("deny", "");
// 控制台管理用户名
servletRegistrationBean.addInitParameter("loginUsername", "root");
// 控制台管理密码
servletRegistrationBean.addInitParameter("loginPassword", "root");
// 是否可以重置数据源,禁用HTML页面上的“Reset All”功能
servletRegistrationBean.addInitParameter("resetEnable", "false");
return servletRegistrationBean ;
}
@Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean() ;
filterRegistrationBean.setFilter(new WebStatFilter());
//所有请求进行监控处理
filterRegistrationBean.addUrlPatterns("/*");
//添加不需要忽略的格式信息
filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.css,/druid/*");
return filterRegistrationBean ;
}
//(2) 配置SqlSessionFactory
/*
每一个SqlSessionFactory都设置了一个DataSource属性 , 所以他们产生的SqlSession就是不同数据库的SqlSession ;
另外TypeAliasesPackage属性表示扫描该属性下的全部java文件作为别名 , 即mapper.xml文件中 select 标签 resultType属性的值 ,
如果不设置则要输入对应实体的全限定名称 , 设置之后只需输入对应实体的类名即可;
MapperLocations 属性用于扫描指定文件下的哪些文件作为MyBatis的xml映射文件;
*/
@Bean
@Primary
public SqlSessionFactory test1SqlSessionFactory(@Qualifier("test1DataSource")DataSource test1DataSource) throws Exception{
SqlSessionFactoryBean fb = new SqlSessionFactoryBean();
fb.setDataSource(test1DataSource);
fb.setTypeAliasesPackage("com.example.demo.datasource");
fb.setMapperLocations(
new PathMatchingResourcePatternResolver().getResources("classpath:/mapper/test1/**/*.xml") //sql映射文件位置
);
fb.setConfigLocation(
new PathMatchingResourcePatternResolver().getResource("classpath:/mapper/mybatis-config.xml") //这里面主要配置驼峰命名规则,不想开启则可以把这一项去掉
);
return fb.getObject();
}
@Bean
public SqlSessionFactory test2SqlSessionFactory(@Qualifier("test2DataSource")DataSource test2DataSource) throws Exception{
SqlSessionFactoryBean fb = new SqlSessionFactoryBean();
fb.setDataSource(test2DataSource);
fb.setTypeAliasesPackage("com.example.demo.datasource");
fb.setMapperLocations(
new PathMatchingResourcePatternResolver().getResources("classpath:/mapper/test2/**/*.xml")
);
return fb.getObject();
}
//(3)配置MapperScannerConfigurer
/*
MapperScannerConfigurer用于配置MyBatis Mapper接口的扫描 ;
该对象可以设置BasePackage 和 AnnotationClass属性,分别表示 扫描哪个包下的文件且标识了指定注解的接口 作为MyBatis 的 Mapper ,
同时还需设置一个SqlSessionFactory;
*/
@Bean(name="test1MapperScannerConfigurer")
public MapperScannerConfigurer test1MapperScannerConfigurer(){
MapperScannerConfigurer configurer = new MapperScannerConfigurer();
configurer.setSqlSessionFactoryBeanName("test1SqlSessionFactory");
configurer.setBasePackage("com.example.demo.datasource");
configurer.setAnnotationClass(test1Dao.class);
return configurer;
}
@Bean(name="test2MapperScannerConfigurer")
public MapperScannerConfigurer test2MapperScannerConfigurer(){
MapperScannerConfigurer configurer = new MapperScannerConfigurer();
configurer.setSqlSessionFactoryBeanName("test2SqlSessionFactory");
configurer.setBasePackage("com.example.demo.datasource");
configurer.setAnnotationClass(test2Dao.class);
return configurer;
}
//自定义的运行器且只能注解在类上的注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Component
public @interface test1Dao {
String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Component
public @interface test2Dao {
String value() default "";
}
//(4)配置 事务管理器 事务管理器只需要指定对应的DataSource即可
@Bean(name="test1TransactionManager")
@Primary
public DataSourceTransactionManager test1TransactionManager(@Qualifier("test1DataSource")DataSource test1DataSource) throws Exception{
return new DataSourceTransactionManager(test1DataSource);
}
@Bean(name="test2TransactionManager")
@Primary
public DataSourceTransactionManager test2TransactionManager(@Qualifier("test2DataSource")DataSource test2DataSource) throws Exception{
return new DataSourceTransactionManager(test2DataSource);
}
}
5、测试
在测试类中进行测试:
package com.example.demo;
import com.alibaba.druid.pool.DruidDataSource;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
@SpringBootTest
class BasedemoApplicationTests {
@Qualifier("test1DataSource")
@Autowired
DataSource dataSource;
@Test
void contextLoads() throws SQLException {
System.out.println(dataSource.getClass());
//获得连接
Connection connection = dataSource.getConnection();
System.out.println(connection);
DruidDataSource druidDataSource = (DruidDataSource) dataSource;
System.out.println("druidDataSource 数据源最大连接数:" + druidDataSource.getMaxActive());
System.out.println("druidDataSource 数据源初始化连接数:" + druidDataSource.getInitialSize());
//关闭连接
connection.close();
}
}
6、监控
浏览器输入http://127.0.0.1:8004/druid/index.html
进行访问druid后台,账号密码在代码的这个位置:
登录
数据源:
之所以没有显示,是因为还没有初始化,分别取调用一下这两个数据库就行了
再回到数据源这边看一下,刷新一下:
刚刚执行的sql也被监控出来了
控制台这边也显示数据库初始化: