多資料來源切換,首先需要例項化多個數據源DataSource,這裡以兩個資料來源為例,多個數據源類似。程式的處理單元是執行緒,所以我們藉助ThreadLocal動態設定當前執行緒的資料來源例項。最後我們需要寫一個AOP,攔截需要切換資料來源的方法,在攔截器裡實現資料來源修改。專案以springboot2結合druid,mysql,mybatis為例。
1。首先建立兩個資料庫,分別為first和second,簡單建立一張表各插入一條資料作為演示:
first資料庫,表t_user
second資料庫,表t_user
2。例項化兩個資料來源,簡單配置下資料來源相關屬性:
spring:
druid:
first:
driverClassName: com。mysql。cj。jdbc。Driver
url: jdbc:mysql://127。0。0。1:3306/first?charset=utf8mb4&useSSL=false
username: root
password: 123456
second:
url: jdbc:mysql://127。0。0。1:3306/second?charset=utf8mb4&useSSL=false
初始化動態資料來源,設定預設資料來源,根據key路由到對應資料來源
@Configuration
public class DruidDataSourceConfiguration {
@Bean(“firstDataSource”)
@ConfigurationProperties(“spring。druid。first”)
public DataSource firstDataSource(){
return DruidDataSourceBuilder。create()。build();
}
@Bean(“secondDataSource”)
@ConfigurationProperties(“spring。druid。second”)
public DataSource secondDataSource(){
@Bean
@Primary
public DynamicDataSource dataSource(DataSource firstDataSource, DataSource secondDataSource) {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
dynamicDataSource。setDefaultTargetDataSource(firstDataSource);
Map
targetDataSources。put(“first”,firstDataSource);
targetDataSources。put(“second”, secondDataSource);
dynamicDataSource。setTargetDataSources(targetDataSources);
return dynamicDataSource;
在ThreadLocal中設定執行緒持有的資料來源:
@Slf4j
public class DynamicDataSource extends AbstractRoutingDataSource {
private static final ThreadLocal
public static void set(String name){
log。info(“set datasource:{}”, name);
contextHolder。set(name);
public static String get(){
return contextHolder。get();
public static void remove(){
log。info(“remove datasource:{}”, contextHolder。get());
contextHolder。remove();
@Override
protected Object determineCurrentLookupKey() {
log。info(“current datasource:{}”, DynamicDataSource。get());
return DynamicDataSource。get();
3。編寫自定義註解,需要切換資料來源的地方添加註解:
@Target(ElementType。METHOD)
@Retention(RetentionPolicy。RUNTIME)
public @interface MyDataSource {
String value() default “first”;
4。編寫AOP,處理自定義註解
@Aspect
@Component
public class DynamicDataSourceAspect {
@Pointcut(value=“@annotation(dataSource)”)
public void dataSourcePointCut(MyDataSource dataSource){}
@Before(value = “dataSourcePointCut(dataSource)”)
public void setDataSource(MyDataSource dataSource){
DynamicDataSource。set(dataSource。value());
@After(value = “dataSourcePointCut(dataSource)”)
public void removeDataSource(MyDataSource dataSource){
DynamicDataSource。remove();
5。測試,使用idea外掛EasyCode快速生成程式碼,參見小麥之前的文章
來吧,試試idea外掛EasyCode
@GetMapping(“{datasource}/{id}”)
public TUser selectOne(@PathVariable(“datasource”) String datatsource,@PathVariable(“id”) Integer id) {
if(“second”。equals(datatsource)){
return this。tUserService。queryByIdSecond(id);
return this。tUserService。queryById(id);
在service中新增一個自定義註解的方法:
public TUser queryById(Integer id) {
return this。tUserDao。queryById(id);
@MyDataSource(“second”)
public TUser queryByIdSecond(Integer id) {
6。驗證結果:
總結:
藉助抽象類AbstractRoutingDataSource可以根據key路由目標資料來源,在需要切換資料來源的地方手動標記,切換到對應的資料來源即可。