1 概述在实际业务开发中通常会在单个应用中通过 分库分表 或者 读写分离的方式来提供应用的读写性能 。
在具体的开发中有很多方式:
- 通过不同的 mApper,映射到不同的 mybatis 源的方式
- 通过继承 Spring 的 AbstractRoutingDataSource 抽象类并重写 determineCurrentLookupKey 方法来管理多个数据源的方式
2 关键点
- 通过 @Aspect 注解来解析自定义注解
- 通过继承 Spring 的 AbstractRoutingDataSource 抽象类,重写 determineCurrentLookupKey 方法来管理多个数据源
- 通过 自定义注解 中的参数用来访问不同的数据源
- 由于 mybatis 的事务 和 sqlSession 的打开和关闭 也是通过 aop 来实现的,因此这里必须通过 @Order 注解来提高自定义注解的优先级
- 分库分表,根据业务来划分不同的库,比如与用户相关的表在 db_user 库,与订单相关的表在 db_order 库 。
- 读写分离,master 和 slave 模式,master 库只用来写入数据,slave 库只用来读取数据 。
4 具体的例子4.1 开发环境
- SpringBoot: 2.2.2.RELEASE
- mybatis-spring-boot-starter: 2.1.1
- HikariCP: 3.4.1
- db_user 库 的 t_user 表如下
CREATE TABLE `t_user` (`id` int(18) NOT NULL AUTO_INCREMENT COMMENT '流水号',`name` varchar(25) COLLATE utf8_bin DEFAULT NULL COMMENT '名称',`age` int(10) DEFAULT NULL COMMENT '年龄',`sex` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '性别',`remarks` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT '备注',`create_date` datetime DEFAULT NULL COMMENT '创建时间',`create_user` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT '创建人',`update_date` datetime DEFAULT NULL COMMENT '更新时间',`update_user` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT '更新人',`del_flag` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '删除标记(0:正常;1:删除)',PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='用户信息表'
- db_order 库 的 t_order 表如下
CREATE TABLE `t_order` (`id` int(18) NOT NULL AUTO_INCREMENT COMMENT '流水号',`user_id` int(18) DEFAULT NULL COMMENT '用户id',`order_date` datetime DEFAULT NULL COMMENT '订单时间',`order_amount` decimal(10,0) DEFAULT NULL COMMENT '订单金额',`remarks` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '备注',`create_date` datetime DEFAULT NULL COMMENT '创建时间',`create_user` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '创建人',`update_date` datetime DEFAULT NULL COMMENT '更新时间',`update_user` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '更新人',`del_flag` char(1) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '删除标记(0:正常;1:删除)',PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='订单表'
4.3 代码结构如下文章插图
4.4 自定义注解和 AOP 实现
- MultiDataSource
import com.ckJAVA.entity.DbEnum;import java.lang.annotation.*;/** * 数据库切换的注解,只作用在方法上 */@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface MultiDataSource {// 用于指定数据库名称的DbEnum value() default DbEnum.user;}
- 通过 aop 来读取注解的配置,并在方法前后进行数据库的切换
import com.ckjava.aop.annotation.MultiDataSource;import com.ckjava.config.MultiDataSourceHolder;import com.ckjava.entity.DbEnum;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.annotation.Pointcut;import org.aspectj.lang.reflect.MethodSignature;import org.springframework.core.annotation.Order;import org.springframework.stereotype.Component;import java.lang.reflect.Method;/** * 通过 aop 来读取注解的配置,并在方法前后进行数据库的切换 */@Aspect@Component@Order(1)public class MultiDataSourceAspect {@Pointcut("@annotation(com.ckjava.aop.annotation.MultiDataSource)")public void dataSourcePointCut() {}/*** 在方法执行前设置数据库 key** @param point*/@Before("dataSourcePointCut()")public void before(JoinPoint point) {MethodSignature signature = (MethodSignature) point.getSignature();Method method = signature.getMethod();// 在含有 MultiDataSource 注解的方法执行前,设置线程的数据库源变量MultiDataSource dataSource = method.getAnnotation(MultiDataSource.class);if (dataSource == null) {MultiDataSourceHolder.setDataSource(DbEnum.user);} else {MultiDataSourceHolder.setDataSource(dataSource.value());}}/*** 在方法执行后移除 数据库 key*/@After("dataSourcePointCut()")public void after() {// 移除线程本地数据库源变量MultiDataSourceHolder.clearDataSource();}}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Java中的“协程”
- ThinkAPI服务SDK正式发布
- 一流设计公司工作全流程
- ps制作漂浮在云层之上的绿色小岛
- 每个架构师都在研究的康威定律,程序员进阶路上,你思考过吗?
- 恒星在主星序阶段是什么 太阳目前属于赫罗图中的主序星
- 宇宙中可能存在生命的星球 宇宙中有没有其他生命存在
- 重庆最大的天坑在哪里 世界第一大天坑
- 减肥运动室内有哪些方法?
- 减肥最有效运动有什么?