前言
最近因為工作的需要,要搭建的一個項目需要實現數據源的讀寫分離,在這里將代碼進行分享,有需要的朋友們可以參考學習。
首先是配置數據源
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> |
數據源是如何切換的呢?通過動態數據源的配置我們知道原來是通過key來進行切換,這里要使用到org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource
,我們可以編寫自己的動態數據源類DynamicDataSource
來繼承它。
1
2
3
4
5
6
|
public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DataSourceContextHolder.getType(); } } |
還需要一個存放key的地方DataSourceContextHolder
為保證切換時線程安全我們使用ThreadLocal
來保存我們的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(); } } |
好了,我們可以通過操作DataSourceContextHolder
來實現數據源動態的切換了。小伙伴們可能會說了,難道每次調用方法都要手動選擇要切換的數據源類型?當然不是啦,Spring AOP登場。
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(){ //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)中查詢方法時會切換到讀數據源,增、刪、改方法會切換到寫數據源。希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流。
原文鏈接:http://www.jianshu.com/p/077395e7e66f