91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

SpringBoot+Mybatis如何實現動態數據源切換

發布時間:2021-05-07 14:13:00 來源:億速云 閱讀:171 作者:小新 欄目:開發技術

這篇文章主要介紹了SpringBoot+Mybatis如何實現動態數據源切換,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

springboot是什么

springboot一種全新的編程規范,其設計目的是用來簡化新Spring應用的初始搭建以及開發過程,SpringBoot也是一個服務于框架的框架,服務范圍是簡化配置文件。

業務背景

電商訂單項目分正向和逆向兩個部分:其中正向數據庫記錄了訂單的基本信息,包括訂單基本信息、訂單商品信息、優惠卷信息、發票信息、賬期信息、結算信息、訂單備注信息、收貨人信息等;逆向數據庫主要包含了商品的退貨信息和維修信息。數據量超過500萬行就要考慮分庫分表和讀寫分離,那么我們在正向操作和逆向操作的時候,就需要動態的切換到相應的數據庫,進行相關的操作。

解決思路

現在項目的結構設計基本上是基于MVC的,那么數據庫的操作集中在dao層完成,主要業務邏輯在service層處理,controller層處理請求。假設在執行dao層代碼之前能夠將數據源(DataSource)換成我們想要執行操作的數據源,那么這個問題就解決了

環境準備:

1.實體類

@Data
public class Product {    
    private Integer id;    
    private String name;    
    private Double price;
}

2.ProductMapper

public interface ProductMapper { 
    @Select("select * from product") 
    public List<Product> findAllProductM(); 
    @Select("select * from product") 
    public List<Product> findAllProductS(); 
}

3.ProductService

@Service 
public class ProductService { 
    @Autowired 
    private ProductMapper productMapper; 
    public void findAllProductM(){ 
        // 查詢Master 
        List<Product> allProductM = productMapper.findAllProductM(); 
        System.out.println(allProductM); 
    }
    public void findAllProductS(){ 
        // 查詢Slave 
        List<Product> allProductS = productMapper.findAllProductS(); 
        System.out.println(allProductS); 
    } 
}

具體實現

第一步:配置多數據源

首先,我們在application.properties中配置兩個數據源

spring.druid.datasource.master.password=root 
spring.druid.datasource.master.username=root 
spring.druid.datasource.master.jdbc- url=jdbc:mysql://localhost:3306/product_master? useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC 
spring.druid.datasource.master.driver-class-name=com.mysql.cj.jdbc.Driver 

spring.druid.datasource.slave.password=root 
spring.druid.datasource.slave.username=root 
spring.druid.datasource.slave.jdbc- url=jdbc:mysql://localhost:3306/product_slave? useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC 
spring.druid.datasource.slave.driver-class-name=com.mysql.cj.jdbc.Driver
在SpringBoot的配置代碼中,我們初始化兩個數據源:

@Configuration 
public class MyDataSourceConfiguratioin { 
    Logger logger = LoggerFactory.getLogger(MyDataSourceConfiguratioin.class); 
    /*** Master data source. */ 
    @Bean("masterDataSource") 
    @ConfigurationProperties(prefix = "spring.druid.datasource.master") 
    DataSource masterDataSource() { 
        logger.info("create master datasource..."); 
        return DataSourceBuilder.create().build(); 
    }

    /*** Slave data source. */ 
    @Bean("slaveDataSource") 
    @ConfigurationProperties(prefix = "spring.druid.datasource.slave") 
    DataSource slaveDataSource() { 
        logger.info("create slave datasource..."); 
        return DataSourceBuilder.create().build(); 
    } 

    @Bean
    @Primary
    DataSource primaryDataSource(@Autowired @Qualifier("masterDataSource")DataSource masterDataSource,

                                 @Autowired @Qualifier("masterDataSource")DataSource slaveDataSource){

        logger.info("create routing datasource..."); 
        Map<Object, Object> map = new HashMap<>(); 
        map.put("masterDataSource", masterDataSource); 
        map.put("slaveDataSource", slaveDataSource); 
        RoutingDataSource routing = new RoutingDataSource(); 
        routing.setTargetDataSources(map); 
        routing.setDefaultTargetDataSource(masterDataSource); 
        return routing; 

    }

}

