首先,既然是多數據源,那么我們就先看下數據源怎么配置的:
javaconfig類似下面這樣:
MapperScan注解常用配置如下:
basePackages:Base packages to scan for MyBatis interfaces,也就是mapper接口所在包名
annotationClass:This property specifies the annotation that the scanner will search for,
也就是只掃描指定包下的指定注解作為mapper,通常為org.apache.ibatis.annotations.Mapper
markerInterface:This property specifies the parent that the scanner will search for,只掃描指定包下指定父接口的子接口作為mapper
sqlSessionTemplateRef:指定這組mapper關聯的sqlSessionTemplate
sqlSessionFactoryRef:指定這組mapper關聯的sqlSessionFactory
那么,問題來了,annotationClass,markerInterface都配置了或者都不配置會怎樣?在org.mybatis.spring.annotation.MapperScannerRegistrar.registerBeanDefinitions中調用的org.mybatis.spring.mapper.ClassPathMapperScanner.registerFilters()代碼如下:
一幕了然,如果都配置了,最終的mapper會是兩者匹配的合集;如果都不配置,那么,最終的mapper會是basePackages下所有任意接口。
使用地方在org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.isCandidateComponent:
還有一個問題,sqlSessionTemplateRef和sqlSessionFactoryRef同時都配置了會怎樣?或者不配置呢?
通常,如果只有一個sqlSessionFactory時是不需要配置的,只有容器中有多個時才需要指定一個。
如果都配置了呢?請看下面分析:
org.mybatis.spring.mapper.ClassPathMapperScanner.processBeanDefinitions(Set<BeanDefinitionHolder>)中處理每一個之前掃描mapper生成的BeanDefinition時,會給每一個BeanDefinition設置sqlSessionFactory,如下:
看到log沒,很清楚:Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.
看完mapper的處理,再來看關聯的sqlSessionFactory:
根據指定數據源類型利用org.springframework.boot.jdbc.DataSourceBuilder創建dataSource,目前主流的是使用阿里開源的Druid數據庫連接池作為數據源:
sqlSessionFactory創建:
通過SqlSessionFactoryBean關聯dataSource和MapperXML,再通過@MapperScan關聯sqlSessionFactory和mapper接口
至此,單個數據源創建算是完成了。如題,多數據源怎么辦?
方法一,手動配置多個dataSource,並在@MapperScan關聯不同的sqlSessionFactory和mapper接口。
方法二,動態數據源,繼承org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource,重寫determineTargetDataSource方法,從targetDataSources中獲取對應數據源操作數據庫,通常在前面業務代碼根據具體怎樣的情況選擇怎樣的dataSource,然后通過設置ThreadLocal變量,這里獲取變量信息來返回對應數據源。切入業務邏輯可以通過aop切面從dao層方法名入手,也可以通過mybatis的攔截器獲取sql信息和入參決定選擇哪個數據源。
PS:如果是讀寫分離,通常情況下主庫讀寫權限,從庫只讀權限,事務DataSourceTransactionManager配置在主庫的dataSource上,@Transactional會自動從配置事務的dataSource中獲取連接。