有时我们项目中需要配置多个数据源,不同的业务使用的数据库不同

实现思路:
配置多个dataSource ,再配置多个sqlSessionFactory,和dataSource一一对应。
重写SqlSessionTemplate,支持多个sqlSessionFactory。最后配置mybatis自动扫描MapperScannerConfigurer。增加切面,在访问数据库前动态获取数据源

相关配置

    <!-- 配置sqlSessionFactory -->
<bean id="sqlSessionFactory_product" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource_product" />
<property name="configLocation" value="classpath:mybatis-config.xml" />
<property name="mapperLocations" value="classpath*:com/zyx/demo/**/*Mapper.xml"/>
</bean>
<!-- 配置sqlSessionFactory -->
<bean id="sqlSessionFactory_promotion" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource_promotion" />
<property name="configLocation" value="classpath:mybatis-config.xml" />
<property name="mapperLocations" value="classpath*:com/zyx/demo/**/*Mapper.xml"/>
</bean> <!-- 重写sqlSessionTemplate实现,支持多个SQLSessionFactory -->
<bean id="dynamicSqlSessionTemplate" class="com.zyx.demo.common.mybatis.DynamicSqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory_product" />
<property name="targetSqlSessionFactorys">
<map key-type="java.lang.String">
<entry value-ref="sqlSessionFactory_product" key="PRODUCT" />
<entry value-ref="sqlSessionFactory_promotion" key="PROMOTION" />
</map>
</property>
<property name="defaultTargetSqlSessionFactory" ref="sqlSessionFactory_product" />
</bean> <!-- 配置MapperScannerConfigurer -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionTemplateBeanName" value="dynamicSqlSessionTemplate" />
<property name="basePackage" value="com.zyx.demo.**.dao" />
</bean> <!-- 定义切面 -->
<bean id="dynamicDataSourceAspectJ" class="com.zyx.demo.common.aop.DynamicDataSourceAspectJ" />
<aop:config proxy-target-class="false" expose-proxy="true">
<aop:pointcut expression="execution(* com.zyx.demo.*.dao..*.*(..))" id="datasource-pointcut" />
<aop:aspect ref="dynamicDataSourceAspectJ">
<aop:before method="switchDataSource" pointcut-ref="datasource-pointcut" />
</aop:aspect>
</aop:config>

重写sqlSessionTemplate

public class DynamicSqlSessionTemplate extends SqlSessionTemplate {

    private static Logger logger = LoggerFactory.getLogger(DynamicSqlSessionTemplate.class);

