多数据源及事物在fast-family-master基础框架中设计实践指南
本篇给大家介绍如何设计开发多数据源及多数据源事物。
阅读本篇文章涵盖知识点如下:
1.注解反射
2.Spring Aop代理
3.ThreadLocal
4.XA事物管理
具体实现如下:
创建动态数据源切换注解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSourceAnnotation {
String name() default "";
}
复制代码
使用aop代理DataSourceAnnotation注解进行数据源切换
@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配置文件
@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