第二步:編寫RoutingDataSource
然后,我們用Spring內置的RoutingDataSource,把兩個真實的數據源代理為一個動態數據源:

public class RoutingDataSource extends AbstractRoutingDataSource { 
    @Override 
    protected Object determineCurrentLookupKey() { 
        return RoutingDataSourceContext.getDataSourceRoutingKey();
    } 
}

第三步:編寫RoutingDataSourceContext
用于存儲當前需要切換為哪個數據源

public class RoutingDataSourceContext { 
    // holds data source key in thread local: 
    static final ThreadLocal<String> threadLocalDataSourceKey = new ThreadLocal<>(); 
    public static String getDataSourceRoutingKey() { 
        String key = threadLocalDataSourceKey.get(); 
        return key == null ? "masterDataSource" : key; 
    }
    public RoutingDataSourceContext(String key) { 
        threadLocalDataSourceKey.set(key); 
    }
    public void close() { 
        threadLocalDataSourceKey.remove(); 
    }
}

測試(一下代碼為controller中代碼)

@GetMapping("/findAllProductM")
public String findAllProductM() {    
    String key = "masterDataSource";    
    RoutingDataSourceContext routingDataSourceContext = new RoutingDataSourceContext(key);    
    productService.findAllProductM();    
    return "master";
}
@GetMapping("/findAllProductS")
public String findAllProductS() {    
    String key = "slaveDataSource";
    RoutingDataSourceContext routingDataSourceContext = new RoutingDataSourceContext(key);
    productService.findAllProductS();
    return "slave";
}

以上代碼即可實現數據源動態切換

優化:

以上代碼是可行的,但是,需要讀數據庫的地方,就需要加上一大段RoutingDataSourceContext

ctx = ...代碼,使用起來十分不便。以下是優化方案

我們可以申明一個自定義注解,將以上RoutingDataSourceContext中的值,放在注解的value屬性中,

然后定義一個切面類,當我們在方法上標注自定義注解的時候,執行切面邏輯,獲取到注解中的值,set到RoutingDataSourceContext中,從而實現通過注解的方式,來動態切換數據源

以下是代碼實現:

注解類

@Target(ElementType.METHOD) 
@Retention(RetentionPolicy.RUNTIME) 
public @interface RoutingWith {
 String value() default "master";
 }

切面類:

@Aspect 
@Component 
public class RoutingAspect {
 @Around("@annotation(routingWith)")
 public Object routingWithDataSource(ProceedingJoinPoint joinPoint, RoutingWith routingWith) throws Throwable {
     String key = routingWith.value();
     RoutingDataSourceContext ctx = new RoutingDataSourceContext(key);
     return joinPoint.proceed();
 }
}

改造Controller方法

@RoutingWith("masterDataSource") 
@GetMapping("/findAllProductM") 
public String findAllProductM() {
 productService.findAllProductM(); return "lagou"; 
}

@RoutingWith("slaveDataSource") 
@GetMapping("/findAllProductS") 
public String findAllProductS() {
  productService.findAllProductS(); return "lagou";
 }

感謝你能夠認真閱讀完這篇文章,希望小編分享的“SpringBoot+Mybatis如何實現動態數據源切換”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

印江| 临海市| 方山县| 东乡县| 封开县| 夏津县| 杭锦后旗| 江孜县| 白玉县| 乌拉特后旗| 乌审旗| 达孜县| 南通市| 耒阳市| 库尔勒市| 栖霞市| 平果县| 礼泉县| 乡宁县| 昆山市| 扎兰屯市| 寿宁县| 灵璧县| 额济纳旗| 开鲁县| 集安市| 临夏市| 靖远县| 潜山县| 民丰县| 广水市| 武清区| 龙山县| 汉沽区| 西华县| 淳化县| 章丘市| 雷波县| 镇原县| 长治市| 桓台县|