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.