在Spring项目中使用 Mybatis 如何实现动态切换数据源

发布时间:2020-11-17 16:20:11

来源:亿速云

阅读:108

作者:Leah

这篇文章将为大家详细讲解有关在Spring项目中使用 Mybatis 如何实现动态切换数据源,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

实现思路是:

第一步,实现动态切换数据源:配置两个DataSource,配置两个SqlSessionFactory指向两个不同的DataSource,两个SqlSessionFactory都用一个SqlSessionTemplate,同时重写Mybatis提供的SqlSessionTemplate类,最后配置Mybatis自动扫描。

第二步,利用aop切面,拦截dao层所有方法,因为dao层方法命名的特点,比如所有查询sql都是select开头,或者get开头等等,拦截这些方法,并把当前数据源切换至从库。

spring中配置如下:

主库数据源配置:

2

从库数据源配置:

主库SqlSessionFactory配置:

从库SqlSessionFactory配置:

两个SqlSessionFactory使用同一个SqlSessionTemplate配置:

配置Mybatis自动扫描dao

自己重写了SqlSessionTemplate代码如下:

package com.sincetimes.slg.framework.core;

import static java.lang.reflect.Proxy.newProxyInstance;

import static org.apache.ibatis.reflection.ExceptionUtil.unwrapThrowable;

import static org.mybatis.spring.SqlSessionUtils.closeSqlSession;

import static org.mybatis.spring.SqlSessionUtils.getSqlSession;

import static org.mybatis.spring.SqlSessionUtils.isSqlSessionTransactional;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.sql.Connection;

import java.util.List;

import java.util.Map;

import org.apache.ibatis.exceptions.PersistenceException;

import org.apache.ibatis.executor.BatchResult;

import org.apache.ibatis.session.Configuration;

import org.apache.ibatis.session.ExecutorType;

import org.apache.ibatis.session.ResultHandler;

import org.apache.ibatis.session.RowBounds;

import org.apache.ibatis.session.SqlSession;

import org.apache.ibatis.session.SqlSessionFactory;

import org.mybatis.spring.MyBatisExceptionTranslator;

import org.mybatis.spring.SqlSessionTemplate;

import org.springframework.dao.support.PersistenceExceptionTranslator;

import org.springframework.util.Assert;

import com.sincetimes.slg.framework.util.SqlSessionContentHolder;

/**

*

* TODO 重写SqlSessionTemplate

* @author ccg

* @version 1.0

* Created 2017年4月21日 下午3:15:15

*/

