分库分表学习
https://articles.zsxq.com/id_xq8o4sj295df.html
AOP核心概念
可参考 JavaGuide的博客 ,具体的不在这里介绍了。
分库分表哪里体现了AOP?
数据库分库分表组件在这篇文章中已经介绍得很详细了,我们要学习的是这个组件中哪里体现出来了AOP,以及说当我们进行分库分表查询的时候,源码的调用逻辑是怎么样的。
我们要思考,在这个分库分表组件中,AOP的关键核心,在哪里体现出来了?
横切关注点(cross-cutting concerns)
横切关注点指的是多个类或对象中的公共行为(如日志记录、事务管理、权限控制、接口限流、接口幂等等)。
数据库路由逻辑是这个组件的横切关注点,包括:
- 从方法参数中解析路由字段(
getAttrValue
)。 - 根据路由字段计算目标库和表的索引(
dbRouterStrategy.doRouter
)。 - 在 SQL 执行时动态修改表名(MyBatis 拦截器)。
- 清理
ThreadLocal
中的路由信息(dbRouterStrategy.clear
)。
切面(Aspect)
切面是对横切关注点进行封装的类,一个切面是一个类。切面可以定义多个通知,用来实现具体的功能。
逻辑分为两部分:
- 方法级别的路由逻辑:
- 使用
@Around
注解的doRouter
方法,将路由逻辑应用到带有@DBRouter
注解的方法。 - 实现动态路由的核心逻辑。
- 使用
- SQL 级别的表名替换
- MyBatis 拦截器中的
intercept
方法,用于拦截并修改 SQL,完成分表逻辑。
- MyBatis 拦截器中的
切面贯穿了方法调用和 SQL 执行两个层面。
连接点(JoinPoint)
连接点是方法调用或者方法执行时的某个特定时刻(如方法调用、异常抛出等)。
- 方法调用:
- 带有
@DBRouter
注解的方法是连接点,例如service.insertUser()
方法。
- 带有
- SQL 执行:
- MyBatis 拦截器中的
BoundSql
是另一个连接点,表示每次执行的 SQL 语句。
- MyBatis 拦截器中的
连接点提供了拦截点,切面通过切点筛选具体的连接点。
通知(Advice):
通知就是切面在某个连接点要执行的操作。通知有五种类型,分别是前置通知(Before)、后置通知(After)、返回通知(AfterReturning)、异常通知(AfterThrowing)和环绕通知(Around)。前四种通知都是在目标方法的前后执行,而环绕通知可以控制目标方法的执行过程。
在组件中的体现:
- 方法级通知:
- 在
doRouter
方法中:- 前置逻辑:解析路由字段,计算库表索引(
dbRouterStrategy.doRouter
)。 - 环绕逻辑:通过
jp.proceed()
执行业务方法。 - 后置逻辑:清理路由信息(
dbRouterStrategy.clear
)。
- 前置逻辑:解析路由字段,计算库表索引(
- 在
- SQL 级通知:
- 在 MyBatis 拦截器中的
intercept
方法:- 前置逻辑:提取 SQL 表名。
- 环绕逻辑:通过动态修改
BoundSql
替换表名。 - 后置逻辑:恢复原始状态(如果有需要)。
- 在 MyBatis 拦截器中的
切点(Pointcut):
一个切点是一个表达式,它用来匹配哪些连接点需要被切面所增强。切点可以通过注解、正则表达式、逻辑运算等方式来定义。比如 execution(* com.xyz.service..*(..))
匹配 com.xyz.service
包及其子包下的类或接口。
在组件中的体现:
切点通过以下方式定义:
方法级切点:
1
"aopPoint() && @annotation(dbRouter)") (
aopPoint()
是一个通用的切点定义(可能是包或类范围)。@annotation(dbRouter)
限定只拦截带有@DBRouter
注解的方法。
SQL 级切点:
- MyBatis 插件拦截了
StatementHandler
接口的prepare
方法,用于动态修改 SQL。
- MyBatis 插件拦截了
切点将通知与具体的连接点绑定,决定哪些方法或 SQL 会被拦截。
织入(Weaving):
织入是将切面和目标对象连接起来的过程,也就是将通知应用到切点匹配的连接点上。常见的织入时机有两种,分别是编译期织入(Compile-Time Weaving 如:AspectJ)和运行期织入(Runtime Weaving 如:AspectJ、Spring AOP)。
在组件中的体现:
- 方法级织入:
- Spring AOP 在运行时使用动态代理,将
doRouter
的切面逻辑织入到带有@DBRouter
注解的方法中。 - 例如,当调用
service.insertUser()
时,Spring AOP 代理会触发doRouter
方法。
- Spring AOP 在运行时使用动态代理,将
- SQL 级织入:
- MyBatis 拦截器在运行时动态修改 SQL 执行流程,通过反射直接修改 SQL 表名。
- 每次执行 SQL 时,
intercept
方法会被调用,动态替换表名。
织入过程确保切面逻辑能够在正确的连接点上执行。
面试题
简单技术问题:
什么是 AOP?在 DB-Router 中如何应用 AOP?
AbstractRoutingDatasource 是什么?它的作用是什么?
ThreadLocal是什么?在 DB-Router 中是如何使用的?
什么是哈希散列?在 DB-Router 中为什么选择了哈希散列算法?
SAC 测试是什么?在 DB-Router 中如何应用 SAC测试?
中等技术问题:
什么是 MyBatis Plugin? 在 DB-Router 中如何应用 MyBatis Plugin 实现动态变更表信息?
2.分库分表的散列算法有哪些,各自的优缺点是什么?在 DB-Router 中如何支持个性化的分库分表控制?请结合具体实例说明。
在 DB-Router 中如何实现扩展监控、扫描、策略等规则?
什么是雪崩测试?在 DB-Router 中如何进行雪崩测试?
难度技术问题:
在 DB-Router 的架构模型中,如何实现扩展性和灵活性的平衡?
在 DB-Router 中如何保证数据路由的高效性和准确性?
在 DB-Router 中,如何避免分库分表后产生的性能问题?
在 DB-Router 中如何应对高并发的场景?请结合具体实例说明。
在 DB-Router 的设计过程中,遇到了哪些技术难点?是如何解决的?
可合