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
<!--读数据源配置--> <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>
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.
public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DataSourceContextHolder.getType(); } }
You also need a place to store the key DataSourceContextHolder. To ensure thread safety during switching, we use 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"; // 线程本地环境 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(); } }
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.
@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("============切换到读数据源==========="); DataSourceContextHolder.setType(DataSourceContextHolder.DATA_SOURCE_READ); } @Before("writeMethodPointcut()") public void switchWriteDataSource(){ //System.out.println("=============切换到写数据源=========="); DataSourceContextHolder.setType(DataSourceContextHolder.DATA_SOURCE_WRITE); } }
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!