public class DynamicSqlSessionTemplate extends SqlSessionTemplate {

private final SqlSessionFactory sqlSessionFactory;

private final ExecutorType executorType;

private final SqlSession sqlSessionProxy;

private final PersistenceExceptionTranslator exceptionTranslator;

private Map targetSqlSessionFactorys;

private SqlSessionFactory defaultTargetSqlSessionFactory;

public void setTargetSqlSessionFactorys(Map targetSqlSessionFactorys) {

this.targetSqlSessionFactorys = targetSqlSessionFactorys;

}

public Map getTargetSqlSessionFactorys(){

return 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() {

SqlSessionFactory targetSqlSessionFactory = targetSqlSessionFactorys.get(SqlSessionContentHolder.getContextType());

if (targetSqlSessionFactory != null) {

return targetSqlSessionFactory;

} else if (defaultTargetSqlSessionFactory != null) {

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;

}

/**

* {@inheritDoc}

*/

public T selectOne(String statement) {

return this.sqlSessionProxy. selectOne(statement);

}

/**

* {@inheritDoc}

*/

public T selectOne(String statement, Object parameter) {

return this.sqlSessionProxy. selectOne(statement, parameter);

}

/**

* {@inheritDoc}

*/

public Map selectMap(String statement, String mapKey) {

return this.sqlSessionProxy. selectMap(statement, mapKey);

}

/**

* {@inheritDoc}

*/

public Map selectMap(String statement, Object parameter, String mapKey) {

return this.sqlSessionProxy. selectMap(statement, parameter, mapKey);

}

/**

* {@inheritDoc}

*/

public Map selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {

return this.sqlSessionProxy. selectMap(statement, parameter, mapKey, rowBounds);

}

/**

* {@inheritDoc}

*/

public List selectList(String statement) {

return this.sqlSessionProxy. selectList(statement);

}

/**

* {@inheritDoc}

*/

public List selectList(String statement, Object parameter) {

return this.sqlSessionProxy. selectList(statement, parameter);

}

/**

* {@inheritDoc}

*/

public List selectList(String statement, Object parameter, RowBounds rowBounds) {

return this.sqlSessionProxy. selectList(statement, parameter, rowBounds);

}

/**

* {@inheritDoc}

*/

public void select(String statement, ResultHandler handler) {

this.sqlSessionProxy.select(statement, handler);

}

/**

* {@inheritDoc}

*/

public void select(String statement, Object parameter, ResultHandler handler) {

this.sqlSessionProxy.select(statement, parameter, handler);

}

/**

* {@inheritDoc}

*/

public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {

this.sqlSessionProxy.select(statement, parameter, rowBounds, handler);

}

/**

* {@inheritDoc}

*/

public int insert(String statement) {

return this.sqlSessionProxy.insert(statement);

}

/**

* {@inheritDoc}

*/

public int insert(String statement, Object parameter) {

return this.sqlSessionProxy.insert(statement, parameter);

}

/**

* {@inheritDoc}

*/

public int update(String statement) {

return this.sqlSessionProxy.update(statement);

}

/**

* {@inheritDoc}

*/

public int update(String statement, Object parameter) {

return this.sqlSessionProxy.update(statement, parameter);

}

/**

* {@inheritDoc}

*/

public int delete(String statement) {

return this.sqlSessionProxy.delete(statement);

}

/**

* {@inheritDoc}

*/

public int delete(String statement, Object parameter) {

return this.sqlSessionProxy.delete(statement, parameter);

}

/**

* {@inheritDoc}

*/

public T getMapper(Class type) {

return getConfiguration().getMapper(type, this);

}

/**

* {@inheritDoc}

*/

public void commit() {

throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession");

}

/**

* {@inheritDoc}

*/

public void commit(boolean force) {

throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession");

}

/**

* {@inheritDoc}

*/

public void rollback() {

throw new UnsupportedOperationException("Manual rollback is not allowed over a Spring managed SqlSession");

}

/**

* {@inheritDoc}

*/

public void rollback(boolean force) {

throw new UnsupportedOperationException("Manual rollback is not allowed over a Spring managed SqlSession");

}

/**

* {@inheritDoc}

*/

public void close() {

throw new UnsupportedOperationException("Manual close is not allowed over a Spring managed SqlSession");

}

/**

* {@inheritDoc}

*/

public void clearCache() {

this.sqlSessionProxy.clearCache();

}

/**

* {@inheritDoc}

*/

public Connection getConnection() {

return this.sqlSessionProxy.getConnection();

}

/**

* {@inheritDoc}

* @since 1.0.2

*/

public List flushStatements() {

return this.sqlSessionProxy.flushStatements();

}

/**

* Proxy needed to route MyBatis method calls to the proper SqlSession got from Spring's Transaction Manager It also

* unwraps exceptions thrown by {@code Method#invoke(Object, Object...)} to pass a {@code PersistenceException} to

* the {@code PersistenceExceptionTranslator}.

*/

private class SqlSessionInterceptor implements InvocationHandler {

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

final 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())) {

// force commit even on non-dirty sessions because some databases require

// a commit/rollback before calling close()

sqlSession.commit(true);

}

return result;

} catch (Throwable t) {

Throwable unwrapped = unwrapThrowable(t);

if (DynamicSqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {

Throwable translated = DynamicSqlSessionTemplate.this.exceptionTranslator

.translateExceptionIfPossible((PersistenceException) unwrapped);

if (translated != null) {

unwrapped = translated;

}

}

throw unwrapped;

} finally {

closeSqlSession(sqlSession, DynamicSqlSessionTemplate.this.getSqlSessionFactory());

}

}

}

}

SqlSessionContentHolder类代码如下:

package com.sincetimes.slg.framework.util;

public abstract class SqlSessionContentHolder {

public final static String SESSION_FACTORY_MASTER = "master";

public final static String SESSION_FACTORY_SLAVE = "slave";

private static final ThreadLocal contextHolder = new ThreadLocal();

public static void setContextType(String contextType) {

contextHolder.set(contextType);

}

public static String getContextType() {

return contextHolder.get();

}

public static void clearContextType() {

contextHolder.remove();

}

}

最后就是写切面去对dao所有方法进行处理了,代码很简单如下:

package com.sincetimes.slg.framework.core;

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

import org.aspectj.lang.annotation.Pointcut;

import com.sincetimes.slg.framework.util.SqlSessionContentHolder;

@Aspect

