Basically, the articles on the Internet only have multiple data sources or only dynamic data sources, while recent projects need to use two methods at the same time. Let’s record the configuration methods for your reference.
Application scenarios
The project needs to connect two different databases A and B at the same time, and they are both master-slave architectures, one write library and multiple read libraries.
Multiple data sources
First, you must disable the DataSourceAutoConfiguration that comes with spring boot, because it will read the spring.datasource.* property of the application.properties file and automatically configure a single data source. Just add the exclude attribute to the @SpringBootApplication annotation:
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class})public class TitanWebApplication { public static void main(String[] args) { SpringApplication.run(TitanWebApplication.class, args); }}Then configure the multi-data source connection information in application.properties:
# titan library spring.datasource.titan-master.url=jdbc:mysql://XXXX:port/titan?characterEncoding=UTF-8spring.datasource.titan-master.username=spring.datasource.titan-master.password=spring.datasource.titan-master.driver-class-name=com.mysql.jdbc.Driver# Connection pool configuration# omit# Other libraries spring.datasource.db2.url=jdbc:mysql://XXXX:port/titan2?characterEncoding=UTF-8spring.datasource.db2.username=spring.datasource.db2.password=spring.datasource.db2.driver-class-name=com.mysql.jdbc.Driver
Since we have disabled automatic data source configuration, we need to manually create these data sources in the next step:
@Configurationpublic class DataSourceConfig { @Bean(name = "titanMasterDS") @ConfigurationProperties(prefix = "spring.datasource.titan-master") // Prefix of the corresponding property in application.properteis public DataSource dataSource1() { return DataSourceBuilder.create().build(); } @Bean(name = "ds2") @ConfigurationProperties(prefix = "spring.datasource.db2") // Prefix of the corresponding property in application.properteis public DataSource dataSource2() { return DataSourceBuilder.create().build(); }}Next, you need to configure two mybatis SqlSessionFactory to use different data sources:
@Configuration@MapperScan(basePackages = {"titan.mapper"}, sqlSessionFactoryRef = "sqlSessionFactory1")public class MybatisDbAConfig { @Autowired @Qualifier("titanMasterDS") private DataSource ds1; @Bean public SqlSessionFactory sqlSessionFactory1() throws Exception { SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setDataSource(ds1); // Use the titan data source to connect to the titan library return factoryBean.getObject(); } @Bean public SqlSessionTemplate sqlSessionTemplate1() throws Exception { SqlSessionTemplate template = new SqlSessionTemplate(sqlSessionFactory1()); // Use the Factory configured above to return template; }}After the above configuration, the Mapper interface under titan.mapper will use the titan data source. Similarly, you can use the second SqlSessionFactory:
@Configuration@MapperScan(basePackages = {"other.mapper"}, sqlSessionFactoryRef = "sqlSessionFactory2")public class MybatisDbBConfig { @Autowired @Qualifier("ds2") private DataSource ds2; @Bean public SqlSessionFactory sqlSessionFactory2() throws Exception { SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setDataSource(ds2); return factoryBean.getObject(); } @Bean public SqlSessionTemplate sqlSessionTemplate2() throws Exception { SqlSessionTemplate template = new SqlSessionTemplate(sqlSessionFactory2()); return template; }}After completing these configurations, suppose there are 2 Mapper titan.mapper.UserMapper and other.mapper.RoleMapper. When using the former, the titan library will be automatically connected, and the latter will be connected to the ds2 library.
Dynamic data sources
The original intention of using dynamic data sources is to be able to separate read and write at the application layer, that is, to control different query methods in the program code to connect to different libraries. In addition to this method, database middleware is also a good choice. Its advantage is that the database cluster is only exposed to a single library for the application and does not need to switch the code logic of the data source.
We realize dynamic data source switching through custom annotations + AOP.
First define a ContextHolder to save the data source name used by the current thread:
public class DataSourceContextHolder { public static final Logger log = LoggerFactory.getLogger(DataSourceContextHolder.class); /** * Default data source*/ public static final String DEFAULT_DS = "titan-master"; private static final ThreadLocal<String> contextHolder = new ThreadLocal<>(); // Set the data source name public static void setDB(String dbType) { log.debug("Switch to {} data source", dbType); contextHolder.set(dbType); } // Get the data source name public static String getDB() { return (contextHolder.get()); } // Clear the data source name public static void clearDB() { contextHolder.remove(); }}Then customize the implementation of the javax.sql.DataSource interface. Here you only need to inherit the parent class AbstractRoutingDataSource that Spring has implemented for us in advance:
public class DynamicDataSource extends AbstractRoutingDataSource { private static final Logger log = LoggerFactory.getLogger(DynamicDataSource.class); @Override protected Object determineCurrentLookupKey() { log.debug("Data source is {}", DataSourceContextHolder.getDB()); return DataSourceContextHolder.getDB(); }}Create dynamic data sources:
/** * Dynamic data source: Dynamic switching between different data sources through AOP* @return */ @Bean(name = "dynamicDS1") public DataSource dataSource() { DynamicDataSource dynamicDataSource = new DynamicDataSource(); // Default data source dynamicDataSource.setDefaultTargetDataSource(dataSource1()); // Configure multi-data source Map<Object, Object> dsMap = new HashMap(5); dsMap.put("titan-master", dataSource1()); dsMap.put("ds2", dataSource2()); dynamicDataSource.setTargetDataSources(dsMap); return dynamicDataSource; }Custom annotation @DS is used to specify which data source the method uses when encoding:
@Retention(RetentionPolicy.RUNTIME)@Target({ ElementType.METHOD})public @interface DS { String value() default "titan-master";}Write AOP sections to implement switching logic:
@Aspect@Componentpublic class DynamicDataSourceAspect { @Before("@annotation(DS)") public void beforeSwitchDS(JoinPoint point){ //Get the current access class Class<?> className = point.getTarget().getClass(); //Get the access method name String methodName = point.getSignature().getName(); //Get the type of parameter of the method Class[] argClass = ((MethodSignature)point.getSignature()).getParameterTypes(); String dataSource = DataSourceContextHolder.DEFAULT_DS; try { // The method object accessed is Method method = className.getMethod(methodName, argClass); // Determine whether the @DS annotation exists if (method.isAnnotationPresent(DS.class)) { DS annotation = method.getAnnotation(DS.class); // Take out the data source name in the annotation dataSource = annotation.value(); } } catch (Exception e) { e.printStackTrace(); } // Switch the data source DataSourceContextHolder.setDB(dataSource); } @After("@annotation(DS)") public void afterSwitchDS(JoinPoint point){ DataSourceContextHolder.clearDB(); }}After completing the above configuration, specifying DynamicDataSource in the previous SqlSessionFactory configuration to use DynamicDataSource to happily switch data sources in the Service:
@Autowired private UserAModelMapper userAMapper; @DS("titan-master") public String ds1() { return userAMapper.selectByPrimaryKey(1).getName(); } @DS("ds2") public String ds2() { return userAMapper.selectByPrimaryKey(1).getName(); }Summarize
The above is the Spring Boot + Mybatis multi-data source and dynamic data source configuration method introduced to you by the editor. I hope it will be helpful to you. If you have any questions, please leave me a message and the editor will reply to you in time. Thank you very much for your support to Wulin.com website!