最近搭建的一個項目需要實現(xiàn)數(shù)據(jù)源的讀寫分離溯警,在這里將代碼進行分享趣苏,以供參考。
關(guān)鍵詞:DataSource 梯轻、AbstractRoutingDataSource食磕、AOP
首先是配置數(shù)據(jù)源
<!--讀數(shù)據(jù)源配置-->
<bean id="readDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"destroy-method="close">
//配置省略
</bean>
<!--寫數(shù)據(jù)源配置-->
<bean id="writeDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"destroy-method="close">
//配置省略
</bean>
<!-- 動態(tài)數(shù)據(jù)源 -->
<bean id = "dataSource" class="com.potato.common.bean.DynamicDataSource" >
<!-- 已配置的數(shù)據(jù)源 -->
<property name="targetDataSources">
<map>
<entry key="READ" value-ref="readDataSource"/>
<entry key="WRITE" value-ref="writeDataSource"/>
</map>
</property>
<!-- 默認(rèn)的數(shù)據(jù)源 -->
<property name="defaultTargetDataSource" ref="writeDataSource"/>
</bean>
數(shù)據(jù)源是如何切換的呢?通過動態(tài)數(shù)據(jù)源的配置我們知道原來是通過key來進行切換喳挑,這里要使用到org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource
,我們可以編寫自己的動態(tài)數(shù)據(jù)源類DynamicDataSource
來繼承它芬为。
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getType();
}
}
還需要一個存放key的地方DataSourceContextHolder
為保證切換時線程安全我們使用ThreadLocal
來保存我們的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";
// 線程本地環(huán)境
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
// 設(shè)置數(shù)據(jù)源類型
public static void setType(String type) {
if(LOGGER.isDebugEnabled())
LOGGER.debug("==============切換數(shù)據(jù)源,類型:"+type+"================");
contextHolder.set(type);
}
// 獲取數(shù)據(jù)源類型
public static String getType() {
return (contextHolder.get());
}
// 清除數(shù)據(jù)源類型
public static void clearType() {
contextHolder.remove();
}
}
好了媚朦,我們可以通過操作DataSourceContextHolder
來實現(xiàn)數(shù)據(jù)源動態(tài)的切換了。小伙伴們可能會說了日戈,難道每次調(diào)用方法都要手動選擇要切換的數(shù)據(jù)源類型询张?當(dāng)然不是啦,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("============切換到讀數(shù)據(jù)源===========");
DataSourceContextHolder.setType(DataSourceContextHolder.DATA_SOURCE_READ);
}
@Before("writeMethodPointcut()")
public void switchWriteDataSource(){
//System.out.println("=============切換到寫數(shù)據(jù)源==========");
DataSourceContextHolder.setType(DataSourceContextHolder.DATA_SOURCE_WRITE);
}
}
好啦份氧,在訪問Mapper(本項目使用的是MyBatis啦,相當(dāng)于是DAO)中查詢
方法時會切換到讀數(shù)據(jù)源弯屈,增蜗帜、刪、改
方法會切換到寫數(shù)據(jù)源资厉。