public class DynamicDataSourceAspect {

@Pointcut("execution( * com.sincetimes.slg.dao.*.*(..))")

public void pointCut(){

}

@Before("pointCut()")

public void before(JoinPoint jp){

String methodName = 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 如何实现动态切换数据源就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

mybatis手动切换数据库_在Spring项目中使用 Mybatis 如何实现动态切换数据源相关推荐

  1. java动态拼接请求_在JavaWeb项目中处理静态文件或动态链接拼接网站地址的最优处理方案...

    在开发网站时候我们会遇到下面问题? - 在引用网页中引用js和css或者动态的Servlet的时候我们是写绝对路径还是相对路径? - 如果写相对路径吧,上线偶尔会报404,还要手动去拼接绝对路径 - ...

  2. Spring Boot 中使用 MyBatis 整合 Druid 多数据源

    本文将讲述 spring boot + mybatis + druid 多数据源配置方案. 环境 CentOs7.3 安装 MySQL 5.7.19 二进制版本 Github 代码 代码我已放到 Gi ...

  3. Spring Boot中使用MyBatis注解配置详解

    之前在Spring Boot中整合MyBatis时,采用了注解的配置方式,相信很多人还是比较喜欢这种优雅的方式的,也收到不少读者朋友的反馈和问题,主要集中于针对各种场景下注解如何使用,下面就对几种常见 ...

  4. 在Maven+Spring项目中使用Node.js的Gulp进行前端自动化构建

    摘要: 在Maven+Spring项目中使用Node.js的Gulp进行前端自动化构建 刚开始打算进行前后端分离开发,后来发现在使用JSP或者Freemarker做动态页面时,想发挥这些自动化构建工具 ...

  5. 在Spring项目中集成使用MongoDB

    在Spring项目中集成使用MongoDB 这里使用的是maven工程,所以依赖jar包都是pom.xml配置型式. pom.xml引入依赖 <properties><spring. ...

  6. 【SpringBoot项目中使用Mybatis批量插入百万条数据】

    SpringBoot项目中使用Mybatis批量插入百万条数据 话不多说,直接上代码,测试原生批处理的效率 开始测试 背景:因为一些业务问题,需要做多数据源,多库批量查询.插入操作,所以就研究了一下. ...

  7. spring 项目中集成 Protocol Buffers 示例

    http://blog.csdn.net/fangzhangsc2006/article/details/8687388 本文适用于了解spring框架,同时想在spring项目中使用Protocol ...

  8. 【SpringBoot】Spring项目中value注解,@Value不能够读取到配置文件的值,无法成功注入值的问题汇总及解决

    Spring项目中value注解,@Value不能够读取到配置文件的值,无法成功注入值的问题汇总及解决 @Value注解 常规用法示例 我们都知道通过@Value()注解可以取到我们配置文件的内容,之 ...

  9. 将MongoDB集成到您的Spring项目中

    本文展示了如何通过注释配置将MongoDB集成到您的spring项目中. 我们将从Gradle配置开始. group 'com.gkatzioura.spring' version '1.0-SNAP ...

最新文章

  1. Django models文件模型变更注意事项(表结构的修改)
  2. 1月份Web服务器份额:Microsoft涨2.32%居亚
  3. 顶刊学者带你深度理解本地差分隐私【会议笔记】
  4. 复杂多个合约部署验证方法
  5. CentOS 7安装Gnome GUI 图形界面
  6. 蓝桥杯c语言基础试题答案,蓝桥杯试题C语言答案.doc
  7. 计算机专业电子技术基础教学,计算机专业“电子技术基础”教学上的难题及对策.doc...
  8. MATLAB中linspace函数使用
  9. Unity (三) NavMeshAgent之:分层路面导航(王者荣耀,英雄联盟中小兵分三路进攻敌方)...
  10. KK模组与普通丝杠模组的区别
  11. C语言malloc与calloc区别
  12. turtle-绘制简易瞄准镜
  13. P和NP以及NPC、NP-Hard问题
  14. OPA Gatekeeper 策略入门
  15. Go语言和php个和lua,当 Go 遇上了 Lua
  16. 3D游戏建模师看不看学历?现在转行还能行吗?
  17. 计算机专业省赛一等奖有什么好处,省技能大赛一等奖好处有什么
  18. 数据可视化echarts介绍
  19. 产品开发:先行动,再研究
  20. 商业图表工具推荐,热门商业图表工具有哪些?

热门文章

  1. 让效率“爆表”的49个数据可视化工具
  2. == 和 equals方法的区别
  3. 太阳直射点纬度计算公式_全纬度昼夜长短通用公式
  4. c++ 模糊搜索 正则表达式_c++使用正则表达式提取关键字的方法
  5. Typora+PicGo+SMMS、github、gitee实现Typora图片上传到图床
  6. docker 不包含依赖 打包_Docker打包深度学习项目(解决:Opencv依赖库、共享内存)...
  7. mysql mha配置idrac远程关机_iDRAC远程管理功能试用_戴尔 PowerEdge R810(Xeon E7520/16GB/3*146GB)_服务器评测与技术-中关村在线...
  8. 不使用输入框如何实现下拉_如何利用Axure实现下拉子菜单?
  9. linux源码gpio模拟i2c,linux内核gpio模拟i2c实例.doc
  10. 台风路径超级计算机,厄尔尼诺又要来了?2号台风或要生成,超级计算机:路径争议大...