前言
最近因为工作的需要,要搭建的一个项目需要实现数据源的读写分离,在这里将代码进行分享,有需要的朋友们可以参考学习。
首先是配置数据源
<!--读数据源配置--> <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 @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)中查询方法时会切换到读数据源,增、删、改方法会切换到写数据源。希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。
如对本文有疑问, 点击进行留言回复!!
Android 4.0使用Kotlin调用C语言以及汇编语言
Java Class.forName()用法和newInstance()方法原理解析
网友评论