Spring is a solution to dynamically switch multiple data sources

  • 2020-05-30 20:04:53
  • OfStack

preface

Spring's dynamic configuration of multiple data sources, i.e. sharding of data in large applications and using multiple database instances for management, can effectively improve the horizontal scalability of the system. Such a scheme will be different from the common single data instance scheme, which requires the program to dynamically decide which database instance to store the data in and which database to extract the data from according to the current request and system state.

Proxy mode is adopted in the later versions of Spring2.x, that is, we implement a virtual data source in the scheme and use it to encapsulate the data source selection logic, so as to effectively separate the data source selection logic from Client. Client provides the context required for selection (because this is known to Client), and the virtual DataSource implements the selection of the data source based on the context provided by Client.

implementation

Specifically, the virtual DataSource only needs to inherit the AbstractRoutingDataSource implementation determineCurrentLookupKey() Encapsulates the selection logic for the data source.

1. Dynamically configure multiple data sources

1. Name constant class of data source:


/** 
 *  Configure multiple data sources dynamically  
 *  Name constant class for the data source  
 * @author LONGHUI_LUO 
 * 
 */ 
public class DataSourceConst { 
 public static final String TEST="test"; 
 public static final String USER="User"; 
} 

2. Create a class to obtain and set the context environment, mainly responsible for changing the name of the context data source:


/** 
 *  Gets and sets the context   The main responsibility is to change the name of the context data source  
 * 
 * @author LONGHUI_LUO 
 * 
 */ 
public class DataSourceContextHolder { 
 private static final ThreadLocal contextHolder = new ThreadLocal(); //  Thread local environment  
 
 //  Set the data source type  
 public static void setDataSourceType(String dataSourceType) { 
  contextHolder.set(dataSourceType); 
 } 
 
 //  Get data source type  
 public static String getDataSourceType() { 
  return (String) contextHolder.get(); 
 } 
 
 //  Clear data source type  
 public static void clearDataSourceType() { 
  contextHolder.remove(); 
 } 
 
} 

3. Create the dynamic data source class. Note that this class must inherit AbstractRoutingDataSource and implement the method determineCurrentLookupKey, which returns 1 Object, 1 normally returns a string:


/** 
 *  Setting up a dynamic data source  
 * 
 * @author LONGHUI_LUO 
 * 
 */ 
public class DynamicDataSource extends AbstractRoutingDataSource { 
 
 protected Object determineCurrentLookupKey() { 
 //  In the DAO Before operation, get the type of data source through the context environment variable  
 return DataSourceContextHolder.getDataSourceType(); 
 } 
 
} 

4. Write the configuration file of spring to configure multiple data sources


  <!--  The same content for the data source  --> 
<bean 
  id="parentDataSource" 
  class="org.apache.commons.dbcp.BasicDataSource" 
  destroy-method="close"> 
  <property 
   name="driverClassName" 
   value="com.microsoft.sqlserver.jdbc.SQLServerDriver" /> 
  <property name="username" value="sa" /> 
  <property name="password" value="net2com" /> 
</bean> 
<!-- start The features for each data source are configured below  --> 
<bean parent="parentDataSource" id="testDataSource"> 
  <propertynamepropertyname="url" value="jdbc:sqlserver://localhost:1433;databaseName=test" /> 
</bean> 
<bean parent="parentDataSource" id="UserDataSource"> 
   <property 
   name="url" 
   value="jdbc:sqlserver://localhost:1433;databaseName=User" /> 
</bean> 
<!-- end  Configure the features of the individual data sources  --> 

5. Write spring configuration file to configure multi-data source mapping


<bean class="com.xxxx.datasouce.DynamicDataSource" id="dataSource"> 
 <property name="targetDataSources"> 
  <map key-type="java.lang.String"> 
   <entry value-ref="testDataSource" key="test"></entry> 
   <entry value-ref="UserDataSource" key="User"></entry> 
  </map> 
 </property> 
 <property name="defaultTargetDataSource" ref="testDataSource" ></property> 
</bean> 

The first property property in this configuration configures the target data source ,<map key-type="java.lang.String"> The key-type in the static key control class must be of the same type as the value in the static key control class DataSourceConst ;<entry key="User" value-ref="userDataSource"/> The value of key must be the same as the value in the static key control class, and you can configure multiple values if you have more than one < entry > The label. The second property property configures the default data source.

Dynamic switching is the data source


DataSourceContextHolder.setDataSourceType(DataSourceConst.TEST); 

Advantages of the scheme

First of all, this solution is completely under the framework of spring. The data source is still configured in the configuration file of spring, and sessionFactory is still configured with its dataSource property. It does not even know the change of dataSource. The only difference is that 1 MultiDataSource is added between the true dataSource and sessionFactory.

Second, the implementation is simple and easy to maintain. Although I have said so many things, this scheme is all about analysis. The only code we really need to write is MultiDataSource and SpObserver. The MultiDataSource class really only has to write getDataSource() and getDataSource(sp) Two methods, and the SpObserver class is simpler. The simpler the implementation, the less likely it is to go wrong and the more maintainable it will be.

Finally, this scheme makes single data sources compatible with multiple data sources. This scheme does not affect the writing of BUS and DAO at all. If our project was developed with a single data source at the beginning and needed to change to multiple data sources as the project progressed, we would only need to modify the spring configuration and slightly modify the MVC layer to write the required data source name in the request and the change would be completed. If our project wants to change the return data source, we only need to modify the configuration file. In this way, more flexibility will be added to our projects.

Disadvantages of the scheme

The failure to solve the problem of sharing the "dataSource" variable when multiple users access the singleton "sessionFactory" leads to a scramble for "dataSource", which is essentially similar to the "producer-consumer" problem in the operating system. Therefore, when multiple users access, multiple data sources may lead to the result of system performance degradation.

conclusion

The above is the whole content of this article, I hope the content of this article to your study or work can bring 1 definite help, if you have questions you can leave a message to communicate.


Related articles: