本篇給你們介紹如何設計開發多數據源及多數據源事物。mysql
1.註解反射git
2.Spring Aop代理github
3.ThreadLocalspring
4.XA事物管理sql
建立動態數據源切換註解緩存
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSourceAnnotation {
String name() default "";
}
複製代碼
使用aop代理DataSourceAnnotation註解進行數據源切換bash
@Aspect
@Component
@Slf4j
@Order(1)
public class DynamicDataSourceAspect {
@Pointcut("@within(com.fast.family.datasource.annotation.DataSourceAnnotation) ||" +
" @annotation(com.fast.family.datasource.annotation.DataSourceAnnotation)")
public void pointcut() {
}
;
@Before("pointcut()")
public void before(JoinPoint joinPoint) {
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
DataSourceAnnotation dataSourceAnnotation =
method.getAnnotation(DataSourceAnnotation.class);
if (dataSourceAnnotation == null) {
dataSourceAnnotation = joinPoint.getTarget().getClass()
.getAnnotation(DataSourceAnnotation.class);
if (dataSourceAnnotation == null) {
return;
}
}
String dataSourceKey = dataSourceAnnotation.name();
if (dataSourceKey != null) {
DataSourceContextHolder.add(dataSourceKey);
}
}
public void after(JoinPoint joinPoint) {
DataSourceContextHolder.clear();
}
}
複製代碼
建立動態數據源接口框架
public interface DynamicDataSource {
Map<Object, Object> loadDataSource();
}
複製代碼
加載配置文件指定的數據源信息分佈式
@Component
@Slf4j
public class DefaultDynamicDataSouce implements DynamicDataSource {
@Autowired
private DynamicDataSourceProperties properties;
//加載配置的數據源信息進緩存
@Override
public Map<Object, Object> loadDataSource() {
Class<? extends DataSource> type = properties.getType();
DataSource result = (DataSource) BeanUtils.instantiate(type);
Map<String, DynamicDataSourceProperties> map = properties.getDatasource();
Iterator<Map.Entry<String, DynamicDataSourceProperties>> iterator = map.entrySet().iterator();
Map<Object, Object> dataSourceMap = new HashMap<>();
while (iterator.hasNext()) {
Map.Entry<String, DynamicDataSourceProperties> entry = iterator.next();
DataSource dataSource = DynamicDataSourceFatcory.createDateSource(entry.getValue(), result);
dataSourceMap.put(entry.getKey(), dataSource);
DynamicDataSourceCacheUtils.put(entry.getKey(), dataSource);
}
return dataSourceMap;
}
}
複製代碼
多數據源Properties配置文件ide
@Data
@ConfigurationProperties(prefix = "fast.family")
public class DynamicDataSourceProperties {
private Class<? extends DataSource> type;
private DruidDataSourceProperties druid;
private AtomikosDataSouceProperties atomikos = new AtomikosDataSouceProperties();
private Map<String, DynamicDataSourceProperties> datasource = new HashMap<>();
}
複製代碼
繼承AbstractRoutingDataSource來進行數據源切換
@Slf4j
public class DynamicRoutingDataSource extends AbstractRoutingDataSource
implements InitializingBean {
@Autowired
private DynamicDataSourceProperties properties;
@Autowired
private DynamicDataSource dynamicDataSource;
@Override
protected DataSource determineTargetDataSource() {
String dataSourceKey = DataSourceContextHolder.get();
//根據DataSourceAnnotation指定數據源名稱來切換數據源
//默認使用master數據源
if (dataSourceKey != null && !dataSourceKey.equals("")) {
return DynamicDataSourceCacheUtils.get(dataSourceKey);
} else {
return DynamicDataSourceCacheUtils.get("master");
}
}
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.get();
}
@Override
public void afterPropertiesSet() {
this.setTargetDataSources(dynamicDataSource.loadDataSource());
}
}
複製代碼
丟進spring 容器
@Configuration
@ConditionalOnClass(DynamicDataSourceProperties.class)
@EnableConfigurationProperties({DynamicDataSourceProperties.class})
public class DynamicDataSourceAutoConfigure {
@Bean
public DynamicRoutingDataSource routingDataSource() {
return new DynamicRoutingDataSource();
}
}
複製代碼
上述代碼已經實現了基本的數據源切換,那麼你們可能會有一個疑問就是,多數據源及事物,這個事物是在哪裏管理呢? 這個時候就須要引入XA事物了。
其實奧祕就在DynamicDataSourceProperties中的type屬性,以阿里druid數據源爲例。
fast:
family:
type: com.alibaba.druid.pool.xa.DruidXADataSource #指定DruidXADataSource則帶有分佈式XA事物管理,指定DruidDataSource則不具有分佈式XA事物管理
datasource:
master:
druid:
username: root
password: root
url: jdbc:mysql://localhost:3306/master-db?useUnicode=true&characterEncoding=utf8
driverClassName: com.mysql.jdbc.Driver
atomikos:
uniqueResourceName: master-db
slave_0:
druid:
username: root
password: root
url: jdbc:mysql://localhost:3306/slave-db?useUnicode=true&characterEncoding=utf8
driverClassName: com.mysql.jdbc.Driver
atomikos:
uniqueResourceName: slave-db
複製代碼
最後各位讀者以爲本篇文章對您有所幫助,能夠點贊一波。
如對fast-family-master基礎框架感興趣能夠star一波,地址以下:
https://github.com/fast-family/fast-family-master