Spring configures the method of read and write separation for dynamic data sources

  • 2020-05-30 20:16:16
  • OfStack

preface

Recently, due to the need of work, a project to be built needs to realize the read and write separation of the data source. The code is Shared here, and those who need it can refer to the study.

The first is to configure the data source


<!-- Read data source configuration -->
<bean id="readDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"destroy-method="close">
// Configuration is omitted 
</bean>

<!-- Write data source configuration -->
<bean id="writeDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"destroy-method="close">
// Configuration is omitted 
</bean>

<!--  Dynamic data source  -->
<bean id = "dataSource" class="com.potato.common.bean.DynamicDataSource" > 
 <!--  The configured data source  --> 
 <property name="targetDataSources">  
 <map>   
  <entry key="READ" value-ref="readDataSource"/>   
  <entry key="WRITE" value-ref="writeDataSource"/>  
 </map> 
 </property> 
 <!--  Default data source  --> 
 <property name="defaultTargetDataSource" ref="writeDataSource"/>
</bean>

How does the data source switch? Through the configuration of the dynamic data source, we know that the switch was originally made through key, which is to be used here org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource , we can write our own dynamic data source class DynamicDataSource To inherit it.


public class DynamicDataSource extends AbstractRoutingDataSource { 
 @Override 
 protected Object determineCurrentLookupKey() {  
  return DataSourceContextHolder.getType(); 
 }
}

You also need a place to store key DataSourceContextHolder To ensure thread safety when switching ThreadLocal To save our key.


public class DataSourceContextHolder {
 private static final Logger LOGGER = LoggerFactory.getLogger(DataSourceContextHolder.class);
 public static final String DATA_SOURCE_WRITE = "WRITE";
 public static final String DATA_SOURCE_READ = "READ";
 //  Thread local environment 
 private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();

 //  Set the data source type 
 public static void setType(String type) {
  if(LOGGER.isDebugEnabled())
   LOGGER.debug("============== Switch data source, type: "+type+"================");
  contextHolder.set(type);
 }
 //  Get data source type 
 public static String getType() {
  return (contextHolder.get());
 }
 //  Clear data source type 
 public static void clearType() {
  contextHolder.remove();
 }
}

Ok, so we can do that DataSourceContextHolder To achieve the dynamic switching of data sources. You might say, do you have to manually select the data source type you want to switch to every time you call a method? Of course not. Here comes Spring AOP.


@Component
@Aspect
public class DynamicDataSourceAspect {

 @Pointcut("execution (* com.potato.orm.mapper.*.select*(..)) || execution (* com.potato.orm.mapper.*.count*(..)) ")
 public void readMethodPointcut() {}

 @Pointcut("execution (* com.potato.orm.mapper.*.insert*(..)) || execution (* com.potato.orm.mapper.*.update*(..)) || execution (* com.potato.orm.mapper.*.delete*(..))")
 public void writeMethodPointcut() {}

 @Before("readMethodPointcut()")
 public void switchReadDataSource(){
  //System.out.println("============ Switch to the read data source ===========");
  DataSourceContextHolder.setType(DataSourceContextHolder.DATA_SOURCE_READ);
 }

 @Before("writeMethodPointcut()")
 public void switchWriteDataSource(){
  //System.out.println("============= Switch to write data source ==========");
  DataSourceContextHolder.setType(DataSourceContextHolder.DATA_SOURCE_WRITE);
 }

}

conclusion

Ok, that's all for this article. When querying methods in Mapper(this project USES MyBatis, which is equivalent to DAO), we switch to read data source, and when adding, deleting, and changing methods, we switch to write data source. I hope the content of this article can help you in your study or work. If you have any questions, please leave a message to communicate.


Related articles: