在做DB数据迁移需求的时候要用到多数据源,正好整理下
实际用到以下几个类
配置文件
#端口 server.port: 8080 spring.application.name: lzqdemo # mysql db.driverClassName=com.mysql.jdbc.Driver db.url=jdbc:mysql://127.0.0.1:3306/db1?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&useSSL=false db.username=root db.password=123456 #数据库2 db2.driverClassName=com.mysql.jdbc.Driver db2.url=jdbc:mysql://127.0.0.1:3306/db2?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&useSSL=false db2.username=root db2.password=123456启动类
一定要加上exclude = {DataSourceAutoConfiguration.class}
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
//移除默认数据库配置类
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class DbDemoApplication {
public static void main(String[] args) {
SpringApplication.run(DbDemoApplication.class, args);
}
}
DBConfig配置
@Configuration
public class DBConfig {
private static HLogger logger = HLoggerFactory.getLogger(DBConfig.class);
@Autowired
@Qualifier("dynamicDataSource")
private DataSource dynamicDataSource;
//当前主数据源
@Bean(name = "dbOne")
@ConfigurationProperties(prefix = "db")
public DataSource dataSource1() {
logger.info(">>>>>>>>>>> masterDataSource config init.");
return DataSourceBuilder.create().build();
}
//需要迁移的旧DB数据源
@Bean(name = "dbTwo")
@ConfigurationProperties(prefix = "db2")
public DataSource dataSource2() {
logger.info(">>>>>>>>>>> slaveDataSource config init.");
return DataSourceBuilder.create().build();
}
@Bean
public MySqlSessionFactoryBean sqlSessionFactoryBean() throws Exception {
MySqlSessionFactoryBean sqlSessionFactoryBean = new MySqlSessionFactoryBean();
sqlSessionFactoryBean.setDaoBasePackage("自己项目的mapper包路径");
sqlSessionFactoryBean.setDataSource(dynamicDataSource);
sqlSessionFactoryBean.setModelBasePackage("自己项目的entity路径");
sqlSessionFactoryBean.setDaoSuffix("Dao");
sqlSessionFactoryBean.setModelSuffix("Entity");
Resource[] resources = new PathMatchingResourcePatternResolver().getResources("classpath*:mybatis/mapper*.xml");
sqlSessionFactoryBean.setMapperLocations(resources);
//加入本地config配置,确保转出的字段如果为null可以存在map内
Resource resources2 = new PathMatchingResourcePatternResolver().getResource("classpath:mybatis-config.xml");
sqlSessionFactoryBean.setConfigLocation(resources2);
return sqlSessionFactoryBean;
}
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dynamicDataSource);
}
}
注意这里事务一样要配置,不然切换数据源后不会生效
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dynamicDataSource);
}
DataSourceConfig配置
@Component
//@ConfigurationProperties("spring.datasource")
public class DataSourceConfig {
@Autowired
@Qualifier("dbOne")
DataSource dataSource1;
@Autowired
@Qualifier("dbTwo")
DataSource dataSource2;
@Primary
@Bean(name = "dynamicDataSource")
public DataSource dynamicDataSource() {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
// 默认数据源
dynamicDataSource.setDefaultTargetDataSource(dataSource1);
// 配置多数据源
Map
DataSourceUtil
public class DataSourceUtil {
public static final String DEFAULT_DS = "dbOne";
private static final ThreadLocal contextHolder = new ThreadLocal<>();
public static void setDB(String dbType) {
contextHolder.set(dbType);
}
public static String getDB() {
return (contextHolder.get());
}
public static void clearDB() {
contextHolder.remove();
}
}
DynamicDataSource
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceUtil.getDB();
}
}
AOP实现动态切换数据源注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface TargetDataSource {
String connName() default "dbOne";
}
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;
@Aspect
@Component
public class DataSourceExchange {
@Before("@annotation(TargetDataSource)")
public void before(JoinPoint joinPoint){
MethodSignature sign = (MethodSignature) joinPoint.getSignature();
Method method = sign.getMethod();
boolean isMethodAop= method.isAnnotationPresent(TargetDataSource.class);
if (isMethodAop){
TargetDataSource datasource = method.getAnnotation(TargetDataSource.class);
DataSourceUtil.setDB(datasource.connName());
//DataSourceHolder.setDataSources(datasource.connName());
}else {
if (joinPoint.getTarget().getClass().isAnnotationPresent(TargetDataSource.class)){
TargetDataSource datasource = joinPoint.getTarget().getClass().getAnnotation(TargetDataSource.class);
DataSourceUtil.setDB(datasource.connName());
//DataSourceHolder.setDataSources(datasource.connName());
}
}
}
@After("@annotation(TargetDataSource)")
public void after(){
DataSourceUtil.clearDB();
//DataSourceHolder.clearDataSource();
}
}
实际使用
connName传你要使用的数据源就可以了
@TargetDataSource(connName = "dbTwo")
public List


