本篇主要分两部分 ①springboot整合druid的代码配置,以及druid的监控页面演示;②对实际场景中多数据源的配置使用进行讲解。
可以用idea快速生成一个可运行的demo工程,具体可以参考如何快速创建springboot项目
org.springframework.boot spring-boot-starter-data-jdbcmysql mysql-connector-javaruntime com.alibaba druid1.2.17 log4j log4j1.2.17 org.springframework.boot spring-boot-starter-jdbcorg.springframework.boot spring-boot-starter-web
spring: datasource: username: root password: root url: jdbc:mysql://localhost:3306/firsttest?serverTimezone=UTC&useUnicode=true@characterEncoding=utf-8 driver-class-name: com.mysql.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource poolPreparedStatements: true #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入 #如果允许时报错 java.lang.ClassNotFoundException: org.apache.log4j.Priority #则导入 log4j 依赖即可,Maven 地址: https://mvnrepository.com/artifact/log4j/log4j filters: stat,wall,log4j maxPoolPreparedStatementPerConnectionSize: 20 useGlobalDataSourceStat: true connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
package com.czing.jdbcdemo.config; import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.support.http.StatViewServlet; import com.alibaba.druid.support.http.WebStatFilter; import org.springframework.boot.context.properties.ConfigurationProperties; 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 javax.servlet.Servlet; import javax.sql.DataSource; import java.util.Arrays; import java.util.HashMap; import java.util.Map; /** * @Description TODO * @Author wangchengzhi * @Date 2023/5/10 21:53 */ @Configuration public class DruidConfig { @ConfigurationProperties(prefix = "spring.datasource") @Bean public DataSource druidDataSource(){ return new DruidDataSource(); } /** * @Author wangchengzhi * @Description * 向DruidConfig中添加代码,配置druid监控管理台的servlet * @Date 22:12 2023/5/10 * @Param * @return **/ @Bean public ServletRegistrationBean druidServletRegistrationBean(){ ServletRegistrationBeanservletRegistrationBean = new ServletRegistrationBean<>(new StatViewServlet(),"/druid/*"); Map initParams = new HashMap<>(); initParams.put("loginUsername","root"); initParams.put("loginPassword","root"); //后台允许谁可以访问 //initParams.put("allow", "localhost"):表示只有本机可以访问 //initParams.put("allow", ""):为空或者为null时,表示允许所有访问 initParams.put("allow",""); //deny:Druid 后台拒绝谁访问 //initParams.put("msb", "192.168.1.20");表示禁止此ip访问 servletRegistrationBean.setInitParameters(initParams); return servletRegistrationBean; } @Bean public FilterRegistrationBean webStatFilter() { FilterRegistrationBean bean = new FilterRegistrationBean(); bean.setFilter(new WebStatFilter()); //exclusions:设置哪些请求进行过滤排除掉,从而不进行统计 Map initParams = new HashMap<>(); initParams.put("exclusions", "*.js,*.css,/druid/*"); bean.setInitParameters(initParams); //"/*" 表示过滤所有请求 bean.setUrlPatterns(Arrays.asList("/*")); return bean; } }
package com.czing.jdbcdemo.controller; import com.czing.jdbcdemo.mult.DataSource; import com.czing.jdbcdemo.mult.DataSourceType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; import java.util.Map; /** * @Description TODO * @Author wangchengzhi * @Date 2023/5/10 17:12 */ @RestController public class JDBCController { @Autowired JdbcTemplate jdbcTemplate; /** * @Author wangchengzhi * @Description * 使用springboot自带的jdbcTemplate实现数据库操作 * @Date 21:34 2023/5/10 * @Param * @return **/ @RequestMapping("/selectTest") public List
项目启动日志:
druid的监控页面访问 http://localhost:8080/druid/sql.html
访问编写的controller测试类:http://localhost:8080/selectTest(访问之后可以观察druid监控页面的情况)
修改application.yml文件
spring: datasource: local: username: root password: root #注意多数据源配置的时候此处为jdbc-url jdbc-url: jdbc:mysql://localhost:3306/firsttest?serverTimezone=UTC&useUnicode=true@characterEncoding=utf-8 driver-class-name: com.mysql.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource remote: username: root password: root jdbc-url: jdbc:mysql://localhost:3306/test?serverTimezone=UTC&useUnicode=true@characterEncoding=utf-8 driver-class-name: com.mysql.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource
编写多数据源的配置类:
package com.czing.jdbcdemo.config; import com.czing.jdbcdemo.mult.DataSourceType; import com.czing.jdbcdemo.mult.DynamicDataSource; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.jdbc.DataSourceBuilder; 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; /** * @Description TODO * @Author wangchengzhi * @Date 2023/5/10 23:07 */ @Configuration public class DataSourceConfig { @Bean @ConfigurationProperties("spring.datasource.remote") public DataSource remoteDataSource() { return DataSourceBuilder.create().build(); } @Bean @ConfigurationProperties("spring.datasource.local") public DataSource localDataSource() { return DataSourceBuilder.create().build(); } @Bean(name = "dynamicDataSource") @Primary public DynamicDataSource dataSource(DataSource remoteDataSource, DataSource localDataSource) { Map
使用自定义注解,在查询方法的时候指定对应的数据源:
package com.czing.jdbcdemo.mult; public enum DataSourceType { REMOTE, LOCAL }
package com.czing.jdbcdemo.mult; /** * @Description TODO * @Author wangchengzhi * @Date 2023/5/10 22:57 */ public class DynamicDataSourceContextHolder { /** * 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本, * 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。 */ private static final ThreadLocalCONTEXT_HOLDER = new ThreadLocal<>(); /** * 设置数据源变量 * @param dataSourceType */ public static void setDataSourceType(String dataSourceType){ System.out.printf("切换到{%s}数据源", dataSourceType); CONTEXT_HOLDER.set(dataSourceType); } /** * 获取数据源变量 * @return */ public static String getDataSourceType(){ return CONTEXT_HOLDER.get(); } /** * 清空数据源变量 */ public static void clearDataSourceType(){ CONTEXT_HOLDER.remove(); } }
package com.czing.jdbcdemo.mult; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; import javax.sql.DataSource; import java.util.Map; /** * @Description TODO * @Author wangchengzhi * @Date 2023/5/10 23:03 */ public class DynamicDataSource extends AbstractRoutingDataSource { public DynamicDataSource(DataSource defaultTargetDataSource, Map
package com.czing.jdbcdemo.config; import com.czing.jdbcdemo.mult.DataSourceType; import com.czing.jdbcdemo.mult.DynamicDataSource; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.jdbc.DataSourceBuilder; 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; /** * @Description TODO * @Author wangchengzhi * @Date 2023/5/10 23:07 */ @Configuration public class DataSourceConfig { @Bean @ConfigurationProperties("spring.datasource.remote") public DataSource remoteDataSource() { return DataSourceBuilder.create().build(); } @Bean @ConfigurationProperties("spring.datasource.local") public DataSource localDataSource() { return DataSourceBuilder.create().build(); } @Bean(name = "dynamicDataSource") @Primary public DynamicDataSource dataSource(DataSource remoteDataSource, DataSource localDataSource) { Map
package com.czing.jdbcdemo.mult; import java.lang.annotation.*; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface DataSource { /** * 切换数据源名称 */ DataSourceType value() default DataSourceType.REMOTE; }
package com.czing.jdbcdemo.mult; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import java.lang.reflect.Method; /** * @Description TODO * @Author wangchengzhi * @Date 2023/5/11 10:09 */ @Aspect @Order(1) @Component public class DataSourceAspect { @Pointcut("@annotation(com.czing.jdbcdemo.mult.DataSource)") public void dsPointCut() { } @Around("dsPointCut()") public Object around(ProceedingJoinPoint point) throws Throwable { MethodSignature signature = (MethodSignature) point.getSignature(); Method method = signature.getMethod(); DataSource dataSource = method.getAnnotation(DataSource.class); if (dataSource != null) { DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name()); } try { return point.proceed(); } finally { // 销毁数据源 在执行方法之后 DynamicDataSourceContextHolder.clearDataSourceType(); } } }
package com.czing.jdbcdemo.controller; import com.czing.jdbcdemo.mult.DataSource; import com.czing.jdbcdemo.mult.DataSourceType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; import java.util.Map; /** * @Description TODO * @Author wangchengzhi * @Date 2023/5/10 17:12 */ @RestController public class JDBCController { @Autowired JdbcTemplate jdbcTemplate; /** * @Author wangchengzhi * @Description * 使用springboot自带的jdbcTemplate实现数据库操作 * @Date 21:34 2023/5/10 * @Param * @return **/ @RequestMapping("/selectTest") @DataSource(value=DataSourceType.LOCAL) public List> getTestAccount(){ String sql ="select * from account"; List > maps = jdbcTemplate.queryForList(sql); return maps; } /** * @Author wangchengzhi * @Description * 使用springboot自带的jdbcTemplate实现数据库操作 * @Date 21:34 2023/5/10 * @Param * @return **/ @RequestMapping("/selectRemote") @DataSource(DataSourceType.REMOTE) public List > getRemoteAccount(){ String sql ="select * from account"; List > maps = jdbcTemplate.queryForList(sql); return maps; } }
http://localhost:8080/selectTest 的访问数据:
http://localhost:8080/selectRemote 的访问数据
以上为springboot实现druid配置查询的demo,并且演示了如何实现多数据源配置动态切换的代码实现,注意多数据源配置的时候url的配置为jdbc-url,其他运行中遇到的问题欢迎留言交流,希望对您的学习有所帮助。