实现Mybatis接口模式下的数据库调用分离
目标:
多项目,多数据库,多连接池,程序级动态切换数据库调用
环境基础:
框架:SPRING+MYBATIS+MYSQL/ORACLE
设想:
Mapper分包处理不同的库
BaseDao分包处理不同的库
BaseService分包处理不同的库
实现:
多个数据源管理结构:
配置文件:
1 <!-- MyBatis begin && Alias--> 2 <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> 3 <property name="dataSource" ref="multipleDataSource"/> 4 <property name="typeAliasesPackage" value="com.thinkgem.jeesite,com.qysxy.product"/> 5 <!--com.thinkgem.jeesite.common.persistence.BaseEntity--> 6 <property name="typeAliasesSuperType" value="com.thinkgem.jeesite.common.persistence.SuperEntity"/> 7 <property name="mapperLocations" value="classpath:/mappings/**/*.xml"/> 8 <property name="configLocation" value="classpath:/mybatis-config.xml"></property> 9 </bean> 10 11 <!--多数据源管理配置--> 12 <bean id="multipleDataSource" class="com.qysxy.framework.spring.support.MultipleDataSource"> 13 <property name="defaultTargetDataSource" ref="dataSource"/> 14 <property name="targetDataSources"> 15 <map> 16 <entry key="MYSQL-PROJECT1" value-ref="dataSource"/> 17 <entry key="MYSQL-PROJECT2" value-ref="dataSource-project2"/> 18 </map> 19 </property> 20 </bean> 21 22 23 <!-- 数据源配置, 使用 BoneCP 数据库连接池 --> 24 <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> 25 <!-- 数据源驱动类可不写,Druid默认会自动根据URL识别DriverClass --> 26 <property name="driverClassName" value="${jdbc.driver}" /> 27 28 <!-- 基本属性 url、user、password --> 29 <property name="url" value="${jdbc.url}" /> 30 <property name="username" value="${jdbc.username}" /> 31 <property name="password" value="${jdbc.password}" /> 32 33 <!-- 配置初始化大小、最小、最大 --> 34 <property name="initialSize" value="${jdbc.pool.init}" /> 35 <property name="minIdle" value="${jdbc.pool.minIdle}" /> 36 <property name="maxActive" value="${jdbc.pool.maxActive}" /> 37 38 <!-- 配置获取连接等待超时的时间 --> 39 <property name="maxWait" value="60000" /> 40 41 <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --> 42 <property name="timeBetweenEvictionRunsMillis" value="60000" /> 43 44 <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 --> 45 <property name="minEvictableIdleTimeMillis" value="300000" /> 46 47 <property name="validationQuery" value="${jdbc.testSql}" /> 48 <property name="testWhileIdle" value="true" /> 49 <property name="testOnBorrow" value="false" /> 50 <property name="testOnReturn" value="false" /> 51 52 <!-- 打开PSCache,并且指定每个连接上PSCache的大小(Oracle使用) 53 <property name="poolPreparedStatements" value="true" /> 54 <property name="maxPoolPreparedStatementPerConnectionSize" value="20" /> --> 55 56 <!-- 配置监控统计拦截的filters --> 57 <property name="filters" value="stat" /> 58 </bean> 59 60 <!-- 数据源配置, 使用 BoneCP 数据库连接池,针对平台插拔系统2 --> 61 <bean id="dataSource-project2" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> 62 <!-- 数据源驱动类可不写,Druid默认会自动根据URL识别DriverClass --> 63 <property name="driverClassName" value="${jdbc.driver}" /> 64 65 <!-- 基本属性 url、user、password --> 66 <property name="url" value="${jdbc.url.project2}" /> 67 <property name="username" value="${jdbc.username}" /> 68 <property name="password" value="${jdbc.password}" /> 69 70 <!-- 配置初始化大小、最小、最大 --> 71 <property name="initialSize" value="${jdbc.pool.init}" /> 72 <property name="minIdle" value="${jdbc.pool.minIdle}" /> 73 <property name="maxActive" value="${jdbc.pool.maxActive}" /> 74 75 <!-- 配置获取连接等待超时的时间 --> 76 <property name="maxWait" value="60000" /> 77 78 <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --> 79 <property name="timeBetweenEvictionRunsMillis" value="60000" /> 80 81 <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 --> 82 <property name="minEvictableIdleTimeMillis" value="300000" /> 83 84 <property name="validationQuery" value="${jdbc.testSql}" /> 85 <property name="testWhileIdle" value="true" /> 86 <property name="testOnBorrow" value="false" /> 87 <property name="testOnReturn" value="false" /> 88 89 <!-- 打开PSCache,并且指定每个连接上PSCache的大小(Oracle使用) 90 <property name="poolPreparedStatements" value="true" /> 91 <property name="maxPoolPreparedStatementPerConnectionSize" value="20" /> --> 92 93 <!-- 配置监控统计拦截的filters --> 94 <property name="filters" value="stat" /> 95 </bean> 96 97 <!--切面注解驱动--> 98 <aop:aspectj-autoproxy proxy-target-class="false"/>
1 import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; 2 3 /** 4 * @author fuguangli 5 * @description 数据库选择路由 6 * @Create date: 2017/2/24 7 */ 8 public class MultipleDataSource extends AbstractRoutingDataSource { 9 @Override 10 protected Object determineCurrentLookupKey() { 11 return DatabaseContextHolder.getDataBaseType(); 12 } 13 }
1 public class DatabaseContextHolder { 2 public static String DATABASE_MYSQL_PROJECT1 = "MYSQL-PROJECT1";//默认 3 public static String DATABASE_MYSQL_PROJECT2 = "MYSQL-PROJECT2"; 4 5 private static final ThreadLocal<String> contextHolder = new ThreadLocal(); 6 7 public static void setDataBaseType(String context) { 8 contextHolder.set(context); 9 } 10 11 public static String getDataBaseType() { 12 if (contextHolder.get() == null) { 13 return DATABASE_MYSQL_PROJECT1; 14 } 15 16 return contextHolder.get(); 17 } 18 19 public static void clearDatabaseType() { 20 contextHolder.remove(); 21 } 22 23 }
1 @Test 2 public void changeDataSource() { 3 Long time = System.currentTimeMillis(); 4 System.out.println("start ="+time); 5 DatabaseContextHolder.setDataBaseType(DatabaseContextHolder.DATABASE_MYSQL_PROJECT2); 6 List<Object> list = testService.findBySql("select * from jee_user"); 7 System.out.println("end ="+(System.currentTimeMillis()-time));//185-126 8 }
此时,可以进行切换数据库,但是还没有做到真正的程序自动切换,此时利用spring的AOP进行分包检测,自动切换数据源。
原理:
目前,spring AOP的使用条件:
1、代理目标必须是实现类
2、代理的方法是实现的接口的方法
3、程序需要调用实现的接口方法
4、代理的类的所有上层接口不能有过代理
还有,在本次框架中需要注意的是,mybatis采用的接口调用,所以mybatis框架对DAO接口已经进行了一次java反射代理,所以,为了动态的切换数据源,需要重新写一个接口和实现类调用DAO方法,然后对此类进行代理。
此时有两种方法实现代理:
一、代理mybatis的DAO接口
基本实现就是,你需要写一个接口和实现类去封装mybatis的调用接口,很像是我们经常做的service层。
1 import com.qysxy.framework.spring.support.DatabaseContextHolder; 2 import org.aspectj.lang.JoinPoint; 3 import org.aspectj.lang.annotation.*; 4 import org.springframework.stereotype.Component; 5 6 import java.lang.annotation.Annotation; 7 8 /** 9 * @author fuguangli 10 * @description 切面通知类 11 * @Create date: 2017/2/24 12 */ 13 @Component("dataSourceAdvice ") 14 @Aspect 15 public class DataSourceAdvice{ 16 17 @Pointcut("execution(*com.thinkgem.jeesite.modules.test.service.*Service.*(..))") 18 private void pointcut(){} 19 20 // @Pointcut("@annotation(daoAOP)") 21 // private void pointcut(DaoAOP daoAOP){} 22 23 /** 24 * 在调用方法执行前执行,不能阻止方法的调用。 25 * @param joinPoint 26 */ 27 @Before("pointcut()") 28 public void doBefore(JoinPoint joinPoint) { 29 DatabaseContextHolder.setDataBaseType(DatabaseContextHolder.DATABASE_MYSQL_PROJECT2); 30 31 System.out.println("--------调用数据库之前切换设置数据源--------"); 32 } 33 }
二、自定义注解,实现切面
其实原理和上面是一样的,也是需要写一层去封装mybatis调用接口,然后做切面配置的时候,加上自定义注解。
贴上自定义注解:
1 import java.lang.annotation.*; 2 3 /** 4 * @author fuguangli 5 * @description 切面注解 6 * @Create date: 2017/2/27 7 */ 8 @Target(ElementType.METHOD) 9 @Retention(RetentionPolicy.RUNTIME) 10 @Documented 11 public @interface DaoAOP { 12 String value() default ""; 13 }
转载于:https://www.cnblogs.com/yuan951/p/6475259.html
实现Mybatis接口模式下的数据库调用分离相关推荐
- 第19章 归档模式下的数据库恢复
1. Restore(修复)将数据文件带回到过去(备份的时间点)+Recover(恢复)恢复从备份到数据文件崩溃这段时间内所有提交的数据=>数据库的完全恢复(所有提交的数据都恢复): 1)修复损 ...
- springcloud mysql库集群_SpringCloud实现分库分表模式下,数据库实时扩容方案
一.项目结构 1.工程结构 2.模块命名 shard-common-entity: 公共代码块 shard-open-inte: 开放接口管理 shard-eureka-7001: 注册中心 shar ...
- mysql命令创建模式_mysql在命令行模式下创建数据库时要显式指定字符集
关于log4j的讨论 1.LoggersLoggers组件在此系统中被分为五个级别:DEBUG.INFO.WARN.ERROR和FATAL.这五个级别是有顺序的,DEBUG < INFO < ...
- spring配置主库从库_spring下的数据库主从分离(下)
上一篇介绍了如何配置并使用动态数据源切换,这边主要梳理下源码原理和遇到的坑. 1.首先就是我们发现有事务的方法里面数据源切换是失败的,并且都是用的主数据源. 这里我们猜想是事务aop要比我们数据源ao ...
- 非归档模式下重做日志覆盖后的rman恢复
非归档模式下重做日志覆盖后的rman恢复 实验原理:在非归档模式下,数据库的重做日志不会写入归档日志中,对数据库的恢复只能依靠3个联机重做日志.当第一个重做日志满了,就切换第二个重做日志中,以此类推, ...
- 什么是DHCP(接口模式+全局模式)
目录 一.DHCP原理 DHCP作用 地址池 DHCP报文类型 DHCP工作原理 DHCP租期更新 DHCP重绑定 IP地址释放 DHCP配置实验 实验要求 实验拓扑 实验配置步骤 总结 一.DHCP ...
- DHCP的全局及接口模式配置
网络拓扑图的构建及要求 6台PC全部设置为DHCP模式 在路由器 R1 配置命令 在PC1输入ipconfig 命令查看获取的IP地址查看获取的IP地址 此时已获取到IP地址,并且可以实现基于全局模式 ...
- 命令行界面命令模式及相互切换、交换机命令行操作模式及模式间的切换过程、命令行界面基本功能、命令的快捷键功能、交换机基本配置命令、交换机特权模式下基本命令、交换机全局配置模式下基本命令、
1.命令行界面命令模式及相互切换 锐捷交换机命令行管理界面分成若干不同的模式,用户当前所处的命令模式决定了可以使用的命令,不可跨模式执行命令.以下给出三种基本模式. 用户模式(User EXE ...
- SQL Server事务日志管理的阶梯,第5级:在完全恢复模式下管理日志
SQL Server事务日志管理的阶梯,第5级:在完全恢复模式下管理日志 在本节中,我们将回顾在完全恢复模式下进行日志备份的原因和方法,以及如何使用这些日志备份文件与完整的数据库备份一起执行数据库恢复 ...
最新文章
- [k8s] 第九章 安全认证
- webpack 打包vue,组件不显示
- STM32F105的时钟配置
- .NET6之MiniAPI(十五):跨域CORS(下)
- android 高斯模糊 c,c-如何在不使用任何内置高斯函数的情况下对图像进行高斯模糊处理?...
- TreeMap实现对中文的排序
- SQL Server 2017 新功能分享
- ORA-01157 无法标识锁定数据文件的解决方法
- 【个人笔记】OpenCV4 C++ 快速入门 10课
- swing中解决中文乱码问题
- 微软改进的DSSM结构:
- 复数基2 DIT FFT程序
- Nachos Lab2 虚拟内存
- 三菱fx2n-2ad编程实例_三菱PLC编程实例,PLC控制自动成型机
- 学c语言前要了解什么软件,学习c语言需要什么软件?
- 关于icon小图标的实现
- 盒式滤波器BoxFilter
- vue引入 wps在线编辑版,可进行 预览,编辑, 打印等功能。
- 四个步骤写一份策划方案(下)
- Selenium Chrome版本兼容问题
热门文章
- 再让大家清爽一下,给加班的oscer们,哈
- 无需安装配置,多操作系统支持数据库及性能测试
- 无人驾驶插秧机智能辅助系统_无人驾驶插秧机搭载北斗导航驾驶系统,误差仅在2.5厘米内...
- Ceres-Solver库入门
- 使用GDAL对HDF数据进行校正
- 开源GIS(十九)——WKT、WKB与GeoJSON
- matlab求解集合覆盖问题,Set Cover Problem (集合覆盖问题)
- payload的使 常用xss_跨站脚本XSS Payloads生成器
- python时间段_python--时间段遍历
- windows制作docker镜像_.NET Core程序跑在任何有docker的地方