    private SqlSessionFactory sqlSessionFactory;
private ExecutorType executorType;
private SqlSession sqlSessionProxy;
private PersistenceExceptionTranslator exceptionTranslator;
private Map<Object, SqlSessionFactory> targetSqlSessionFactorys;
private SqlSessionFactory defaultTargetSqlSessionFactory; public void setTargetSqlSessionFactorys(Map<Object, SqlSessionFactory> targetSqlSessionFactorys) {
this.targetSqlSessionFactorys = targetSqlSessionFactorys;
} public void setDefaultTargetSqlSessionFactory(SqlSessionFactory defaultTargetSqlSessionFactory) {
this.defaultTargetSqlSessionFactory = defaultTargetSqlSessionFactory;
} public DynamicSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
this(sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType());
} public DynamicSqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType) {
this(sqlSessionFactory, executorType, new MyBatisExceptionTranslator(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(), true));
} public DynamicSqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
super(sqlSessionFactory, executorType, exceptionTranslator);
this.sqlSessionFactory = sqlSessionFactory;
this.executorType = executorType;
this.exceptionTranslator = exceptionTranslator;
this.sqlSessionProxy = (SqlSession) newProxyInstance(SqlSessionFactory.class.getClassLoader(), new Class[] { SqlSession.class }, new SqlSessionInterceptor());
this.defaultTargetSqlSessionFactory = sqlSessionFactory;
} @Override
public SqlSessionFactory getSqlSessionFactory() {
String dataSourceType = DynamicDataSourceContextHolder.getDataSourceType();
SqlSessionFactory targetSqlSessionFactory = targetSqlSessionFactorys.get(dataSourceType);
if (targetSqlSessionFactory != null) {
return targetSqlSessionFactory;
} else if (defaultTargetSqlSessionFactory != null) {
if (dataSourceType != null) {
logger.warn("此[" + dataSourceType + "]dataSourceType未配置文件中配置targetSqlSessionFactorys,将会返回defaultTargetSqlSessionFactory来执行后面的操作");
}
return defaultTargetSqlSessionFactory;
} else {
Assert.notNull(targetSqlSessionFactorys, "Property 'targetSqlSessionFactorys' or 'defaultTargetSqlSessionFactory' are required");
Assert.notNull(defaultTargetSqlSessionFactory, "Property 'defaultTargetSqlSessionFactory' or 'targetSqlSessionFactorys' are required");
}
return this.sqlSessionFactory;
} @Override
public Configuration getConfiguration() {
return this.getSqlSessionFactory().getConfiguration();
} public ExecutorType getExecutorType() {
return this.executorType;
} public PersistenceExceptionTranslator getPersistenceExceptionTranslator() {
return this.exceptionTranslator;
} public <T> T selectOne(String statement) {
return this.sqlSessionProxy.<T> selectOne(statement);
} public <T> T selectOne(String statement, Object parameter) {
return this.sqlSessionProxy.<T> selectOne(statement, parameter);
} public <K, V> Map<K, V> selectMap(String statement, String mapKey) {
return this.sqlSessionProxy.<K, V> selectMap(statement, mapKey);
} public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
return this.sqlSessionProxy.<K, V> selectMap(statement, parameter, mapKey);
} public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
return this.sqlSessionProxy.<K, V> selectMap(statement, parameter, mapKey, rowBounds);
} public <E> List<E> selectList(String statement) {
return this.sqlSessionProxy.<E> selectList(statement);
}
public <E> List<E> selectList(String statement, Object parameter) {
return this.sqlSessionProxy.<E> selectList(statement, parameter);
} public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
return this.sqlSessionProxy.<E> selectList(statement, parameter, rowBounds);
} public void select(String statement, ResultHandler handler) {
this.sqlSessionProxy.select(statement, handler);
} public void select(String statement, Object parameter, ResultHandler handler) {
this.sqlSessionProxy.select(statement, parameter, handler);
} public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
this.sqlSessionProxy.select(statement, parameter, rowBounds, handler);
} public int insert(String statement) {
return this.sqlSessionProxy.insert(statement);
} public int insert(String statement, Object parameter) {
return this.sqlSessionProxy.insert(statement, parameter);
} public int update(String statement) {
return this.sqlSessionProxy.update(statement);
} public int update(String statement, Object parameter) {
return this.sqlSessionProxy.update(statement, parameter);
} public int delete(String statement) {
return this.sqlSessionProxy.delete(statement);
} public int delete(String statement, Object parameter) {
return this.sqlSessionProxy.delete(statement, parameter);
} public <T> T getMapper(Class<T> type) {
return getConfiguration().getMapper(type, this);
} public void commit() {
throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession");
} public void commit(boolean force) {
throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession");
} public void rollback() {
throw new UnsupportedOperationException("Manual rollback is not allowed over a Spring managed SqlSession");
} public void rollback(boolean force) {
throw new UnsupportedOperationException("Manual rollback is not allowed over a Spring managed SqlSession");
} public void close() {
throw new UnsupportedOperationException("Manual close is not allowed over a Spring managed SqlSession");
} public void clearCache() {
this.sqlSessionProxy.clearCache();
} public Connection getConnection() {
return this.sqlSessionProxy.getConnection();
} public List<BatchResult> flushStatements() {
return this.sqlSessionProxy.flushStatements();
} private class SqlSessionInterceptor implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
SqlSession sqlSession = getSqlSession(DynamicSqlSessionTemplate.this.getSqlSessionFactory(), DynamicSqlSessionTemplate.this.executorType, DynamicSqlSessionTemplate.this.exceptionTranslator);
try {
Object result = method.invoke(sqlSession, args);
if (!isSqlSessionTransactional(sqlSession, DynamicSqlSessionTemplate.this.getSqlSessionFactory())) {
sqlSession.commit(true);
}
return result;
} catch (Throwable t) {
Throwable unwrapped = unwrapThrowable(t);
if (DynamicSqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
closeSqlSession(sqlSession, DynamicSqlSessionTemplate.this.getSqlSessionFactory());
sqlSession = null;
Throwable translated = DynamicSqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
if (translated != null) {
unwrapped = translated;
}
}
throw unwrapped;
} finally {
if (sqlSession != null) {
closeSqlSession(sqlSession, DynamicSqlSessionTemplate.this.getSqlSessionFactory());
}
}
}
}
}

