日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

springboot 多数据源mybatis的两种整合方法

發布時間:2023/12/3 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 springboot 多数据源mybatis的两种整合方法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載自??springboot-mybatis多數據源的兩種整合方法

簡介:
隨著并發量的不斷增加,顯然單個數據庫已經承受不了高并發帶來的壓力。一個項目使用多個數據庫(無論是主從復制- - 讀寫分離還是分布式數據庫結構)的重要性變得越來越明顯。傳統項目中(個人對傳統項目的理解就是所有的業務模塊都在一個tomcat中完成,多個相同的tomcat集群也可認為是傳統項目)整合多數據源有兩種方法:分包和AOP。

版本:
springboot:1.5.9.RELEASE?
mariadb:5.7

一、分包方式實現

1、在application.properties中配置兩個數據庫:

## test1 database spring.datasource.test1.url=jdbc:mysql://localhost:3307/multipledatasource1?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false spring.datasource.test1.username=root spring.datasource.test1.password=root spring.datasource.test1.driver-class-name=com.mysql.cj.jdbc.Driver ## test2 database spring.datasource.test2.url=jdbc:mysql://localhost:3307/multipledatasource2?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false spring.datasource.test2.username=root spring.datasource.test2.password=root spring.datasource.test2.driver-class-name=com.mysql.cj.jdbc.Driver


2、建立連個數據源的配置文件

springbooot中的參數可以參考上一篇博客(不定期更新中):https://blog.csdn.net/tuesdayma/article/details/81029539

第一個配置文件:

//表示這個類為一個配置類 @Configuration // 配置mybatis的接口類放的地方 @MapperScan(basePackages = "com.mzd.multipledatasources.mapper.test01", sqlSessionFactoryRef = "test1SqlSessionFactory") public class DataSourceConfig1 {// 將這個對象放入Spring容器中@Bean(name = "test1DataSource")// 表示這個數據源是默認數據源@Primary// 讀取application.properties中的配置參數映射成為一個對象// prefix表示參數的前綴@ConfigurationProperties(prefix = "spring.datasource.test1")public DataSource getDateSource1() {return DataSourceBuilder.create().build();}@Bean(name = "test1SqlSessionFactory")// 表示這個數據源是默認數據源@Primary// @Qualifier表示查找Spring容器中名字為test1DataSource的對象public SqlSessionFactory test1SqlSessionFactory(@Qualifier("test1DataSource") DataSource datasource)throws Exception {SqlSessionFactoryBean bean = new SqlSessionFactoryBean();bean.setDataSource(datasource);bean.setMapperLocations(// 設置mybatis的xml所在位置new PathMatchingResourcePatternResolver().getResources("classpath*:mapping/test01/*.xml"));return bean.getObject();}@Bean("test1SqlSessionTemplate")// 表示這個數據源是默認數據源@Primarypublic SqlSessionTemplate test1sqlsessiontemplate(@Qualifier("test1SqlSessionFactory") SqlSessionFactory sessionfactory) {return new SqlSessionTemplate(sessionfactory);} }

第二個配置文件:

