spring+mybatis多数据源,动态切换
有时我们项目中需要配置多个数据源,不同的业务使用的数据库不同
实现思路:
配置多个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多数据源,动态切换的更多相关文章
- spring+mybatis多数据源动态切换
spring mvc+mybatis+多数据源切换 选取oracle,mysql作为例子切换数据源.oracle为默认数据源,在测试的action中,进行mysql和oracle的动态切换. web. ...
- mybatis 多数据源动态切换
笔者主要从事c#开发,近期因为项目需要,搭建了一套spring-cloud微服务框架,集成了eureka服务注册中心. gateway网关过滤.admin服务监控.auth授权体系验证,集成了redi ...
- Spring + Mybatis 项目实现动态切换数据源
项目背景:项目开发中数据库使用了读写分离,所有查询语句走从库,除此之外走主库. 最简单的办法其实就是建两个包,把之前数据源那一套配置copy一份,指向另外的包,但是这样扩展很有限,所有采用下面的办法. ...
- 170615、spring不同数据库数据源动态切换
spring mvc+mybatis+多数据源切换 选取Oracle,MySQL作为例子切换数据源.mysql为默认数据源,在测试的action中,进行mysql和oracle的动态切换. 1.web ...
- springboot多数据源动态切换和自定义mybatis分页插件
1.配置多数据源 增加druid依赖 完整pom文件 数据源配置文件 route.datasource.driver-class-name= com.mysql.jdbc.Driver route.d ...
- Spring多数据源动态切换
title: Spring多数据源动态切换 date: 2019-11-27 categories: Java Spring tags: 数据源 typora-root-url: ...... --- ...
- 实战:Spring AOP实现多数据源动态切换
需求背景 去年底,公司项目有一个需求中有个接口需要用到平台.算法.大数据等三个不同数据库的数据进行计算.组装以及最后的展示,当时这个需求是另一个老同事在做,我只是负责自己的部分. 直到今年回来了,这个 ...
- Spring3.3 整合 Hibernate3、MyBatis3.2 配置多数据源/动态切换数据源 方法
一.开篇 这里整合分别采用了Hibernate和MyBatis两大持久层框架,Hibernate主要完成增删改功能和一些单一的对象查询功能,MyBatis主要负责查询功能.所以在出来数据库方言的时候基 ...
- Spring3.3 整合 Hibernate3、MyBatis3.2 配置多数据源/动态切换数据源方法
一.开篇 这里整合分别采用了Hibernate和MyBatis两大持久层框架,Hibernate主要完成增删改功能和一些单一的对象查询功能,MyBatis主要负责查询功能.所以在出来数据库方言的时候基 ...
- Springboot多数据源配置--数据源动态切换
在上一篇我们介绍了多数据源,但是我们会发现在实际中我们很少直接获取数据源对象进行操作,我们常用的是jdbcTemplate或者是jpa进行操作数据库.那么这一节我们将要介绍怎么进行多数据源动态切换.添 ...
随机推荐
- DevExpress GridControl 控件点滴
一.常用控件样式 public void setDgv(DevExpress.XtraGrid.Views.Grid.GridView gridView1) { gridView1.OptionsVi ...
- net5:自定义验证控件服务器端验证与客户端验证的使用
原文发布时间为:2008-07-29 -- 来源于本人的百度文章 [由搬家工具导入] using System;using System.Data;using System.Configuration ...
- css3 手机端翻屏切换效果
原理是基于css3的 1.景深:perspective:100px; 2.中心点:transform-origin:center center 0; 3.transform-style:preserv ...
- LeetCode OJ-- Spiral Matrix II
https://oj.leetcode.com/problems/spiral-matrix-ii/ 螺旋矩阵,和题目一一样的思路,这个是产生n*n 矩阵. #include <iostream ...
- [开源] FreeSql.Tools Razor 生成器
FreeSql 经过半年的开发和坚持维护,在 0.6.x 版本中完成了几大重要事件: 1.按小包拆分,每个数据库实现为单独 dll: 2.实现 .net framework 4.5 支持: 3.同时支 ...
- Ext grid单元格编辑时获取获取Ext.grid.column.Column
item2.width = 80; //item2.flex = 1; item2.align = 'center'; item2.menuDisabled = true; //禁止显示列头部右侧菜单 ...
- 深入理解Java中的HashMap的实现原理
HashMap继承自抽象类AbstractMap,抽象类AbstractMap实现了Map接口.关系图例如以下所看到的: Java中的Map<key, value>接口同意我们将一个对象作 ...
- Basic Vim Configuration
原文: https://computers.tutsplus.com/tutorials/basic-vim-configuration--cms-21498 原来,vim的配置文件,.vimrc也是 ...
- List<InvestInfoDO> invest = advertiseDao6.qryInvestInfo(InvestInfoDO1);怎样获得list的实体类;
List<InvestInfoDO> invest = advertiseDao6.qryInvestInfo(InvestInfoDO1); 怎样获得List的实体类呢,就是怎样获得I ...
- Odoo(OpenERP)开发实践:通过XML-RPC接口訪问Odoo数据库
Odoo(OpenERP)server支持通过XML-RPC接口訪问.操作数据库,基于此可实现与其它系统的交互与集成. 本文是使用Java通过XMLRPC接口操作Odoo数据库的简单演示样例.本例引用 ...