前言
动态数据源和多数据源的区别:
- 动态数据源只有一个自定义的动态DataSource对象和一个事务管理器对象。使用时,通过同一个事务管理器对象来操作动态DataSource里的具体数据源。
- 多数据源是有多个DataSource对象,每个DataSource对象对应一个事务管理器对象。
使用时,根据选择的事务管理器(通过@Transactional注解上指定的value,即事务管理器bean的id),获取对应的DataSource。
代码
1.动态数据源类
public class DynamicDataSource extends AbstractRoutingDataSource {
//在开启事务时,会调用到此方法,
//根据方法返回值作为key,从map中获取实际数据源
@Override
protected Object determineCurrentLookupKey() {
try {
Field targetF = this.getClass().getSuperclass().getDeclaredField("targetDataSources");
targetF.setAccessible(true);
Map<Object, Object> targetV = (Map<Object, Object>) targetF.get(this);
String ds = DynamicDataSourceContextHolder.getDataSourceType();
if (ds != null)
System.out.println("操作的数据源是: "
+ ds + "->url:" + ((DruidDataSource) targetV.get(ds)).getUrl());
return DynamicDataSourceContextHolder.getDataSourceType();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return "ds1";
}
}
2.数据源配置类
private ComboPooledDataSource getDs1() {
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
try {
comboPooledDataSource.setDriverClass(driverClass);
comboPooledDataSource.setJdbcUrl(jdbcUrl);
comboPooledDataSource.setUser(user);
comboPooledDataSource.setPassword(password);
comboPooledDataSource.setMinPoolSize(10);
comboPooledDataSource.setMaxPoolSize(100);
comboPooledDataSource.setMaxIdleTime(1800);
comboPooledDataSource.setAcquireIncrement(3);
comboPooledDataSource.setMaxStatements(1000);
comboPooledDataSource.setInitialPoolSize(10);
comboPooledDataSource.setIdleConnectionTestPeriod(60);
comboPooledDataSource.setAcquireRetryAttempts(30);
comboPooledDataSource.setBreakAfterAcquireFailure(false);
comboPooledDataSource.setTestConnectionOnCheckout(false);
comboPooledDataSource.setAcquireRetryDelay(100);
} catch (PropertyVetoException e) {
e.printStackTrace();
}
return comboPooledDataSource;
}
private ComboPooledDataSource getDs2() {
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
try {
comboPooledDataSource.setDriverClass(driverClass);
comboPooledDataSource.setJdbcUrl(jdbcUrl1);
comboPooledDataSource.setUser(user);
comboPooledDataSource.setPassword(password);
comboPooledDataSource.setMinPoolSize(10);
comboPooledDataSource.setMaxPoolSize(100);
comboPooledDataSource.setMaxIdleTime(1800);
comboPooledDataSource.setAcquireIncrement(3);
comboPooledDataSource.setMaxStatements(1000);
comboPooledDataSource.setInitialPoolSize(10);
comboPooledDataSource.setIdleConnectionTestPeriod(60);
comboPooledDataSource.setAcquireRetryAttempts(30);
comboPooledDataSource.setBreakAfterAcquireFailure(false);
comboPooledDataSource.setTestConnectionOnCheckout(false);
comboPooledDataSource.setAcquireRetryDelay(100);
} catch (PropertyVetoException e) {
e.printStackTrace();
}
return comboPooledDataSource;
}
@Bean
public DataSource dynamicDataSource() {
Map<Object, Object> targetDataSources = new HashMap<>();
ComboPooledDataSource ds1 = getDs1();
targetDataSources.put("ds1", ds1);
targetDataSources.put("ds2", getDs2());
DynamicDataSource dynamicDataSource = new DynamicDataSource();
dynamicDataSource.setTargetDataSources(targetDataSources);
dynamicDataSource.setDefaultTargetDataSource(ds1);
DynamicDataSourceContextHolder.dataSourceIds.add("ds1");
DynamicDataSourceContextHolder.dataSourceIds.add("ds2");
return dynamicDataSource;
}
3.切面
@Aspect
@Order(-1)
@Component
public class DynamicDataSourceAspect {
private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceAspect.class);
@Before("@annotation(ds)")
public void changeDataSource(JoinPoint point, TargetDataSource ds) {
//这个就是数据源标识
String dsId = ds.name();
if (!DynamicDataSourceContextHolder.containsDataSource(dsId)) {
logger.error("数据源【{}】不存在,使用默认数据源 > {}",
ds.name(),
point.getSignature());
}
else {
logger.debug("Use dataSource : {} > {}",
ds.name(),
point.getSignature());
//如果容器中有数据源,那么就把数据源标识设置到ThreadLocal中
DynamicDataSourceContextHolder.setDataSourceType(dsId);
}
}
@After("@annotation(ds)")
public void releaseLocal(JoinPoint point, TargetDataSource ds) {
logger.info("==释放ds:" + ds.name() + "的ThreadLocal绑定==");
if(DynamicDataSourceContextHolder.getDataSourceType() != null) {
DynamicDataSourceContextHolder.getContextHolder().remove();
}
}
}