首页 数字经济

从零到一:手写 MyBatis 框架深度剖析与架构设计实战

分类:数字经济
字数: (8657)
阅读: (1043)
内容摘要:从零到一:手写 MyBatis 框架深度剖析与架构设计实战,

在之前的系列文章中,我们一步步地实现了 MyBatis 框架的核心功能。本篇文章作为该系列的第 94 篇,将对整个架构进行一次完整的回顾,并深入解析其中一些关键技术点,希望能帮助读者更好地理解 MyBatis 的设计思想和实现细节。在实际项目中,数据库连接管理通常由连接池(如 HikariCP 或 Druid)负责,并通过 Nginx 进行反向代理和负载均衡,以应对高并发访问,必要时还会使用宝塔面板简化运维操作。

MyBatis 整体架构回顾

MyBatis 的整体架构可以概括为以下几个核心模块:

从零到一:手写 MyBatis 框架深度剖析与架构设计实战
  1. 配置解析模块:负责解析 MyBatis 的配置文件(mybatis-config.xml)和 Mapper 文件,将 XML 配置转换为 Java 对象,存储到 Configuration 对象中。
  2. SqlSession 管理模块:负责创建和管理 SqlSession 对象,SqlSession 是 MyBatis 对外提供的操作数据库的接口。
  3. Executor 执行器模块:负责执行 SQL 语句,包括 StatementHandler、ParameterHandler 和 ResultSetHandler 等。
  4. StatementHandler 模块:负责将 SQL 语句转换为 JDBC Statement 对象,并设置参数。
  5. ParameterHandler 模块:负责将 Java 对象转换为 SQL 语句需要的参数。
  6. ResultSetHandler 模块:负责将 JDBC ResultSet 结果集转换为 Java 对象。
  7. TypeHandler 类型处理器模块:负责 Java 类型和 JDBC 类型之间的转换。
  8. Mapper 接口代理模块:通过动态代理机制,将 Mapper 接口的方法调用转换为 SQL 语句的执行。

核心技术深度解析

1. 配置解析模块

MyBatis 的配置解析模块使用了 XML 解析器(如 DOM4J 或 JAXB)来解析 XML 配置文件。解析后的配置信息会被存储到 Configuration 对象中,Configuration 对象包含了数据源、事务管理器、Mapper 映射等信息。例如,解析数据源配置的代码如下:

从零到一:手写 MyBatis 框架深度剖析与架构设计实战
// 解析数据源配置
private void parseDataSource(XNode context) throws Exception {
  String type = context.getStringAttribute("type");
  Properties props = context.getChildrenAsProperties();
  DataSourceFactory factory = (DataSourceFactory) resolveClass(type).getDeclaredConstructor().newInstance(); // 反射创建数据源工厂
  factory.setProperties(props);
  DataSource dataSource = factory.getDataSource();
  builderAssistant.environment(id, transactionManagerType, dataSource);
}

2. Executor 执行器模块

Executor 是 MyBatis 的核心组件之一,负责执行 SQL 语句。MyBatis 提供了多种 Executor 实现,如 SimpleExecutor、ReuseExecutor 和 BatchExecutor。SimpleExecutor 每次执行 SQL 语句都会创建一个新的 Statement 对象,ReuseExecutor 会重用 Statement 对象,BatchExecutor 会将多个 SQL 语句批量执行。选择合适的 Executor 实现可以提高 SQL 执行的效率。

从零到一:手写 MyBatis 框架深度剖析与架构设计实战
// SimpleExecutor 的 execute 查询方法
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
  Statement stmt = null;
  List<E> list;
  try {
    Configuration configuration = ms.getConfiguration();
    StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); // 创建 StatementHandler
    stmt = prepareStatement(handler, ms.getStatementLog()); // 预编译 statement
    list = handler.query(stmt, resultHandler); // 执行查询
  } finally {
    closeStatement(stmt);
  }
  return list;
}

3. Mapper 接口代理

MyBatis 使用动态代理技术,将 Mapper 接口的方法调用转换为 SQL 语句的执行。当调用 Mapper 接口的方法时,MyBatis 会创建一个代理对象,该代理对象会拦截方法调用,并根据方法名和参数信息,找到对应的 SQL 语句,并执行该 SQL 语句。例如:

从零到一:手写 MyBatis 框架深度剖析与架构设计实战
// MapperProxy 的 invoke 方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  if (Object.class.equals(method.getDeclaringClass())) {
    return method.invoke(this, args);
  }
  final MapperMethod mapperMethod = cachedMapperMethod(method);
  return mapperMethod.execute(sqlSession, args);
}

实战避坑经验总结

  1. SQL 注入风险:在使用 MyBatis 时,要避免 SQL 注入风险。可以使用 # 来占位,而不是 $# 会使用 PreparedStatement,可以有效地防止 SQL 注入。
  2. N+1 查询问题:在使用 MyBatis 的关联查询时,可能会出现 N+1 查询问题。可以使用 fetchType="lazy" 来延迟加载关联对象,或者使用 join 查询来避免 N+1 查询问题。
  3. 缓存问题:MyBatis 提供了两级缓存:一级缓存和二级缓存。一级缓存是 SqlSession 级别的缓存,二级缓存是 Mapper 级别的缓存。要合理地使用缓存,避免脏数据问题。可以通过设置 useCache="true" 开启二级缓存。
  4. 事务管理:要确保事务的正确性,需要配置合适的事务管理器。可以使用 JDBC 事务管理器或 Spring 事务管理器。

总结

通过手写 MyBatis 框架,我们可以深入理解 MyBatis 的设计思想和实现细节。掌握 MyBatis 的核心技术,可以帮助我们更好地使用 MyBatis,并解决实际项目中遇到的问题。希望本篇文章能够帮助读者更好地理解 MyBatis 框架。

从零到一:手写 MyBatis 框架深度剖析与架构设计实战

转载请注明出处: 代码一只喵

本文的链接地址: http://m.acea4.store/blog/217112.SHTML

本文最后 发布于2026-04-23 09:43:04,已经过了4天没有更新,若内容或图片 失效,请留言反馈

()
您可能对以下文章感兴趣
评论
  • 西红柿鸡蛋面 1 天前
    N+1 问题确实是个坑,之前项目里遇到过,排查了半天才发现是这个问题,后来改用 join 查询解决了。