项目背景:项目开发中数据库使用了读写分离,所有查询语句走从库,除此之外走主库。
最简单的办法其实就是建两个包,把之前数据源那一套配置copy一份,指向另外的包,但是这样扩展很有限,所有采用下面的办法。
参考了两篇文章如下:
https://www.nhooo.com/article/111840.htm
https://www.nhooo.com/article/111842.htm
这两篇文章都对原理进行了分析,下面只写自己的实现过程其他不再叙述。
实现思路是:
第一步,实现动态切换数据源:配置两个DataSource,配置两个SqlSessionFactory指向两个不同的DataSource,两个SqlSessionFactory都用一个SqlSessionTemplate,同时重写Mybatis提供的SqlSessionTemplate类,最后配置Mybatis自动扫描。
第二步,利用aop切面,拦截dao层所有方法,因为dao层方法命名的特点,比如所有查询sql都是select开头,或者get开头等等,拦截这些方法,并把当前数据源切换至从库。
spring中配置如下:
主库数据源配置:
2
从库数据源配置:
主库SqlSessionFactory配置:
从库SqlSessionFactory配置:
两个SqlSessionFactory使用同一个SqlSessionTemplate配置:
配置Mybatis自动扫描dao
自己重写了SqlSessionTemplate代码如下:
packagecom.sincetimes.slg.framework.core;
importstaticjava.lang.reflect.Proxy.newProxyInstance;
importstaticorg.apache.ibatis.reflection.ExceptionUtil.unwrapThrowable;
importstaticorg.mybatis.spring.SqlSessionUtils.closeSqlSession;
importstaticorg.mybatis.spring.SqlSessionUtils.getSqlSession;
importstaticorg.mybatis.spring.SqlSessionUtils.isSqlSessionTransactional;
importjava.lang.reflect.InvocationHandler;
importjava.lang.reflect.Method;
importjava.sql.Connection;
importjava.util.List;
importjava.util.Map;
importorg.apache.ibatis.exceptions.PersistenceException;
importorg.apache.ibatis.executor.BatchResult;
importorg.apache.ibatis.session.Configuration;
importorg.apache.ibatis.session.ExecutorType;
importorg.apache.ibatis.session.ResultHandler;
importorg.apache.ibatis.session.RowBounds;
importorg.apache.ibatis.session.SqlSession;
importorg.apache.ibatis.session.SqlSessionFactory;
importorg.mybatis.spring.MyBatisExceptionTranslator;
importorg.mybatis.spring.SqlSessionTemplate;
importorg.springframework.dao.support.PersistenceExceptionTranslator;
importorg.springframework.util.Assert;
importcom.sincetimes.slg.framework.util.SqlSessionContentHolder;
/**
*
*TODO重写SqlSessionTemplate
*@authorccg
*@version1.0
*Created2017年4月21日下午3:15:15
*/
publicclassDynamicSqlSessionTemplateextendsSqlSessionTemplate{
privatefinalSqlSessionFactorysqlSessionFactory;
privatefinalExecutorTypeexecutorType;
privatefinalSqlSessionsqlSessionProxy;
privatefinalPersistenceExceptionTranslatorexceptionTranslator;
privateMap
SqlSessionContentHolder类代码如下:
packagecom.sincetimes.slg.framework.util;
publicabstractclassSqlSessionContentHolder{
publicfinalstaticStringSESSION_FACTORY_MASTER="master";
publicfinalstaticStringSESSION_FACTORY_SLAVE="slave";
privatestaticfinalThreadLocalcontextHolder=newThreadLocal();
publicstaticvoidsetContextType(StringcontextType){
contextHolder.set(contextType);
}
publicstaticStringgetContextType(){
returncontextHolder.get();
}
publicstaticvoidclearContextType(){
contextHolder.remove();
}
}
最后就是写切面去对dao所有方法进行处理了,代码很简单如下:
packagecom.sincetimes.slg.framework.core;
importorg.aspectj.lang.JoinPoint;
importorg.aspectj.lang.annotation.Aspect;
importorg.aspectj.lang.annotation.Before;
importorg.aspectj.lang.annotation.Pointcut;
importcom.sincetimes.slg.framework.util.SqlSessionContentHolder;
@Aspect
publicclassDynamicDataSourceAspect{
@Pointcut("execution(*com.sincetimes.slg.dao.*.*(..))")
publicvoidpointCut(){
}
@Before("pointCut()")
publicvoidbefore(JoinPointjp){
StringmethodName=jp.getSignature().getName();
//dao方法查询走从库
if(methodName.startsWith("query")||methodName.startsWith("get")||methodName.startsWith("count")||methodName.startsWith("list")){
SqlSessionContentHolder.setContextType(SqlSessionContentHolder.SESSION_FACTORY_SLAVE);
}else{
SqlSessionContentHolder.setContextType(SqlSessionContentHolder.SESSION_FACTORY_MASTER);
}
}
}
以上所述是小编给大家介绍的Spring+Mybatis项目实现动态切换数据源实例详解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!