Preface
Recently, due to the needs of work, a project to be built needs to realize the separation of reading and writing of data sources. The code is shared here, and friends in need can refer to it and learn.
The first is to configure the data source
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <!--读数据源配置-->
<bean id= "readDataSource" class = "com.alibaba.druid.pool.DruidDataSource" init-method= "init" destroy-method= "close" >
</bean>
<!--写数据源配置-->
<bean id= "writeDataSource" class = "com.alibaba.druid.pool.DruidDataSource" init-method= "init" destroy-method= "close" >
</bean>
<!-- 动态数据源 -->
<bean id = "dataSource" class = "com.potato.common.bean.DynamicDataSource" >
<!-- 已配置的数据源 -->
<property name= "targetDataSources" >
<map>
<entry key= "READ" value-ref= "readDataSource" />
<entry key= "WRITE" value-ref= "writeDataSource" />
</map>
</property>
<!-- 默认的数据源 -->
<property name= "defaultTargetDataSource" ref= "writeDataSource" />
</bean>
|
Copy after login
How to switch the data source? Through the configuration of the dynamic data source, we know that switching is performed through key. Here we need to use org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource. We can write our own dynamic data source class DynamicDataSource to inherit it.
1 2 3 4 5 6 | public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder. getType ();
}
}
|
Copy after login
You also need a place to store the key DataSourceContextHolder. To ensure thread safety during switching, we use ThreadLocal to save our key.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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" ;
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
public static void setType(String type) {
if (LOGGER.isDebugEnabled())
LOGGER.debug( "==============切换数据源,类型:" +type+ "================" );
contextHolder.set(type);
}
public static String getType () {
return (contextHolder.get());
}
public static void clearType() {
contextHolder.remove();
}
}
|
Copy after login
Okay, we can dynamically switch data sources by operating DataSourceContextHolder. Friends may ask, do you have to manually select the data source type to switch every time you call a method? Of course not, Spring AOP comes on the scene.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | @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(){
DataSourceContextHolder.setType(DataSourceContextHolder.DATA_SOURCE_READ);
}
@Before( "writeMethodPointcut()" )
public void switchWriteDataSource(){
DataSourceContextHolder.setType(DataSourceContextHolder.DATA_SOURCE_WRITE);
}
}
|
Copy after login
Summary
Okay, the above is the entire content of this article. When accessing Mapper (this project uses MyBatis , which is equivalent to the query method in DAO) will switch to the reading data source, and the add, delete, and modify methods will switch to the writing data source. I hope the content of this article can be of some help to everyone's study or work. If you have any questions, you can leave a message to communicate.
For more related articles on how Spring configures dynamic data sources to achieve read-write separation, please pay attention to the PHP Chinese website!