废话少说,直接上代码!!!!
这里用的是mybatisPlus封装的动态数据源,spring的也可以,都是差不多的
首先,导入mybatisPlus和数据源依赖 这里用的springboot子模块就没有加版本号
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
接下来我们来看源码:
dynamic-datasource 提供了一个重要的类DynamicRoutingDataSource
@Override
public DataSource determineDataSource() {
String dsKey = DynamicDataSourceContextHolder.peek();
return getDataSource(dsKey);
}
这里的DynamicRoutingDataSource.peek()就是获取当前的数据源的名称!!
接下来点进DynamicDataSourceContextHolder类,这才是我们的关键!!点进源码:
/**
* 核心基于ThreadLocal的切换数据源工具类
*
* @author TaoYu Kanyuxia
* @since 1.0.0
*/
public final class DynamicDataSourceContextHolder {
/**
* 为什么要用链表存储(准确的是栈)
* <pre>
* 为了支持嵌套切换,如ABC三个service都是不同的数据源
* 其中A的某个业务要调B的方法,B的方法需要调用C的方法。一级一级调用切换,形成了链。
* 传统的只设置当前线程的方式不能满足此业务需求,必须使用栈,后进先出。
* </pre>
*/
private static final ThreadLocal<Deque<String>> LOOKUP_KEY_HOLDER = new NamedThreadLocal<Deque<String>>("dynamic-datasource") {
@Override
protected Deque<String> initialValue() {
return new ArrayDeque<>();
}
};
private DynamicDataSourceContextHolder() {
}
/**
* 获得当前线程数据源
*
* @return 数据源名称
*/
public static String peek() {
return LOOKUP_KEY_HOLDER.get().peek();
}
/**
* 设置当前线程数据源
* <p>
* 如非必要不要手动调用,调用后确保最终清除
* </p>
*
* @param ds 数据源名称
*/
public static String push(String ds) {
String dataSourceStr = StringUtils.isEmpty(ds) ? "" : ds;
LOOKUP_KEY_HOLDER.get().push(dataSourceStr);
return dataSourceStr;
}
/**
* 清空当前线程数据源
* <p>
* 如果当前线程是连续切换数据源 只会移除掉当前线程的数据源名称
* </p>
*/
public static void poll() {
Deque<String> deque = LOOKUP_KEY_HOLDER.get();
deque.poll();
if (deque.isEmpty()) {
LOOKUP_KEY_HOLDER.remove();
}
}
/**
* 强制清空本地线程
* <p>
* 防止内存泄漏,如手动调用了push可调用此方法确保清除
* </p>
*/
public static void clear() {
LOOKUP_KEY_HOLDER.remove();
}
由此可得有一个peek()方法操作的是我们的TheadLocal变量 LOOKUP_KEY_HOLDER
所以我们只要改变这个变量的值就能动态的去切换数据源!!
上代码!!!
首先配置两个以上的数据源:
封装类对象用来接收传递数据源名称以及条件
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.util.StringUtils;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Paginate<T> extends Page {
private String dataSourceId = "ac";
private String holderName;
private String startTime;
private String endTime;
public String getDataSourceId() {
return dataSourceId;
}
/**
* 默认为ac
* @param dataSourceId
*/
public void setDataSourceId(String dataSourceId) {
this.dataSourceId = StringUtils.hasLength(dataSourceId) ? dataSourceId : this.dataSourceId;
}
}
Mapper: 语句写成自己的,我这里直接用我的代码7语句来演示了!
// 根据数据源切换
List<PlanTableVo> SelectByHongMengPlan(
Page page,
@Param("startTime") String startTime,
@Param("endTime") String endTime,
@Param("advertiserName") String advertiserName,
@Param("holderName") String holderName,
@Param("name") String name,
@Param("adName") String adName);
实现类(关键核心!!):
@Resource
private DynamicRoutingDataSource routingDataSource;
// 查询所有数据源
@Override
public List<String> listDataSource() {
return new ArrayList<>(routingDataSource.getDataSources().keySet());
}
// 动态切换数据源
@Override
public List<PlanTableVo> SelectByHongMengPlan(Page page, PaginatePlan<PlanTableVo> paginatePlan) {
// 判断是否是正确的数据源名称
Assert.assertTrue("不支持的数据源id",
listDataSource().stream().anyMatch(
dataSourceId -> paginatePlan.getDataSourceId().equalsIgnoreCase(dataSourceId)));
// 判断当前的数据源是否一致 // 获得当前数据源
if (!paginatePlan.getDataSourceId().equalsIgnoreCase(DynamicDataSourceContextHolder.peek())) {
DynamicDataSourceContextHolder.poll();
DynamicDataSourceContextHolder.push(paginatePlan.getDataSourceId());
}
List<PlanTableVo> planTableVos = hongmengOceanEngineAdDayDataMapper.SelectByHongMengPlan(page,
paginatePlan.getStartTime(),
paginatePlan.getEndTime(),
paginatePlan.getAdvertiserName(),
paginatePlan.getHolderName(),
paginatePlan.getName(),
paginatePlan.getAdName());
return planTableVos;
}
这里有一个 listDataSource() 方法 里面有一个 getDataSources().keySet()方法获取所有数据源名称
前台可以直接获取这个接口查询所有数据源然后一个下拉框动态切换!!
下面这一段代码直接从前台传一个数据源名称即可从页面动态改变数据源切换数据!!!
我就不测试了!!!
感谢大家的观看,希望各位点个小爱心!!!多多关注!!