提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 前言
- 一、pandas是什么?
- 二、使用步骤
- 1.引入库
- 2.读入数据
- 总结
前言
spring aop 动态切换数据源,从源数据库导入数据到目标数据库
1,需要实现AbstractRoutingDataSource接口重写determineCurrentLookupKey()方法
2,实现ApplicationRunner接口重写run()方法,程序启动的时候就可以从数据表中(也可以从配置文件中读取)初始化Target,Resource数据源
提示:以下是本篇文章正文内容,下面案例可供参考
一、AbstractRoutingDataSource是什么?
AbstractRoutingDataSource的getConnection() 方法根据查找 lookup key 键对不同目标数据源的调用,通常是通过(但不一定)某些线程绑定的事物上下文来实现。
AbstractRoutingDataSource的多数据源动态切换的核心逻辑是:在程序运行时,把数据源数据源通过 AbstractRoutingDataSource 动态织入到程序中,灵活的进行数据源切换。
基于AbstractRoutingDataSource的多数据源动态切换,可以实现读写分离
二、使用步骤
1.实现逻辑
1,定义DynamicDataSource类继承抽象类AbstractRoutingDataSource,并实现了determineCurrentLookupKey()方法。
2,把配置的多个数据源会放在AbstractRoutingDataSource的 targetDataSources和defaultTargetDataSource中,然后通过afterPropertiesSet()方法将数据源分别进行复制到resolvedDataSources和resolvedDefaultDataSource中。
3,调用AbstractRoutingDataSource的getConnection()的方法的时候,先调用determineTargetDataSource()方法返回DataSource在进行getConnection()。
2.初始数据库连接信息表
public void dataSourceInit() {
logger.info("cityPartner==========开始加载数据源");
DynamicDataSource dynamicDataSource =(DynamicDataSource) DynamicDataSourceContextHolder.applicationContext.getBean("dataSource");
Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
Environment env =DynamicDataSourceRegister.environment;
//从数据库表中读取数据源(目标和源文件数据源)
List<TenantCitypartnerDatasource> tcds=DatasourceMapper.selectDataSource();
if(tcds!=null&&tcds.size()>0){
for(TenantCitypartnerDatasource tcd:tcds){
Map<String, Object> dsMap = new HashMap<>();
dsMap.put("driver-class-name","com.mysql.jdbc.Driver");
dsMap.put("url",tcd.getUrl());
dsMap.put("username", tcd.getUsername());
dsMap.put("password", tcd.getPassword());
DataSource ds = CityPartnerDataSourceRegister.buildDataSource(dsMap);//创建DataSourceBuilder
CityPartnerDataSourceRegister.dataBinder(ds, env);//绑定主数据源
CityPartnerDataSourceRegister.targetDataSources.put(tcd.getDataSourceType(), ds);
CityPartnerDataSourceRegister. DBdataSourceInfo.put(tcd.getDataSourceType(), tcd);
CityPartnerDataSourceRegister.realConnectionInfo.put(tcd.getDataSourceType(), getDataSourceKey(tcd));
logger.info("加载:{}数据源数据源,{}库,成功",tcd.getSystemCode(),tcd.getService_name());
}
// 添加更多数据源
targetDataSources.putAll(CityPartnerDataSourceRegister.targetDataSources);
}
dynamicDataSource.setTargetDataSources(targetDataSources);
dynamicDataSource.afterPropertiesSet();//这一行非常关键
//DynamicDataSourceContextHolder.dataSourceIds.clear();
DynamicDataSourceContextHolder.dataSourceIds.addAll(CityPartnerDataSourceRegister.targetDataSources.keySet());
}
//生成key
public String getDataSourceKey(TenantCitypartnerDatasource tcd){
return tcd.getSystemCode()+"-"+tcd.getService_name();
}
保存初始化的数据源信息类
public class CityPartnerDataSourceRegister {
private static final Logger logger = LoggerFactory.getLogger(CityPartnerDataSourceRegister.class);
// 如配置文件中未指定数据源类型,使用该默认值
private static final Object DATASOURCE_TYPE_DEFAULT = "com.alibaba.druid.pool.DruidDataSource";
private static ConversionService conversionService = new DefaultConversionService();
private static PropertyValues dataSourcePropertyValues;
public static Map<String, DataSource> targetDataSources = new HashMap<String, DataSource>();
public static Map<String, String> realConnectionInfo = new HashMap<String, String>();
//保存数据库连接信息
public static Map<String, TenantCitypartnerDatasource> DBdataSourceInfo = new HashMap<String, TenantCitypartnerDatasource>();
@SuppressWarnings("unchecked")
public static DataSource buildDataSource(Map<String, Object> dsMap) {
try {
Class<? extends DataSource> dataSourceType;
dataSourceType = (Class<? extends DataSource>) Class.forName((String) DATASOURCE_TYPE_DEFAULT);
String driverClassName = dsMap.get("driver-class-name").toString();
String url = dsMap.get("url").toString();
String username = dsMap.get("username").toString();
String password = dsMap.get("password").toString();
DataSourceBuilder factory = DataSourceBuilder.create().driverClassName(driverClassName).url(url)
.username(username).password(password).type(dataSourceType);
return factory.build();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 为DataSource绑定更多数据
*
* @param dataSource
* @param env
*/
public static void dataBinder(DataSource dataSource, Environment env){
RelaxedDataBinder dataBinder = new RelaxedDataBinder(dataSource);
//dataBinder.setValidator(new LocalValidatorFactory().run(this.applicationContext));
dataBinder.setConversionService(conversionService);
dataBinder.setIgnoreNestedProperties(false);//false
dataBinder.setIgnoreInvalidFields(false);//false
dataBinder.setIgnoreUnknownFields(true);//true
if(dataSourcePropertyValues == null){
Map<String, Object> rpr = new RelaxedPropertyResolver(env, "spring.datasource").getSubProperties(".");
Map<String, Object> values = new HashMap<>(rpr);
// 排除已经设置的属性
values.remove("type");
values.remove("driver-class-name");
values.remove("url");
values.remove("username");
values.remove("password");
dataSourcePropertyValues = new MutablePropertyValues(values);
}
dataBinder.bind(dataSourcePropertyValues);
}
}
public class DynamicDataSourceContextHolder {
public static ApplicationContext applicationContext;
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
public static List<String> dataSourceIds = new ArrayList<>();
public static void setDataSourceType(String dataSourceType) {
contextHolder.set(dataSourceType);
}
public static String getDataSourceType() {
return contextHolder.get();
}
/**
* 判断指定DataSrouce当前是否存在
*
*/
public static boolean containsDataSource(String dataSourceId){
return dataSourceIds.contains(dataSourceId);
}
}
spring AOP
DataSourceEM 方法枚举
//自定义注解
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TargetDataSource {
DataSourceEM source();
}
public enum DataSourceEM {
// sourceName必须和数据库里的dataSourceType一致
SOURCE_RESOURCE("source_resource","saas-resource库"),
SOURCE_USER("source_user","saas-user库"),
SOURCE_DEVICE("source_device","saas-device库"),
TARGET_SAASMAIN("target_saas_main","saas_main库"),
TARGET_DEVICE("target_device","device库"),
TARGET_USER("target_user","user库"),
TARGET_RESOURCE("target_resource","resource库");
private String sourceName;
private String desc;
private DataSourceEM(String sourceName,String desc){
this.sourceName = sourceName;
this.desc = desc;
}
public String getSourceName() {
return sourceName;
}
public void setSourceName(String sourceName) {
this.sourceName = sourceName;
}
// todo get set...
}
拦截处理代码
@Aspect
@Component
@Order(1)
public class DataSourceInteceptor {
private static final Logger logger = LoggerFactory.getLogger(DataSourceInteceptor.class);
long i = 0;
@Autowired
private Environment env;
@Pointcut("@annotation(com.zdst.tenant.manage.web.cityPartnerDataSource.TargetDataSource)")
public void dataSourcePointcut(){}
@Before("dataSourcePointcut()")
public void before(JoinPoint pjp) throws Exception {
MethodSignature signature=(MethodSignature) pjp.getSignature();
Method method=signature.getMethod();
TargetDataSource targetDataSource=method.getAnnotation(TargetDataSource.class);
Object[] args = pjp.getArgs();
String dataName=targetDataSource.source().getSourceName();
if(dataName!=null&&dataName!=""){
if(DynamicDataSourceContextHolder.containsDataSource(dataName)){
logger.info("cityPartner===aop切换数据源:{},{}",dataName,CityPartnerDataSourceRegister.realConnectionInfo.get(dataName));
DynamicDataSourceContextHolder.setDataSourceType(dataName);
}else {
logger.info("cityPartner===aop切换数据源失败,没有找到{}这个数据源,切回默认数据源:",dataName);
DynamicDataSourceContextHolder.setDataSourceType(null);
}
}else {
logger.info("cityPartner===aop切换数据源dataName值为空,切回默认数据源");
DynamicDataSourceContextHolder.setDataSourceType(null);
}
}
/**
* 拦截器具体实现
* @param pjp
* @return JsonResult(被拦截方法的执行结果,或需要登录的错误提示。)
* @throws Throwable
*/
@Around("dataSourcePointcut()")
public Object Interceptor(ProceedingJoinPoint pjp) throws Throwable{
return pjp.proceed();
}
@After("dataSourcePointcut()")
public void after() {
logger.info("cityPartner===切回默认数据库");
DynamicDataSourceContextHolder.setDataSourceType(null);
}
}
总结
DataSourceEM 枚举里的sourceName必须和数据库里的dataSourceType一致
只是处理datax导入的数据在做处理,大表数据处理还是用datax导入数据