增加切面

public class DynamicDataSourceAspectJ {

    private Logger logger = LoggerFactory.getLogger(DynamicDataSourceAspectJ.class);

    /**
* 切换数据源*/
public void switchDataSource(JoinPoint joinPoint) {
try {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
boolean methodAnnotation = method.isAnnotationPresent(DynamicDataSource.class);
DynamicDataSource dynamicDataSource = method.getAnnotation(DynamicDataSource.class);
if (!methodAnnotation) {
Class<?> clazzs[] = joinPoint.getTarget().getClass().getInterfaces();
if (clazzs != null && clazzs.length>0) {
Class<?> clazz = clazzs[0];
dynamicDataSource = (DynamicDataSource) clazz.getAnnotation(DynamicDataSource.class);
if (dynamicDataSource != null) {
DynamicDataSourceContextHolder.setDataSourceType(dynamicDataSource.dataSourceType());
}
}
}
} catch (Exception e) {
logger.error("切换数据源异常:" + e.getMessage(), e);
}
}
}
public class DynamicDataSourceContextHolder {

    /**
* DataSource上下文,每个线程对应相应的数据源key
*/
public static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
private static Logger logger = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);
public static void setDataSourceType(String dataSourceType) {
contextHolder.set(dataSourceType);
} public static String getDataSourceType() {String dataSourceType = contextHolder.get();
logger.debug("当前线程Thread:" + Thread.currentThread().getName() + " 当前的数据源 key is " + dataSourceType);
return dataSourceType;
} public static void clearDataSourceType() {
contextHolder.remove();
}
}

自定义标签,需要在dao层的接口上声明数据源

@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface DynamicDataSource { public final static String PRODUCT = "PRODUCT";
public final static String PROMOTION = "PROMOTION"; String dataSourceType() default DynamicDataSource.PRODUCT;
}

spring+mybatis多数据源,动态切换的更多相关文章

  1. spring+mybatis多数据源动态切换

    spring mvc+mybatis+多数据源切换 选取oracle,mysql作为例子切换数据源.oracle为默认数据源,在测试的action中,进行mysql和oracle的动态切换. web. ...

  2. mybatis 多数据源动态切换

    笔者主要从事c#开发,近期因为项目需要,搭建了一套spring-cloud微服务框架,集成了eureka服务注册中心. gateway网关过滤.admin服务监控.auth授权体系验证,集成了redi ...

  3. Spring + Mybatis 项目实现动态切换数据源

    项目背景:项目开发中数据库使用了读写分离,所有查询语句走从库,除此之外走主库. 最简单的办法其实就是建两个包,把之前数据源那一套配置copy一份,指向另外的包,但是这样扩展很有限,所有采用下面的办法. ...

  4. 170615、spring不同数据库数据源动态切换

    spring mvc+mybatis+多数据源切换 选取Oracle,MySQL作为例子切换数据源.mysql为默认数据源,在测试的action中,进行mysql和oracle的动态切换. 1.web ...

  5. springboot多数据源动态切换和自定义mybatis分页插件

    1.配置多数据源 增加druid依赖 完整pom文件 数据源配置文件 route.datasource.driver-class-name= com.mysql.jdbc.Driver route.d ...

  6. Spring多数据源动态切换

    title: Spring多数据源动态切换 date: 2019-11-27 categories: Java Spring tags: 数据源 typora-root-url: ...... --- ...

  7. 实战:Spring AOP实现多数据源动态切换

    需求背景 去年底,公司项目有一个需求中有个接口需要用到平台.算法.大数据等三个不同数据库的数据进行计算.组装以及最后的展示,当时这个需求是另一个老同事在做,我只是负责自己的部分. 直到今年回来了,这个 ...

  8. Spring3.3 整合 Hibernate3、MyBatis3.2 配置多数据源/动态切换数据源 方法

    一.开篇 这里整合分别采用了Hibernate和MyBatis两大持久层框架,Hibernate主要完成增删改功能和一些单一的对象查询功能,MyBatis主要负责查询功能.所以在出来数据库方言的时候基 ...

  9. Spring3.3 整合 Hibernate3、MyBatis3.2 配置多数据源/动态切换数据源方法

    一.开篇 这里整合分别采用了Hibernate和MyBatis两大持久层框架,Hibernate主要完成增删改功能和一些单一的对象查询功能,MyBatis主要负责查询功能.所以在出来数据库方言的时候基 ...

  10. Springboot多数据源配置--数据源动态切换

    在上一篇我们介绍了多数据源,但是我们会发现在实际中我们很少直接获取数据源对象进行操作,我们常用的是jdbcTemplate或者是jpa进行操作数据库.那么这一节我们将要介绍怎么进行多数据源动态切换.添 ...

