一、MyBatis架构设计精髓
1. 核心组件运行机制
java
// 构建SqlSessionFactory(配置加载与元数据解析)
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// SqlSession生命周期管理(对比连接池与线程安全)
try (SqlSession session = sqlSessionFactory.openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.selectUserById(1L); // 触发代理对象执行
}
核心流程解析:
- 配置加载阶段:XML解析 → Environment构建 → TypeHandler注册
- Mapper绑定过程:动态代理生成Mapper接口实现类(JDK Proxy或CGLIB)
- SQL执行链路:StatementHandler → ParameterHandler → ResultSetHandler
二、动态SQL引擎深度剖析
2.1 OGNL表达式解析原理
xml
运行 HTML
执行过程拆解:
- XML解析阶段:将动态标签转换为SqlNode树形结构
- 参数绑定阶段:OGNL引擎解析test表达式(对比${}与#{}的安全差异)
- SQL拼接阶段:根据条件动态生成BoundSql对象
2.2 动态SQL性能优化策略
- 重用预编译语句:通过
标签复用公共片段 - 避免嵌套过深:超过3层的动态条件建议拆分为多个方法
- 批处理优化:使用
配合BATCH执行器提升批量插入效率
三、缓存体系与事务管理
3.1 二级缓存陷阱与解决方案
xml
运行 HTML
缓存穿透场景:
- 多表关联更新导致脏数据(通过
建立命名空间依赖) - 分布式环境缓存同步问题(整合Redis实现集中式缓存)
3.2 事务控制最佳实践
java
// 手动控制事务边界
try (SqlSession session = sqlSessionFactory.openSession()) {
try {
userMapper.insert(user);
logMapper.addLog(user.getId());
session.commit(); // 两阶段提交
} catch (Exception e) {
session.rollback(); // 异常回滚
}
}
四、插件开发与扩展实战
4.1 自定义分页插件开发
java
@Intercepts({
@Signature(type = Executor.class, method = "query",
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
public class PaginationInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 拦截SQL执行,自动追加LIMIT语句
Object[] args = invocation.getArgs();
RowBounds rowBounds = (RowBounds) args[2];
if (rowBounds != RowBounds.DEFAULT) {
MappedStatement ms = (MappedStatement) args[0];
BoundSql boundSql = ms.getBoundSql(args[1]);
String sql = boundSql.getSql() + " LIMIT " + rowBounds.getOffset() + "," + rowBounds.getLimit();
// 修改原始SQL并执行...
}
return invocation.proceed();
}
}
插件链执行顺序:
Executor → ParameterHandler → ResultSetHandler → StatementHandler
4.2 慢SQL监控插件实现
java
// 记录超过阈值的SQL执行时间
@Override
public Object intercept(Invocation invocation) throws Throwable {
long start = System.currentTimeMillis();
Object result = invocation.proceed();
long time = System.currentTimeMillis() - start;
if (time > 1000) {
log.warn("Slow SQL detected: {}ms - {}", time, getSql(invocation));
}
return result;
}
五、SpringBoot整合进阶Demo
5.1 多数据源动态路由
yaml
# application.yml
mybatis:
mapper-locations: classpath:mapper/*.xml
configuration:
map-underscore-to-camel-case: true
datasource:
primary:
url: jdbc:mysql://localhost:3306/db1
secondary:
url: jdbc:mysql://localhost:3306/db2
java
// 动态数据源切换
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDataSourceType();
}
}
// AOP切面实现数据源路由
@Around("@annotation(targetDataSource)")
public Object switchDataSource(ProceedingJoinPoint joinPoint, TargetDataSource targetDataSource) throws Throwable {
DataSourceContextHolder.setDataSource(targetDataSource.value());
try {
return joinPoint.proceed();
} finally {
DataSourceContextHolder.clear();
}
}
5.2 MyBatis-Plus增强实践
java
// 快速实现条件构造
LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.like(User::getName, "John")
.between(User::getAge, 20, 30)
.orderByDesc(User::getCreateTime);
List users = userMapper.selectList(queryWrapper);
// 逻辑删除自动处理
@TableLogic(value = "0", delval = "1")
private Integer deleted;
六、性能调优 Checklist
- 连接池配置
properties
# 合理设置Druid参数
spring.datasource.druid.initial-size=5
spring.datasource.druid.max-active=20
spring.datasource.druid.min-idle=5
- 批量操作优化
java
// 使用BatchExecutor提升批量插入性能
SqlSession batchSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
UserMapper batchMapper = batchSession.getMapper(UserMapper.class);
for (User user : userList) {
batchMapper.insert(user);
}
batchSession.commit();
- 结果集处理优化
- 使用ResultHandler流式处理大数据量
- 避免N+1查询(开启懒加载需谨慎)
通过本文深度解析,开发者不仅能掌握MyBatis的核心工作机制,更能针对复杂业务场景进行定制化扩展,构建高性能数据访问层。