This is the fifth day of my participation in Gwen Challenge
background
Recently, I was asked to make a big data system and analyze it. The trouble is to switch between multiple data sources and extract data. This dynamic data source solution was configured to allow for data extraction across servers and databases and then collation. Share with you here.
Implementation scheme
Database configuration file
Our project uses the configuration file in THE form of YML and the database connection pool of HIkari. The first step is naturally to configure multiple database sources. We find spring’s datasource and configure the three data sources below.
spring: application: name: dynamicDatasource datasource: test1: driver-class-name: com.mysql.jdbc.Driver url: JDBC: mysql: / / 127.0.0.1:3306 / test1? serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false username: root password: 123456 test2: driver-class-name: Com. Mysql. JDBC Driver url: JDBC: mysql: / / 127.0.0.1:3306 / test2? serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false username: root password: 123456 test3: driver-class-name: Com. Mysql. JDBC Driver url: JDBC: mysql: / / 127.0.0.1:3306 / test3? serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false username: root password: 123456 hikari: Leak-detection-threshold: 2000 Duplicating codeCopy the code
Define the data source entity class
We can create a datasourceBean folder to manage the entity classes of the datasource. We’re going to create three entity classes here. They correspond to test1, test2, and test3
@Configuration public class Test1DataSourceBean { @Value("${spring.datasource.test1.driver-class-name}") private String test1Driver; @Value("${spring.datasource.test1.url}") private String test1Url; @Value("${spring.datasource.test1.username}") private String test1Username; @Value("${spring.datasource.test1.password}") private String test1Password; @Bean(name="test1DataSource") public DataSource test1DataSource() throws Exception{ HikariDataSource dataSource = new HikariDataSource(); dataSource.setDriverClassName(test1Driver); dataSource.setJdbcUrl(test1Url); dataSource.setUsername(test1Username); dataSource.setPassword(test1Password); return dataSource; } } @Configuration public class Test2DataSourceBean { @Value("${spring.datasource.test2.driver-class-name}") private String test2Driver; @Value("${spring.datasource.test2.url}") private String test2Url; @Value("${spring.datasource.test2.username}") private String test2Username; @Value("${spring.datasource.test2.password}") private String test2Password; @Bean(name="test2DataSource") public DataSource test2DataSource() throws Exception{ HikariDataSource dataSource = new HikariDataSource(); dataSource.setDriverClassName(test2Driver); dataSource.setJdbcUrl(test2Url); dataSource.setUsername(test2Username); dataSource.setPassword(test2Password); return dataSource; } } @Configuration public class Test3DataSourceBean { @Value("${spring.datasource.test3.driver-class-name}") private String test3Driver; @Value("${spring.datasource.test3.url}") private String test3Url; @Value("${spring.datasource.test3.username}") private String test3Username; @Value("${spring.datasource.test3.password}") private String test3Password; @Bean(name="test3DataSource") public DataSource test3DataSource() throws Exception{ HikariDataSource dataSource = new HikariDataSource(); dataSource.setDriverClassName(test3Driver); dataSource.setJdbcUrl(test3Url); dataSource.setUsername(test3Username); dataSource.setPassword(test3Password); return dataSource; }} Copy the codeCopy the code
Define an enumerated class to manage the data source
public enum DatabaseType { test1("test1", "test1"), test2("test2", "test2"), test3("test3","test3"); private String name; private String value; DatabaseType(String name, String value){ this.name = name; this.value = value; } public String getName(){ return name; } public String getValue(){ return value; }} Copy the codeCopy the code
Define a thread-safe data source container
public class DatabaseContextHolder { private static final ThreadLocal<DatabaseType> contextHolder = new ThreadLocal<>(); public static void setDatabaseType(DatabaseType type){ contextHolder.set(type); } public static DatabaseType getDatabaseType(){ return contextHolder.get(); }} Copy the codeCopy the code
Defining dynamic data sources
public class DynamicDataSource extends AbstractRoutingDataSource{ protected Object determineCurrentLookupKey() { return DatabaseContextHolder.getDatabaseType(); }} Copy the codeCopy the code
Mybatis configuration class
Many articles on the web are configured to create a data source dependency problem, which is solved here.
@Configuration @MapperScan(basePackages="cn.test.jichi", SqlSessionFactoryRef ="sessionFactory") public class MybatisConfig {/** * @description: set dynamic data source */ @Bean(name="dynamicDataSource") @Primary public DynamicDataSource DataSource( @Qualifier("test1DataSource") DataSource test1DataSource, @Qualifier("test2DataSource") DataSource test2DataSource, @Qualifier("test3DataSource") DataSource test3DataSource){ Map<Object, Object> targetDataSource = new HashMap<>(); targetDataSource.put(DatabaseType.test1, test1DataSource); targetDataSource.put(DatabaseType.test2, test2DataSource); targetDataSource.put(DatabaseType.test3, test3DataSource); DynamicDataSource dataSource = new DynamicDataSource(); dataSource.setTargetDataSources(targetDataSource); dataSource.setDefaultTargetDataSource(test1DataSource); return dataSource; } /** * @description: */ @bean (name="sessionFactory") public SqlSessionFactory sessionFactory( @Qualifier("test1DataSource") DataSource test1DataSource, @Qualifier("test2DataSource") DataSource test2DataSource, @Qualifier("test3DataSource") DataSource test3DataSource) throws Exception{ SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean(); // construct method to solve the problem of dynamic data source loop dependency. sessionFactoryBean.setDataSource(this.DataSource(test1DataSource,test2DataSource, test3DataSource)); return sessionFactoryBean.getObject(); } } package cn.chinaunicom.sdsi.utils; import cn.chinaunicom.sdsi.config.dynamicDataSourceConfig.DatabaseContextHolder; import cn.chinaunicom.sdsi.config.dynamicDataSourceConfig.DatabaseType; */ public class DynamicDataSourceUtils {public static void chooseBasicDataSource(){ DatabaseContextHolder.setDatabaseType(DatabaseType.basic); } public static void chooseBranchDataSource(){ DatabaseContextHolder.setDatabaseType(DatabaseType.branch); }} Copy the codeCopy the code
Provide an example
Public void testDymnaicDatasource(){// The datasource is its own by default. System.out.println("----- default data source "); DemoEntity totalCount = demoMapper.getTotalCount(); String nameCount1 = totalCount.getNameCount(); String ageCount2 = totalCount.getAgeCount(); System.out.println("nameCount:"+nameCount1); System.out.println("ageCount:"+ageCount2); Println ("----- data source is test2"); // Switch to branch system.out.println ("----- data source is test2"); DynamicDataSourceUtils.chooseBranchDataSource(); Integer nameCount = demoMapper.getNameCount(); Integer ageCount = demoMapper.getAgeCount(); System.out.println("nameCount:"+nameCount); System.out.println("ageCount:"+ageCount); // The data source is basic system.out.println ("----- data source is test3"); DynamicDataSourceUtils.chooseBasicDataSource(); Integer ageCount1 = demoMapper.getAgeCount(); System.out.println("ageCount:"+ageCount1); } Duplicate codeCopy the code
conclusion
At this point, the dynamic switching of multiple data sources is realized. Multiple data sources can be manipulated within the same method.
Author: Classic chicken Wing link: juejin.cn/post/691906… The copyright belongs to the author. Commercial reprint please contact the author for authorization, non-commercial reprint please indicate the source.