随机推荐

  1. javaweb学习总结(十六)——JSP指令(转)

    一.JSP指令简介 JSP指令(directive)是为JSP引擎而设计的,它们并不直接产生任何可见输出,而只是告诉引擎如何处理JSP页面中的其余部分. 在JSP 2.0规范中共定义了三个指令: pa ...

  2. 【CF505D】Mr. Kitayuta's Technology

    题目大意: 在一个有向图中,有n个顶点,给出m对数字(u,v)表示顶点u和顶点v必须直接或者间接相连,让你构造一个这样的图,输出最少需要多少条边. 挖坑待填 官方题解链接:http://codefor ...

  3. ajax cache enable and ajax concurrency!

    Today, forget to close ajax cache which leads to duplicate result from cache as to Jquery, this way, ...

  4. javascript 函数重载另一种实现办法

    最近在读javascript忍者 感受下jquery作者 john Resig对于js的独到见解. 先上代码: function addMethod(object,name,fn){ var old ...

  5. wpf GridControl selectAll UnSelect

    <Window x:Class="WpfApplication1.GridControlView" xmlns="http://schemas.microsoft. ...

  6. 贪心—— P1809 过河问题_NOI导刊2011提高(01)

    洛谷——P1809 过河问题_NOI导刊2011提高(01) 题目描述 有一个大晴天,Oliver与同学们一共N人出游,他们走到一条河的东岸边,想要过河到西岸.而东岸边有一条小船. 船太小了,一次只能 ...

  7. 第1章 CentOS安装

    一.安装说明 1.1 CentOS介绍               CentOS(Community Enterprise Operating System,中文意思是:社区企业操作系统)是Linux ...

  8. 邁向IT專家成功之路的三十則鐵律 鐵律二:IT專家專業之道–專精

    在IT技術的領域當中有許多的類別,若要細分那可真是難以一一列舉,但常見的大致有軟體研發工程師.韌體研發工程師.系統分析師.網路工程師.系統工程師.維護工程師.動畫設計師.製圖工程師.以及各類別的專業電 ...

  9. 【spring data jpa】使用spring data jpa 的删除操作,需要加注解@Modifying @Transactional 否则报错如下: No EntityManager with actual transaction available for current thread - cannot reliably process 'remove' call

    使用spring data jpa 的删除操作,需要加注解@Modifying     @Transactional 否则报错如下: No EntityManager with actual tran ...

  10. git 怎样删除远程仓库的最近一次错误提交?

    假设你有3个commit如下: commit 3 commit 2 commit 1 其中最后一次提交commit 3是错误的,那么可以执行: git reset --hard HEAD~1 你会发现 ...