# Springboot多数据源加druid **Repository Path**: jiulititi/Springbootmultidatasouce_druid ## Basic Information - **Project Name**: Springboot多数据源加druid - **Description**: Springboot多数据源加druid - **Primary Language**: Java - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 4 - **Created**: 2022-03-18 - **Last Updated**: 2023-11-12 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 1、添加依赖 要使用druid,这三个依赖必不可少: ```xml com.alibaba druid-spring-boot-starter 1.1.21 com.alibaba druid 1.2.6 log4j log4j 1.2.17 ``` 至于其他的依赖,像lombok、mysql、mybatis等数据库的依赖自行添加。 # 2、编辑`application.properties`配置文件 数据库的内容自行准备好,我这里使用的是我MySQL数据库里的`world`和`sakila`两个数据库做演示。 ```xml #配置应用的端口 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文件夹下的目录结构 ![在这里插入图片描述](https://img-blog.csdnimg.cn/02e7a6a6ce264267a34cf1ca1e4cc6ca.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAKOKKmW_iipkpfuWTpg==,size_16,color_FFFFFF,t_70,g_se,x_16) mybatis-config.xml的内容如下,主要是用于开启驼峰规则,不想要可以不要: ```xml ``` log4j.properties的内容如下: ```xml 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的目录如下: ![在这里插入图片描述](https://img-blog.csdnimg.cn/bf6b57245828473fb1407e94ce1583c7.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAKOKKmW_iipkpfuWTpg==,size_18,color_FFFFFF,t_70,g_se,x_16) 对于多数据源的配置及druid的配置主要在`MultiDataSourceConfig`中进行: ```java 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、测试 在测试类中进行测试: ```java 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(); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/847de609ffd14a86b35c9a88a52ad5fd.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAKOKKmW_iipkpfuWTpg==,size_20,color_FFFFFF,t_70,g_se,x_16) # 6、监控 浏览器输入`http://127.0.0.1:8004/druid/index.html`进行访问druid后台,账号密码在代码的这个位置: ![在这里插入图片描述](https://img-blog.csdnimg.cn/62a9dc056b644faf8e3d89e441209b1a.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAKOKKmW_iipkpfuWTpg==,size_20,color_FFFFFF,t_70,g_se,x_16) 登录 ![在这里插入图片描述](https://img-blog.csdnimg.cn/df002f5e2ae74d98b4b4aa5957aacbce.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAKOKKmW_iipkpfuWTpg==,size_20,color_FFFFFF,t_70,g_se,x_16) 数据源: ![在这里插入图片描述](https://img-blog.csdnimg.cn/d2970bae498a463d914a6f903468b5b3.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAKOKKmW_iipkpfuWTpg==,size_20,color_FFFFFF,t_70,g_se,x_16) 之所以没有显示,是因为还没有初始化,分别取调用一下这两个数据库就行了 ![在这里插入图片描述](https://img-blog.csdnimg.cn/ecdee8c4c4c64cb888c8d21e630f6552.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAKOKKmW_iipkpfuWTpg==,size_20,color_FFFFFF,t_70,g_se,x_16) ![在这里插入图片描述](https://img-blog.csdnimg.cn/18be0a7805da43e38ba034e8fb5c31e1.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAKOKKmW_iipkpfuWTpg==,size_20,color_FFFFFF,t_70,g_se,x_16) 再回到数据源这边看一下,刷新一下: ![在这里插入图片描述](https://img-blog.csdnimg.cn/b39e0d6148ae473e896715560a52dc3f.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAKOKKmW_iipkpfuWTpg==,size_20,color_FFFFFF,t_70,g_se,x_16) 刚刚执行的sql也被监控出来了 ![在这里插入图片描述](https://img-blog.csdnimg.cn/f9c851dac5784d3db60ba74d0e186dc5.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAKOKKmW_iipkpfuWTpg==,size_20,color_FFFFFF,t_70,g_se,x_16) 控制台这边也显示数据库初始化: ![在这里插入图片描述](https://img-blog.csdnimg.cn/d5861f5f42ef4d3399825774b6eea435.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAKOKKmW_iipkpfuWTpg==,size_20,color_FFFFFF,t_70,g_se,x_16)