一、配置数据源
# 数据源 spring.datasource.druid.write.url=jdbc:mysql://localhost:3380/test spring.datasource.druid.write.username=root spring.datasource.druid.write.password= spring.datasource.druid.write.driver-class-name=com.mysql.jdbc.Driver spring.datasource.druid.read.url=jdbc:mysql://localhost:3381/test spring.datasource.druid.read.username=root spring.datasource.druid.read.password= spring.datasource.druid.read.driver-class-name=com.mysql.jdbc.Driver # JPA spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect spring.jpa.database=mysql spring.jpa.generate-ddl=false spring.jpa.hibernate.ddl-auto=none spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.DefaultComponentSafeNamingStrategy spring.jpa.show-sql=false二、数据源配置类
/** * 数据源配置 * * @author Administrator * */ @Configuration public class DataSourceConfig { public final static String WRITE_DATASOURCE_KEY = "writeDruidDataSource"; public final static String READ_DATASOURCE_KEY = "readDruidDataSource"; @ConfigurationProperties(prefix = "spring.datasource.druid.read") @Bean(name = READ_DATASOURCE_KEY) public DataSource readDruidDataSource() { return new DruidDataSource(); } @ConfigurationProperties(prefix = "spring.datasource.druid.write") @Bean(name = WRITE_DATASOURCE_KEY) public DataSource writeDruidDataSource() { return new DruidDataSource(); } /** * 注入AbstractRoutingDataSource * * @param readDruidDataSource * @param writeDruidDataSource * @return * @throws Exception */ @Bean @Primary public AbstractRoutingDataSource routingDataSource( @Qualifier(READ_DATASOURCE_KEY) DataSource readDruidDataSource, @Qualifier(WRITE_DATASOURCE_KEY) DataSource writeDruidDataSource) throws Exception { DynamicDataSource dataSource = new DynamicDataSource(); Map<Object, Object> targetDataSources = new HashMap<Object, Object>(); targetDataSources.put(WRITE_DATASOURCE_KEY, writeDruidDataSource); targetDataSources.put(READ_DATASOURCE_KEY, readDruidDataSource); dataSource.setTargetDataSources(targetDataSources);// 配置数据源 dataSource.setDefaultTargetDataSource(writeDruidDataSource);// 默认为主库用于写数据 return dataSource; } }三、使用ThreadLocal使数据源与线程绑定
public class DynamicDataSourceHolder { // 使用ThreadLocal把数据源与当前线程绑定 private static final ThreadLocal<String> dataSources = new ThreadLocal<String>(); public static void setDataSource(String dataSourceName) { dataSources.set(dataSourceName); } public static String getDataSource() { return (String) dataSources.get(); } public static void clearDataSource() { dataSources.remove(); } }四、动态数据源配置
public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { // 可以做一个简单的负载均衡策略 String lookupKey = DynamicDataSourceHolder.getDataSource(); System.out.println("------------lookupKey---------" + lookupKey); return lookupKey; } }五、自定义注解
@Target({ ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface TargetDateSource { String dataSource() default "";// 数据源 }七、定义切面,实现数据源切换
@Aspect @Component @Order(0) public class DynamicDataSourceAspect { @Around("execution(public * com.study.mysql.jpa.core..*.*(..))") public Object around(ProceedingJoinPoint pjp) throws Throwable { MethodSignature methodSignature = (MethodSignature) pjp.getSignature(); Method targetMethod = methodSignature.getMethod(); if (targetMethod.isAnnotationPresent(TargetDateSource.class)) { String targetDataSource = targetMethod.getAnnotation(TargetDateSource.class).dataSource(); System.out.println("----------数据源是:" + targetDataSource + "------"); DynamicDataSourceHolder.setDataSource(targetDataSource); } // 执行方法 Object result = pjp.proceed(); DynamicDataSourceHolder.clearDataSource(); return result; } }通过注解@TargetDataSource注解实现读写分离。
@Override @TargetDateSource(dataSource = DataSourceConfig.READ_DATASOURCE_KEY) public WxSpUserInfo findById(String id) { return wxSpUserInfoRepository.findById(id).orElse(null); }