Spring配置动态数据源实现读写分离的方法
前言
最近因为工作的需要,要搭建的一个项目需要实现数据源的读写分离,在这里将代码进行分享,有需要的朋友们可以参考学习。
首先是配置数据源
<!--读数据源配置--> <beanid="readDataSource"class="com.alibaba.druid.pool.DruidDataSource"init-method="init"destroy-method="close"> //配置省略 </bean> <!--写数据源配置--> <beanid="writeDataSource"class="com.alibaba.druid.pool.DruidDataSource"init-method="init"destroy-method="close"> //配置省略 </bean> <!--动态数据源--> <beanid="dataSource"class="com.potato.common.bean.DynamicDataSource"> <!--已配置的数据源--> <propertyname="targetDataSources"> <map> <entrykey="READ"value-ref="readDataSource"/> <entrykey="WRITE"value-ref="writeDataSource"/> </map> </property> <!--默认的数据源--> <propertyname="defaultTargetDataSource"ref="writeDataSource"/> </bean>
数据源是如何切换的呢?通过动态数据源的配置我们知道原来是通过key来进行切换,这里要使用到org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource,我们可以编写自己的动态数据源类DynamicDataSource来继承它。
publicclassDynamicDataSourceextendsAbstractRoutingDataSource{ @Override protectedObjectdetermineCurrentLookupKey(){ returnDataSourceContextHolder.getType(); } }
还需要一个存放key的地方DataSourceContextHolder为保证切换时线程安全我们使用ThreadLocal来保存我们的key。
publicclassDataSourceContextHolder{ privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(DataSourceContextHolder.class); publicstaticfinalStringDATA_SOURCE_WRITE="WRITE"; publicstaticfinalStringDATA_SOURCE_READ="READ"; //线程本地环境 privatestaticfinalThreadLocal<String>contextHolder=newThreadLocal<String>(); //设置数据源类型 publicstaticvoidsetType(Stringtype){ if(LOGGER.isDebugEnabled()) LOGGER.debug("==============切换数据源,类型:"+type+"================"); contextHolder.set(type); } //获取数据源类型 publicstaticStringgetType(){ return(contextHolder.get()); } //清除数据源类型 publicstaticvoidclearType(){ contextHolder.remove(); } }
好了,我们可以通过操作DataSourceContextHolder来实现数据源动态的切换了。小伙伴们可能会说了,难道每次调用方法都要手动选择要切换的数据源类型?当然不是啦,SpringAOP登场。
@Component @Aspect publicclassDynamicDataSourceAspect{ @Pointcut("execution(*com.potato.orm.mapper.*.select*(..))||execution(*com.potato.orm.mapper.*.count*(..))") publicvoidreadMethodPointcut(){} @Pointcut("execution(*com.potato.orm.mapper.*.insert*(..))||execution(*com.potato.orm.mapper.*.update*(..))||execution(*com.potato.orm.mapper.*.delete*(..))") publicvoidwriteMethodPointcut(){} @Before("readMethodPointcut()") publicvoidswitchReadDataSource(){ //System.out.println("============切换到读数据源==========="); DataSourceContextHolder.setType(DataSourceContextHolder.DATA_SOURCE_READ); } @Before("writeMethodPointcut()") publicvoidswitchWriteDataSource(){ //System.out.println("=============切换到写数据源=========="); DataSourceContextHolder.setType(DataSourceContextHolder.DATA_SOURCE_WRITE); } }
总结
好啦,以上就是这篇文章的全部内容了,在访问Mapper(本项目使用的是MyBatis啦,相当于是DAO)中查询方法时会切换到读数据源,增、删、改方法会切换到写数据源。希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。