前言
最近因為工作的需要,要搭建的一個項目需要實現數據源的讀寫分離,在這里將代碼進行分享,有需要的朋友們可以參考學習。
首先是配置數據源
<!--讀數據源配置--><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>
數據源是如何切換的呢?通過動態數據源的配置我們知道原來是通過key來進行切換,這里要使用到org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource,我們可以編寫自己的動態數據源類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"; // 線程本地環境 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(); }}好了,我們可以通過操作DataSourceContextHolder來實現數據源動態的切換了。小伙伴們可能會說了,難道每次調用方法都要手動選擇要切換的數據源類型?當然不是啦,Spring AOP登場。
@Component@Aspectpublic 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); }}總結
好啦,以上就是這篇文章的全部內容了,在訪問Mapper(本項目使用的是MyBatis啦,相當于是DAO)中查詢方法時會切換到讀數據源,增、刪、改方法會切換到寫數據源。希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流。
新聞熱點
疑難解答