This is the first day of my participation in the Gwen Challenge in November. Check out the details: the last Gwen Challenge in 2021

Dynamically switching data sources:

Springboot provides a AbstractRoutingDataSource class. We can achieve a class inherits AbstractRoutingDataSource and determineCurrentLookUpKey () method.

Specific steps:

Data Source Configuration

Spring: a datasource: type: com. Alibaba. Druid. Pool. DruidDataSource # MySQL configuration driverClassName: com. MySQL.. JDBC Driver url: JDBC: mysql: / / 127.0.0.1:3306 / graduate? UseUnicode =true&characterEncoding= UTF-8&usessl =false username: root password: root #MySQL config dbManager: driverClassName: Com. Mysql. JDBC Driver url: JDBC: mysql: / / 127.0.0.1:3306 / HFB? useUnicode=true&characterEncoding=UTF-8&useSSL=false username: root password: root db37: driverClassName: Com. Mysql. JDBC Driver url: JDBC: mysql: / / 127.0.0.1:3306 / sys? useUnicode=true&characterEncoding=UTF-8&useSSL=false username: root password: root dbmanager37: driverClassName: Com. Mysql. JDBC Driver url: JDBC: mysql: / / 127.0.0.1:3306 / srb_core? useUnicode=true&characterEncoding=UTF-8&useSSL=false username: root password: rootCopy the code

Write DataSourceContextHolder to set and save the data source used by the current thread

Public class DataSourceContextHolder {// Default data source private static final String DEFAULT_DATASOURCE = "pq"; Private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>(); public static String getDataSource() { return CONTEXT_HOLDER.get(); } public static void setDataSource(String key) { CONTEXT_HOLDER.set(key); } public static void cleanDataSource() { CONTEXT_HOLDER.remove(); }}Copy the code

Write DynamicDataSource

Public class DynamicDataSource extends AbstractRoutingDataSource {/ * * * @ return switch data source when this method is called * / @ Override protected Object determineCurrentLookupKey() { return DataSourceContextHolder.getDataSource(); }}Copy the code

The configuration class

@primary @bean (name = "db") @primary @bean (name = "db") @ConfigurationProperties(prefix = "spring.datasource") public DataSource dataSourcePq() { return new DruidDataSource(); } @Bean("db_37") @ConfigurationProperties("spring.datasource.pq37") public DataSource dataSourcePq37() { return new DruidDataSource(); } @Bean("db_manager_37") @ConfigurationProperties("spring.datasource.pqmanager37") public DataSource dataSourcePqManager37() { return new DruidDataSource(); } @ Primary / / must have a data source is marked as Primary @ Bean (" db_manager ") @ ConfigurationProperties (" spring. The datasource. Pqmanager ") to the public DataSource dataSourcePqManager() { return new DruidDataSource(); } /** * DataSource selector @primary causes loop dependency issues ** @return */ @bean (name = "dynamicDataSource") public DataSource dynamicDataSource(@Qualifier("db") DataSource PqSource, @Qualifier("db_manager") DataSource PqManagerSource, @Qualifier("db_37") DataSource PqSource37, @Qualifier("db_manager_37") DataSource PqManagerSource37) { DynamicDataSource dynamicDataSource = new DynamicDataSource(); . / / configure the default data source dynamicDataSource setDefaultTargetDataSource (PqSource); // Save all swappable data sources Map<Object, Object> dataSourceMap = new HashMap<>(); dataSourceMap.put("db", PqSource); dataSourceMap.put("db_manager", PqManagerSource); dataSourceMap.put("db_37", PqSource37); dataSourceMap.put("db_manager_37", PqManagerSource37); dynamicDataSource.setTargetDataSources(dataSourceMap); return dynamicDataSource; }}Copy the code
@EnableTransactionManagement @Configuration public class MyBatisConfig { @Resource(name = "dynamicDataSource") private DataSource dynamicDataSource; @Autowired private MybatisProperties mybatisProperties; @Bean public SqlSessionFactory sqlSessionFactory() throws Exception { SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); sqlSessionFactoryBean.setDataSource(dynamicDataSource); sqlSessionFactoryBean.setMapperLocations(mybatisProperties.resolveMapperLocations()); sqlSessionFactoryBean.setConfiguration(mybatisProperties.getConfiguration()); return sqlSessionFactoryBean.getObject(); } @Bean public PlatformTransactionManager platformTransactionManager() { return new DataSourceTransactionManager(dynamicDataSource); }}Copy the code

Intercept the request with an interceptor to see if any of the request parameters exist (indicating that the data source needs to be switched, or the default data source if it does not). You can also use AOP methods on a method,

Use custom annotations to configure the data source to be switched. In the section, you only need to use reflection to get the corresponding data source to switch.

/ * * * to intercept the request switch data source * / public class DataSourceInterceptor extends HandlerInterceptorAdapter {/ * * * * * @ intercept request param request * @param response * @param handler * @return * @throws Exception */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String dataSourceKey = request.getParameter("dataSourceKey"); System.out.println(dataSourceKey); if (StringUtils.isNotEmpty(dataSourceKey)) { DataSourceContextHolder.setDataSource(dataSourceKey); } return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // System.out.println(DataSourceContextHolder.getDataSource()); DataSourceContextHolder.cleanDataSource(); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { super.afterCompletion(request, response, handler, ex); }}Copy the code

Configuring interceptors

@Configuration public class InterceptorsConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { InterceptorRegistration registration = registry.addInterceptor(new DataSourceInterceptor()); / / intercept all paths registration. AddPathPatterns ("/sys / * * "); }}Copy the code