原文链接: Spring Boot2.x 动态数据源配置
基于 Spring Boot 2.x、Spring Data JPA、druid、mysql 的动态数据源配置Demo,适合用于数据库的读写分离等应用场景。通过在Service层方法上添加自定义注解实现读写不同的数据库。
配置文件已配置好druid监控相关属性,监控页面链接:ip:8080/druid。账号:admin,密码:123456。详情查看 application.yml 文件。
配置 pom.xml 文件
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.21</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> </dependency> </dependencies>
配置application.yml文件
spring: datasource: druid: primary: driverClassName: com.mysql.cj.jdbc.Driver username: root password: root url: jdbc:mysql://localhost:3306/primary?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8 filters: stat,wall local: driver-class-name: com.mysql.cj.jdbc.Driver username: root password: root url: jdbc:mysql://localhost:3306/local?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8 filters: stat,wall stat-view-servlet: enabled: true login-username: admin login-password: 123456 reset-enable: false url-pattern: /druid/* web-stat-filter: enabled: true # 添加过滤规则 url-pattern: /* # 忽略过滤格式 exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*" jpa: database: MYSQL hibernate: show_sql: true format_sql: true primary-dialect: org.hibernate.dialect.MySQL5InnoDBDialect secondary-dialect: org.hibernate.dialect.MySQL5InnoDBDialect # 打开后会自动在主库生成表 # ddl-auto: update database-platform: org.hibernate.dialect.MySQL5InnoDBDialect # 打开后会自动在主库生成表 # generate-ddl: true
项目目录结构

DataSource.java
package dynamic.data.annotation; import dynamic.data.common.ContextConst; import java.lang.annotation.*; /** * @Author: ChangXuan * @Decription: * @Date: 22:25 2020/2/23 **/ @Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface DataSource { ContextConst.DataSourceType value() default ContextConst.DataSourceType.PRIMARY; }
DynamicDataSourceAspect.java
package dynamic.data.aspect; import dynamic.data.common.ContextConst; import dynamic.data.datasource.DataSourceContextHolder; import dynamic.data.annotation.DataSource; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; import java.lang.reflect.Method; /** * @Author: ChangXuan * @Decription: * @Date: 22:28 2020/2/23 **/ @Component @Aspect public class DynamicDataSourceAspect { @Before("execution(* dynamic.data.service..*.*(..))") public void before(JoinPoint point){ try { DataSource annotationOfClass = point.getTarget().getClass().getAnnotation(DataSource.class); String methodName = point.getSignature().getName(); Class[] parameterTypes = ((MethodSignature) point.getSignature()).getParameterTypes(); Method method = point.getTarget().getClass().getMethod(methodName, parameterTypes); DataSource methodAnnotation = method.getAnnotation(DataSource.class); methodAnnotation = methodAnnotation == null ? annotationOfClass:methodAnnotation; ContextConst.DataSourceType dataSourceType = methodAnnotation != null && methodAnnotation.value() !=null ? methodAnnotation.value() :ContextConst.DataSourceType.PRIMARY ; DataSourceContextHolder.setDataSource(dataSourceType.name()); } catch (NoSuchMethodException e) { e.printStackTrace(); } } @After("execution(* dynamic.data.service..*.*(..))") public void after(JoinPoint point){ DataSourceContextHolder.clearDataSource(); } }
ContextConst.java
package dynamic.data.common; /** * @Author: ChangXuan * @Decription: * @Date: 22:17 2020/2/23 **/ public interface ContextConst { enum DataSourceType{ PRIMARY,LOCAL } }
DataSourceContextHolder .java
package dynamic.data.datasource; /** * @Author: ChangXuan * @Decription: * @Date: 22:23 2020/2/23 **/ public class DataSourceContextHolder { private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(); public static void setDataSource(String dbType){ System.out.println("切换到["+dbType+"]数据源"); contextHolder.set(dbType); } public static String getDataSource(){ return contextHolder.get(); } public static void clearDataSource(){ contextHolder.remove(); } }
DynamicDataSource.java
package dynamic.data.datasource;import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;/** * @Author: ChangXuan * @Decription: * @Date: 22:22 2020/2/23 **/public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DataSourceContextHolder.getDataSource(); }}
MutiplyDataSource.java
package dynamic.data.datasource; import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; import dynamic.data.common.ContextConst; 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.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.PlatformTransactionManager; import javax.sql.DataSource; import java.util.HashMap; /** * @Author: ChangXuan * @Decription: * @Date: 22:15 2020/2/23 **/ @Configuration public class MutiplyDataSource { @Bean(name = "dataSourcePrimary") @ConfigurationProperties(prefix = "spring.datasource.druid.primary") public DataSource primaryDataSource(){ return DruidDataSourceBuilder.create().build(); } @Bean(name = "dataSourceLocal") @ConfigurationProperties(prefix = "spring.datasource.druid.local") public DataSource localDataSource(){ return DruidDataSourceBuilder.create().build(); } @Primary @Bean(name = "dynamicDataSource") public DataSource dynamicDataSource() { DynamicDataSource dynamicDataSource = new DynamicDataSource(); //配置默认数据源 dynamicDataSource.setDefaultTargetDataSource(primaryDataSource()); //配置多数据源 HashMap<Object, Object> dataSourceMap = new HashMap(); dataSourceMap.put(ContextConst.DataSourceType.PRIMARY.name(),primaryDataSource()); dataSourceMap.put(ContextConst.DataSourceType.LOCAL.name(),localDataSource()); dynamicDataSource.setTargetDataSources(dataSourceMap); return dynamicDataSource; } /** * 配置@Transactional注解事务 * @return */ @Bean public PlatformTransactionManager transactionManager() { return new DataSourceTransactionManager(dynamicDataSource()); } }
使用
在 DynamicDataSourceAspect.java 中配置的service下使用注解的方式指定执行的方法使用哪个数据库。示例参考下方代码:



来源:https://www.cnblogs.com/chxuan/p/12389075.html