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

实现思路:
配置多个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. ajax cache enable and ajax concurrency!

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

  2. 【Visual Studio】VS2013的Release模式下进行调试(转)

    原文转自 http://blog.csdn.net/haizimin/article/details/50262901 在有的情况下,我们可能不能直接利用Debug模式进行程序调试,那么如何在Rele ...

  3. Change visual studio 2015 enterprise installation path(转)

    I would like to install VS2015 in a drive different than C:. The problem is that when I run the inst ...

  4. 慕课 python 操作数据库

    test_connection import MySQLdb conn = MySQLdb.Connect( host = '127.0.0.1', port = 3306, user = '**** ...

  5. django:访问本地静态文件的配置

    1.在setting.py中新增如下配置,static为静态文件的目录,BASE_DIR为项目根目录 STATIC_URL = '/static/' STATIC_ROOT = os.path.joi ...

  6. Ubuntu 16.04 LTS 成功编译 Android 6.0 源码教程

    sudo apt-get install -y git flex bison gperf build-essential libncurses5-dev:i386 \  libx11-dev:i386 ...

  7. hdu 1588(矩阵好题+递归求解等比数列)

    Gauss Fibonacci Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)T ...

  8. PropertyPlaceholderConfigurer 基本用法

    目录 一.PropertyPlaceholderConfigurer 的继承体系 二.PropertyPlaceholderConfigurer 的基本概念 三.PropertyPlaceholder ...

  9. Java并发容器,底层原理深入分析

    ConcurrentHashMap ConcurrentHashMap底层具体实现 JDK 1.7底层实现 将数据分为一段一段的存储,然后给每一段数据配一把锁, 当一个线程占用锁访问其中一个段数据时, ...

  10. SpringMVC中 Controller的 @ResponseBody注解分析

    需求分析:需要 利用    out 对象返回给财付通是否接收成功 .那么将需要如下代码: /** * 返回处理结果给财付通服务器. * @param msg: Success or fail. * @ ...