从去年10月开始项目较忙,感觉大部分时间都是在做一些小的 trick,补一些遗漏的知识点或者说工具点而已。很少能有机会做一些有意思的钻进去的东西,其实在备选 topic 里面已经储备了好多要看的东西,也许4月份开始能有时间腾出来解决这些问题。
今天的主题也很简单,就是一个 Spring Application 连接多个数据源的问题。一部分 Mapper 使用数据源 A,另一部分 Mapper 使用数据源 B。就是在 MapperScan 的时候,指定不同的 SqlSessionFactory即可。
<bean id="sqlSessionFactoryMaster" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="configLocation" value="classpath:conf/mybatis.xml"></property> <property name="dataSource" ref="dataSourceMaster"/> <property name="mapperLocations" value="classpath*:cn/**/dao/master/*.xml"/> <property name="typeAliasesPackage" value="${aliases.modelpackages}"/> </bean> <bean id="orderScannerConfigurerMaster" class="tk.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="cn/**/dao/master"/> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryMaster"/> <property name="properties"> <value> mappers=tk.mybatis.mapper.common.Mapper </value> </property> </bean> <bean id="sqlSessionFactorySlave" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="configLocation" value="classpath:conf/mybatis.xml"></property> <property name="dataSource" ref="dataSourceSlave"/> <property name="mapperLocations" value="classpath*:cn/**/dao/slave/*.xml"/> <property name="typeAliasesPackage" value="${aliases.modelpackages}"/> </bean> <bean id="orderScannerConfigurerSlave" class="tk.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="cn/**/dao/slave"/> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactorySlave"/> <property name="properties"> <value> mappers=tk.mybatis.mapper.common.Mapper </value> </property> </bean>
主要是需要创建两个Configuration,里面分别实现了 DataSource 的创建(读取application yml 里面特定的属性),TransactionManager 的创建,以及最重要的,sqlSessionFactory 的创建。通过创建不同的 sqlSessionFactory,配置读取不同的 mapper 文件。
@Configuration @MapperScan(basePackages = MasterDatasourceConfig.Package, sqlSessionFactoryRef = "masterSqlSessionFactory") public class MasterDatasourceConfig { static final String Package = " cn.*.master"; static final String MAPPER_LOCATION = "classpath:mapper/master/*.xml"; @Value("${master.datasource.url}") private String url; @Value("${master.datasource.username}") private String user; @Value("${master.datasource.password}") private String password; @Value("${master.datasource.driver}") private String driverClass; @Bean(name = "masterDataSource") @Primary public DataSource masterDataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(this.driverClass); dataSource.setUrl(this.url); dataSource.setUsername(this.user); dataSource.setPassword(this.password); return dataSource; } @Bean(name = "masterTransactionManager") @Primary public DataSourceTransactionManager masterTransactionManager(){ return new DataSourceTransactionManager((masterDataSource())); } @Bean(name = "masterSqlSessionFactory") @Primary public SqlSessionFactory masterSqlSessionFactory(@Qualifier("masterDataSource") DataSource masterDataSource) throws Exception { final SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean(); sessionFactoryBean.setDataSource(masterDataSource); sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver() .getResources(MasterDatasourceConfig.MAPPER_LOCATION)); return sessionFactoryBean.getObject(); } }
@Configuration @MapperScan(basePackages = SlaveDatasourceConfig.Package, sqlSessionFactoryRef = "slaveSqlSessionFactory") public class SlaveDatasourceConfig { static final String Package = "cn.*.slave"; static final String MAPPER_LOCATION = "classpath:mapper/slave/*.xml"; @Value("${slave.datasource.url}") private String url; @Value("${slave.datasource.username}") private String user; @Value("${slave.datasource.password}") private String password; @Value("${slave.datasource.driver}") private String driverClass; @Bean(name = "slaveDataSource") public DataSource slaveDataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(this.driverClass); dataSource.setUrl(this.url); dataSource.setUsername(this.user); dataSource.setPassword(this.password); return dataSource; } @Bean(name = "slaveTransactionManager") public DataSourceTransactionManager slaveTransactionManager(){ return new DataSourceTransactionManager((slaveDataSource())); } @Bean(name = "slaveSqlSessionFactory") public SqlSessionFactory slaveSqlSessionFactory(@Qualifier("slaveDataSource") DataSource slaveDataSource) throws Exception { final SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean(); sessionFactoryBean.setDataSource(slaveDataSource); sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver() .getResources(SlaveDatasourceConfig.MAPPER_LOCATION)); return sessionFactoryBean.getObject(); } }
如果说是单数据源的情况下,绑定 mybatis 是非常简单的。配置文件里面配置 spring datasource即可,其他都是自动的,包括创建 SqlSessionFactory。