- 資訊首頁(yè) > 開(kāi)發(fā)技術(shù) > 編程語(yǔ)言 >
- 詳解SpringBoot+Mybatis實(shí)現動(dòng)態(tài)數據源切換
電商訂單項目分正向和逆向兩個(gè)部分:其中正向數據庫記錄了訂單的基本信息,包括訂單基本信息、訂單商品信息、優(yōu)惠卷信息、發(fā)票信息、賬期信息、結算信息、訂單備注信息、收貨人信息等;逆向數據庫主要包含了商品的退貨信息和維修信息。數據量超過(guò)500萬(wàn)行就要考慮分庫分表和讀寫(xiě)分離,那么我們在正向操作和逆向操作的時(shí)候,就需要動(dòng)態(tài)的切換到相應的數據庫,進(jìn)行相關(guān)的操作。
現在項目的結構設計基本上是基于MVC的,那么數據庫的操作集中在dao層完成,主要業(yè)務(wù)邏輯在service層處理,controller層處理請求。假設在執行dao層代碼之前能夠將數據源(DataSource)換成我們想要執行操作的數據源,那么這個(gè)問(wèn)題就解決了
1.實(shí)體類(lèi)
@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(){ // 查詢(xún)Master List<Product> allProductM = productMapper.findAllProductM(); System.out.println(allProductM); } public void findAllProductS(){ // 查詢(xún)Slave List<Product> allProductS = productMapper.findAllProductS(); System.out.println(allProductS); } }
第一步:配置多數據源
首先,我們在application.properties中配置兩個(gè)數據源
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的配置代碼中,我們初始化兩個(gè)數據源: @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; } }
第二步:編寫(xiě)RoutingDataSource
然后,我們用Spring內置的RoutingDataSource,把兩個(gè)真實(shí)的數據源代理為一個(gè)動(dòng)態(tài)數據源:
public class RoutingDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return RoutingDataSourceContext.getDataSourceRoutingKey(); } }
第三步:編寫(xiě)RoutingDataSourceContext
用于存儲當前需要切換為哪個(gè)數據源
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"; }
以上代碼即可實(shí)現數據源動(dòng)態(tài)切換
以上代碼是可行的,但是,需要讀數據庫的地方,就需要加上一大段RoutingDataSourceContext
ctx = ...代碼,使用起來(lái)十分不便。以下是優(yōu)化方案
我們可以申明一個(gè)自定義注解,將以上RoutingDataSourceContext中的值,放在注解的value屬性中,
然后定義一個(gè)切面類(lèi),當我們在方法上標注自定義注解的時(shí)候,執行切面邏輯,獲取到注解中的值,set到RoutingDataSourceContext中,從而實(shí)現通過(guò)注解的方式,來(lái)動(dòng)態(tài)切換數據源
以下是代碼實(shí)現:
注解類(lèi)
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface RoutingWith { String value() default "master"; }
切面類(lèi):
@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"; }
到此這篇關(guān)于詳解SpringBoot+Mybatis實(shí)現動(dòng)態(tài)數據源切換的文章就介紹到這了,更多相關(guān)SpringBoot+Mybatis動(dòng)態(tài)數據源切換內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自本網(wǎng)站內容采集于網(wǎng)絡(luò )互聯(lián)網(wǎng)轉載等其它媒體和分享為主,內容觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如侵犯了原作者的版權,請告知一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容,聯(lián)系我們QQ:712375056,同時(shí)歡迎投稿傳遞力量。
Copyright ? 2009-2022 56dr.com. All Rights Reserved. 特網(wǎng)科技 特網(wǎng)云 版權所有 特網(wǎng)科技 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 百度云 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2
建議您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流瀏覽器瀏覽本網(wǎng)站