Abstract: The current persistence framework used in the project is mybatis. After analysis, it is not difficult to find that the multi-data source configuration needs to solve two problems. One is to switch from the original spring classic method to the springboot method. How about multiple data sources? Configuration? Has there been much change? The other is how to associate multiple data sources with the configuration of mybatis?
Recently, due to project needs, the author embarked on a springboot multi-data source configuration journey. The author has configured spring's dynamic multi-data source switching before, using JDBC Template at that time.
The current persistence framework used in the project is mybatis. After analysis, it is not difficult to find that the multi-data source configuration needs to solve two problems. One is to switch from the original spring classic method to the springboot method. Multiple data sources How to configure? Has there been much change? The other is how to associate multiple data sources with the configuration of mybatis?
Let’s take a look first, how to configure mybatis under a single data source?
First of all, let me declare that when the project only relies on a single data source, if you don't mind springboot doing things for you, then congratulations, you save trouble! You only need to add the relevant property configuration of the data source in the project's property file, and springboot will provide you with a data source for "free". The default is tomcat jdbc connection pool.
Of course you can refuse springboot's kindness. If you rely on third-party connection pool technology, you can configure your own data source. Then springboot will not automatically configure the data source after detecting that you have defined the DataSource yourself. .
The author cannot refuse the kindness of springboot, so I only added the following properties to the application.properties of the project:
spring.datasource.url=jdbc:mysql://localhost:3306/test spring.datasource.username=root spring.datasource.password=root spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.max-idle=10 spring.datasource.max-wait=10000 spring.datasource.min-idle=5 spring.datasource.initial-size=5 spring.datasource.validation-query=SELECT 1 spring.datasource.test-on-borrow=false spring.datasource.test-while-idle=true spring.datasource.time-between-eviction-runs-millis=18800 然后笔者创建了一个专门用于配置mybatis的类,如下: @Configuration public class MybatisSpringConfig { @Bean(name = "sqlSessionFactory") public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setDataSource(dataSource); factoryBean.setTypeAliasesPackage("demo.model"); return factoryBean.getObject(); } [[[@Bean](http://my.oschina.net/bean)](http://my.oschina.net/bean)](http://my.oschina.net/bean) public MapperScannerConfigurer mapperScannerConfigurer() { MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer(); mapperScannerConfigurer.setBasePackage("demo.repository"); return mapperScannerConfigurer; } }
Yes, mybatis can work normally in spring through such a simple configuration. You don't need to deliberately create a mybatis configuration file, register the mapper interface and specify the location of the corresponding xml file. This is entirely due to mybatis-spring, which is like a "glue" that can easily Mybatis and spring are "glued" together.
Configuration steps of MyBatis-Spring
You might as well talk about the general steps of mybatis-spring configuration first:
Configure the Bean of the data source DataSource.
Configure the transaction manager using DataSource.
Use DataSource to configure the Bean of SqlSessionFactory.
Configure the Bean of MapperScannerConfigurer.
It is required that the data source of the configured transaction manager and SqlSessionFactory must be the same, otherwise transaction management will not work. The purpose of configuring MapperScannerConfigurer is to automatically scan the package where the mapper interface is located, and automatically help you register the mapper interface as a Bean (the implementation class of the agent-generated interface), so that you can directly use it for dependency injection. It is recommended to register the mapper interface and its corresponding xml The files are placed in the same package, so you don't need to specify the location of the xml file in SqlSessionFactory.
OK, compared to the configuration content I posted above, you may find out why I missed a few steps? Thanks to springboot, because it automatically configures a DataSource, it also automatically configures a transaction manager. So the author only configured SqlSessionFactory and MapperScannerConfigurer.
Of course, if you still insist on configuring your own data source after seeing this, please refer to the multi-data source configuration instructions below and extract one of the multiple data sources to realize the custom single data source configuration. .
After the above single data source example, it can be said that when we switch to springboot to write code, springboot brings us great convenience, and also It does not affect our customization, so I believe that no matter what spring configuration you use before using springboot, there will be no obstacles after using springboot, and it will even be faster than before!
Let’s briefly talk about the scenarios that require multiple data sources. I refer to other articles. Most of the needs come from the database master-slave mode or read-write separation. Then according to the two data sources of master and slave, directly post the configuration class of the data source.
application.properties
##
datasource.master.url=jdbc:mysql://localhost:3306/master datasource.master.username=root datasource.master.password=root datasource.master.driver-class-name=com.mysql.jdbc.Driver datasource.master.max-idle=10 datasource.master.max-wait=10000 datasource.master.min-idle=5 datasource.master.initial-size=5 datasource.master.validation-query=SELECT 1 datasource.master.test-on-borrow=false datasource.master.test-while-idle=true datasource.master.time-between-eviction-runs-millis=18800 datasource.slave.url=jdbc:mysql://localhost:3306/slave datasource.slave.username=root datasource.slave.password=root datasource.slave.driver-class-name=com.mysql.jdbc.Driver datasource.slave.max-idle=10 datasource.slave.max-wait=10000 datasource.slave.min-idle=5 datasource.slave.initial-size=5 datasource.slave.validation-query=SELECT 1 datasource.slave.test-on-borrow=false datasource.slave.test-while-idle=true datasource.slave.time-between-eviction-runs-millis=18800
@Configuration public class MasterConfig { [[[@Primary](http://my.oschina.net/primary)](http://my.oschina.net/primary)](http://my.oschina.net/primary) @Bean(name = "masterDataSource") @ConfigurationProperties(prefix = "datasource.master") public DataSource dataSource() { return DataSourceBuilder.create().build(); }
@Primary @Bean(name = "masterTransactionManager") public DataSourceTransactionManager transactionManager(@Qualifier("masterDataSource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } }
@Configuration public class SlaveConfig { @Bean(name = "slaveDataSource") @ConfigurationProperties(prefix = "datasource.slave") public DataSource dataSource() { return DataSourceBuilder.create().build(){ } @Bean(name = "slaveTransactionManager") public DataSourceTransactionManager transactionManager(@Qualifier("slaveDataSource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } }
配置DataSource时,利用@ConfigurationProperties(prefix = "xxx.xxx")可以依靠指定的前缀,在诸多的属性值中“挑选”出数据源依赖的属性,进而完成数据源的构建。
当自己定义了DataSource后,springboot就会取消自动配置的动作了。为了各司其职,为每个数据源配置各自的事务管理器,springboot自然也会取消自动配置事务管理器的动作。由于是多个数据源和多个事务管理器,都是一个类型的,你要是不起个区别的名字,任谁都分辨不出来吧?
@Primary 有什么作用呢?简单地说,当有两个同一类型的Bean,依赖注入时你没有指定name,正常情况下会报错,有两个你要的Bean,识别不了。但是 @Primary 相当于指定这个Bean为默认的,如果你没有指定name,就采用 @Primary 标识的Bean。
OK,两个数据源的配置配好了,还需要配置各自的Mybatis来进行持久化的操作。
MyBatis-Spring相关配置
mybatis for master
@Configuration @MapperScan(basePackages = {"demo.repository.master"}, sqlSessionFactoryRef = "masterSqlSessionFactory") public class MasterConfig { @Primary @Bean(name = "masterDataSource") @ConfigurationProperties(prefix = "datasource.master") public DataSource dataSource() { return DataSourceBuilder.create().build(); } @Primary @Bean(name = "masterTransactionManager") public DataSourceTransactionManager transactionManager(@Qualifier("masterDataSource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } @Primary @Bean(name = "masterSqlSessionFactory") public SqlSessionFactory sqlSessionFactory(@Qualifier("masterDataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setDataSource(dataSource); factoryBean.setTypeAliasesPackage("demo.model"); return factoryBean.getObject(); } }
mybatis for slave
@Configuration @MapperScan(basePackages = {"demo.repository.slave"}, sqlSessionFactoryRef = "slaveSqlSessionFactory") public class SlaveConfig { @Bean(name = "slaveDataSource") @ConfigurationProperties(prefix = "datasource.slave") public DataSource dataSource() { return DataSourceBuilder.create().build(); } @Bean(name = "slaveTransactionManager") public DataSourceTransactionManager transactionManager(@Qualifier("slaveDataSource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } @Bean(name = "slaveSqlSessionFactory") public SqlSessionFactory basicSqlSessionFactory(@Qualifier("slaveDataSource") DataSource basicDataSource) throws Exception { SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setDataSource(basicDataSource); factoryBean.setTypeAliasesPackage("demo.model"); return factoryBean.getObject(); } }
这里需要强调几个地方:
细心人会发现上面的配置类中,少了MapperScannerConfigurer的Bean配置,改用了@MapperScan注解。其实两者的作用是一样的,但是@MapperScan比较新,稍后会做解释为什么它比较新。
由于两个数据源的原因,引出了两套SqlSessionFactory的配置,所以@MapperScan中需要指明依赖的是哪个SqlSessionFactory,“sqlSessionFactoryRef”对应就是SqlSessionFactory的name属性。
@MapperScan会将扫描的mapper接口代理生成实现类,并自动注册为Bean。由于两个数据源的配置类中都有@MapperScan注解,为了避免造成冲突和排错时的困扰,猛烈提醒,两个数据源的配置,mybatis对应的mapper接口及对应xml文件也构建两套,最好接口名上也做些区分。model类使用同一套倒是没什么影响。所以你会看到上面的配置中,@MapperScan中basePackages指向的是两个包路径。
好了,来解释下@MapperScan为何比较新,并且笔者推荐使用@MapperScan。
首先@MapperScan要求的mybatis-spring版本比较新,说明它是新推出的特性。
其次@MapperScan要比配置MapperScannerConfigurer的Bean要简练的多,代码量上就看得出来。
最后,@MapperScan中的basePackageClasses属性是MapperScannerConfigurer所没有的。并且笔者用到了这个basePackageClasses属性,所以这里强力推荐使用@MapperScan注解。
多聊一些,描述下笔者为何会用到@MapperScan中的basePackageClasses属性吧,况且与上述示例中的basePackages有何区别呢?
上面提到了多数据源的一般场景,笔者的不同。笔者的项目中划分了n个子模块,每个子模块有各自的数据库,现在需要每个子模块共享一个公共信息的数据库。
从代码上来说,由于各个子模块依赖的公共信息数据库-数据源、mapper接口和xml映射文件是相同的,笔者希望将这些类和文件抽离到maven的一个公共module(最后会打包为一个jar文件)中,供其他n个子模块依赖使用,这样可以避免重复代码嘛。
笔者这么做之后,发现配置MapperScannerConfigurer的basePackages找不到mapper接口所在的包路径,因为笔者是在子模块中配置的MapperScannerConfigurer,它自然会在子模块的结构中去寻找指定的包路径,是mapper接口被笔者放到了公共的module中,所以是找不到的!
不过还好在@MapperScan中发现了basePackageClasses属性,它会“接受”你指定的mapper接口的全名。再次提醒,记得把xml映射文件和mapper接口放在一起,mybatis-spring会帮你做关联。
The above is the detailed content of How to configure multiple data sources in springboot. For more information, please follow other related articles on the PHP Chinese website!