一、配置數據源
# 數據源
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);
}