@Configuration @MapperScan(basePackages = "com.mzd.multipledatasources.mapper.test02", sqlSessionFactoryRef = "test2SqlSessionFactory") public class DataSourceConfig2 {@Bean(name = "test2DataSource")@ConfigurationProperties(prefix = "spring.datasource.test2")public DataSource getDateSource2() {return DataSourceBuilder.create().build();}@Bean(name = "test2SqlSessionFactory")public SqlSessionFactory test2SqlSessionFactory(@Qualifier("test2DataSource") DataSource datasource)throws Exception {SqlSessionFactoryBean bean = new SqlSessionFactoryBean();bean.setDataSource(datasource);bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapping/test02/*.xml"));return bean.getObject();}@Bean("test2SqlSessionTemplate")public SqlSessionTemplate test2sqlsessiontemplate(@Qualifier("test2SqlSessionFactory") SqlSessionFactory sessionfactory) {return new SqlSessionTemplate(sessionfactory);} }

注意:

1、@Primary這個注解必須要加,因為不加的話spring將分不清楚那個為主數據源(默認數據源)

2、mapper的接口、xml形式以及dao層都需要兩個分開,目錄如圖:?
?
3、bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(“XXXX”));mapper的xml形式文件位置必須要配置,不然將報錯:no statement (這種錯誤也可能是mapper的xml中,namespace與項目的路徑不一致導致的,具體看情況吧,注意一下就行,問題不大的)

4、在service層中根據不同的業務注入不同的dao層。

5、如果是主從復制- -讀寫分離:比如test01中負責增刪改,test02中負責查詢。但是需要注意的是負責增刪改的數據庫必須是主庫(master)

6、如果是分布式結構的話,不同模塊操作各自的數據庫就好,test01包下全是test01業務,test02全是test02業務,但是如果test01中摻雜著test02的編輯操作,這時候將會產生事務問題:即test01中的事務是沒法控制test02的事務的,這個問題在之后的博客中會解決。

?

二、AOP實現

簡介: 用這種方式實現多數據源的前提必須要清楚兩個知識點:AOP原理和AbstractRoutingDataSource抽象類。

1、AOP:這個東西。。。不切當的說就是相當于攔截器,只要滿足要求的都會被攔截過來,然后進行一些列的操作。具體需要自己去體會。。。

2、AbstractRoutingDataSource:這個類是實現多數據源的關鍵,他的作用就是動態切換數據源,實質:有多少個數據源就存多少個數據源在targetDataSources(是AbstractRoutingDataSource的一個map類型的屬性,其中value為每個數據源,key表示每個數據源的名字)這個屬性中,然后根據determineCurrentLookupKey()這個方法獲取當前數據源在map中的key值,然后determineTargetDataSource()方法中動態獲取當前數據源,如果當前數據源不存并且默認數據源也不存在就拋出異常。

public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {//多數據源map集合private Map<Object, Object> targetDataSources;//默認數據源private Object defaultTargetDataSource;//其實就是targetDataSources,后面的afterPropertiesSet()方法會將targetDataSources賦值給resolvedDataSourcesprivate Map<Object, DataSource> resolvedDataSources;private DataSource resolvedDefaultDataSource;public void setTargetDataSources(Map<Object, Object> targetDataSources) {this.targetDataSources = targetDataSources;}protected DataSource determineTargetDataSource() {Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");Object lookupKey = this.determineCurrentLookupKey();DataSource dataSource = (DataSource)this.resolvedDataSources.get(lookupKey);if (dataSource == null && (this.lenientFallback || lookupKey == null)) {dataSource = this.resolvedDefaultDataSource;}if (dataSource == null) {throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");} else {return dataSource;}}protected abstract Object determineCurrentLookupKey(); }


具體實現:

1、定義一個動態數據源:繼承AbstractRoutingDataSource 抽象類,并重寫determineCurrentLookupKey()方法

public class DynamicDataSource extends AbstractRoutingDataSource {@Overrideprotected Object determineCurrentLookupKey() {DataSourceType.DataBaseType dataBaseType = DataSourceType.getDataBaseType();return dataBaseType;}}

2、創建一個切換數據源類型的類: ThreadLocal這個知識點可以參考我的博客:https://blog.csdn.net/tuesdayma/article/details/74841657 就是為了線程的安全性,每個線程之間不會相互影響。

public class DataSourceType {public enum DataBaseType {TEST01, TEST02}// 使用ThreadLocal保證線程安全private static final ThreadLocal<DataBaseType> TYPE = new ThreadLocal<DataBaseType>();// 往當前線程里設置數據源類型public static void setDataBaseType(DataBaseType dataBaseType) {if (dataBaseType == null) {throw new NullPointerException();}System.err.println("[將當前數據源改為]:" + dataBaseType);TYPE.set(dataBaseType);}// 獲取數據源類型public static DataBaseType getDataBaseType() {DataBaseType dataBaseType = TYPE.get() == null ? DataBaseType.TEST01 : TYPE.get();System.err.println("[獲取當前數據源的類型為]:" + dataBaseType);return dataBaseType;}// 清空數據類型public static void clearDataBaseType() {TYPE.remove();}}


3、定義多個數據源:怎么定義就不多說了,和方法一是一樣的,主要是將定義好的多個數據源放在動態數據源中。

@Configuration @MapperScan(basePackages = "com.mzd.multipledatasources.mapper", sqlSessionFactoryRef = "SqlSessionFactory") public class DataSourceConfig {@Primary@Bean(name = "test1DataSource")@ConfigurationProperties(prefix = "spring.datasource.test1")public DataSource getDateSource1() {return DataSourceBuilder.create().build();}@Bean(name = "test2DataSource")@ConfigurationProperties(prefix = "spring.datasource.test2")public DataSource getDateSource2() {return DataSourceBuilder.create().build();}@Bean(name = "dynamicDataSource")public DynamicDataSource DataSource(@Qualifier("test1DataSource") DataSource test1DataSource,@Qualifier("test2DataSource") DataSource test2DataSource) {Map<Object, Object> targetDataSource = new HashMap<>();targetDataSource.put(DataSourceType.DataBaseType.TEST01, test1DataSource);targetDataSource.put(DataSourceType.DataBaseType.TEST02, test2DataSource);DynamicDataSource dataSource = new DynamicDataSource();dataSource.setTargetDataSources(targetDataSource);dataSource.setDefaultTargetDataSource(test1DataSource);return dataSource;}@Bean(name = "SqlSessionFactory")public SqlSessionFactory test1SqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dynamicDataSource)throws Exception {SqlSessionFactoryBean bean = new SqlSessionFactoryBean();bean.setDataSource(dynamicDataSource);bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapping/*.xml"));return bean.getObject();} }


4、定義AOP:就是不同業務切換不同數據庫的入口。如果覺得execution太長不愿意寫,就可以定義一個注解來實現。可參考于我的博客:https://blog.csdn.net/tuesdayma/article/details/79704238

@Aspect @Component public class DataSourceAop {@Before("execution(* com.mzd.multipledatasources.service..*.test01*(..))")public void setDataSource2test01() {System.err.println("test01業務");DataSourceType.setDataBaseType(DataBaseType.TEST01);}@Before("execution(* com.mzd.multipledatasources.service..*.test02*(..))")public void setDataSource2test02() {System.err.println("test02業務");DataSourceType.setDataBaseType(DataBaseType.TEST02);} }


整體目錄如圖:?


源代碼:https://github.com/mzd123/springboot-multipledatasources/tree/master
?

總結

以上是生活随笔為你收集整理的springboot 多数据源mybatis的两种整合方法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。