找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2064

积分

0

好友

276

主题
发表于 17 小时前 | 查看: 5| 回复: 0

本篇源码:https://gitee.com/YanX2000/yan-batis/tree/master/yanbatis-04

上一篇

概述

YanBatis-04 在 YanBatis-03 的基础上,新增了数据源管理、JDBC事务处理和真正的数据库操作功能,实现了从模拟SQL执行到实际数据库查询的重要跨越。这对于深入理解 MyBatis 这类ORM框架的内部工作原理是一个关键的里程碑。

新增功能对比 (相对于 YanBatis-03)

核心架构变化对比

组件 YanBatis-03 YanBatis-04 变化说明
SQL执行 模拟返回字符串 真实数据库查询 从模拟执行转向实际JDBC操作
数据源管理 无数据源概念 Environment+DataSource 新增数据源配置和管理
事务处理 无事务管理 JdbcTransaction 支持JDBC事务管理
结果处理 返回硬编码字符串 ResultSet到对象映射 支持查询结果自动映射
配置解析 简单XML解析 环境配置解析 支持environments配置解析

1. 数据源和环境配置管理

YanBatis-03 的配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<mappers>
<mapper resource="mapper/User_Mapper.xml"/>
</mappers>
</configuration>

YanBatis-04 的完整配置:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="DRUID">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/yanbatis?useUnicode=true&useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456."/>
</dataSource>
</environment>
</environments>

<mappers>
<mapper resource="mapper/User_Mapper.xml"/>
</mappers>
</configuration>

新增核心类:

  • Environment: 环境配置类,封装环境ID、事务工厂和数据源
  • DataSourceFactory: 数据源工厂接口,支持不同类型数据源
  • DruidDataSourceFactory: Druid数据源工厂实现
  • TransactionFactory: 事务工厂接口
  • JdbcTransactionFactory: JDBC事务工厂实现
  • JdbcTransaction: JDBC事务实现类

2. SQL执行方式变革

YanBatis-03 的模拟执行:

@Override
public <T> T selectOne(String statement, Object parameter){
    MappedStatement mappedStatement = configuration.getMappedStatement(statement);
return (T) ("你被代理了!\n方法:" + statement + "\n入参:" + parameter + "\n待执行SQL:" + mappedStatement.getSql());
}

YanBatis-04 的真实数据库操作:

@Override
public <T> T selectOne(String statement, Object parameter){
try {
        MappedStatement mappedStatement = configuration.getMappedStatement(statement);
        Environment environment = configuration.getEnvironment();

        Connection connection = environment.getDataSource().getConnection();

        BoundSql boundSql = mappedStatement.getBoundSql();
        PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSql());
        preparedStatement.setLong(1, Long.parseLong(((Object[]) parameter)[0].toString()));
        ResultSet resultSet = preparedStatement.executeQuery();

        List<T> objList = resultSet2Obj(resultSet, Class.forName(boundSql.getResultType()));
return objList.getFirst();
    } catch (Exception e) {
        log.debug("selectOne error", e);
returnnull;
    }
}

关键改进:

  • 真实JDBC操作: 使用PreparedStatement执行SQL
  • 参数绑定: 支持参数绑定到PreparedStatement
  • ResultSet处理: 将查询结果自动映射为Java对象
  • 异常处理: 完善的异常处理机制

3. 结果集映射功能

新增ResultSet到对象映射方法:

private <T> List<T> resultSet2Obj(ResultSet resultSet, Class<?> clazz){
    List<T> list = new ArrayList<>();
try {
        ResultSetMetaData metaData = resultSet.getMetaData();
int columnCount = metaData.getColumnCount();
// 每次遍历行值
while (resultSet.next()) {
            T obj = (T) clazz.newInstance();
for (int i = 1; i <= columnCount; i++) {
                Object value = resultSet.getObject(i);
                String columnName = metaData.getColumnName(i);
                String setMethod = "set" + columnName.substring(0, 1).toUpperCase() + columnName.substring(1);
                Method method;
if (value instanceof Timestamp) {
                    method = clazz.getMethod(setMethod, Date.class);
                } else {
                    method = clazz.getMethod(setMethod, value.getClass());
                }
                method.invoke(obj, value);
            }
            list.add(obj);
        }
    } catch (Exception e) {
        log.error("resultSet2Obj error", e);
    }
return list;
}

功能特点:

  • 自动映射: 根据列名自动调用对应的setter方法
  • 类型处理: 支持不同数据类型的自动转换
  • 反射调用: 使用反射动态创建对象并设置属性值
  • 特殊类型处理: 对Timestamp等特殊类型进行适配

4. 配置解析增强

YanBatis-03 的XMLConfigBuilder:

public Configuration parse(){
try {
// 解析映射器
        mapperElement(root.element("mappers"));
    } catch (Exception e) {
thrownew RuntimeException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
return configuration;
}

YanBatis-04 的增强解析:

public Configuration parse(){
try {
// 环境
        log.debug("step 2 解析mybatis-config.xml");
        log.debug("step 2.1 解析环境");
        environmentsElement(root.element("environments"));
// 解析映射器
        log.debug("step 2.2 解析映射器");
        mapperElement(root.element("mappers"));
    } catch (Exception e) {
thrownew RuntimeException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
return configuration;
}

新增environmentsElement方法:

private void environmentsElement(Element context)throws Exception {
    String environment = context.attributeValue("default");
    List<Element> environmentList = context.elements("environment");
for (Element e : environmentList) {
        String id = e.attributeValue("id");
if (environment.equals(id)) {
// 事务管理器
            TransactionFactory txFactory = (TransactionFactory) typeAliasRegistry.resolveAlias(e.element("transactionManager").attributeValue("type")).newInstance();

// 数据源
            Element dataSourceElement = e.element("dataSource");
            DataSourceFactory dataSourceFactory = (DataSourceFactory) typeAliasRegistry.resolveAlias(dataSourceElement.attributeValue("type")).newInstance();
            List<Element> propertyList = dataSourceElement.elements("property");
            Properties props = new Properties();
for (Element property : propertyList) {
                props.setProperty(property.attributeValue("name"), property.attributeValue("value"));
            }
            dataSourceFactory.setProperties(props);
            DataSource dataSource = dataSourceFactory.getDataSource();

// 构建环境
            Environment environmentBuilder = Environment.builder()
                    .id(id)
                    .dataSource(dataSource)
                    .transactionFactory(txFactory)
                    .build();
            configuration.setEnvironment(environmentBuilder);
        }
    }
}

5. 类型别名注册机制

Configuration构造器中注册别名:

public Configuration(){
    typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
    typeAliasRegistry.registerAlias("DRUID", DruidDataSourceFactory.class);
}

TypeAliasRegistry功能:

  • 支持类型别名到具体类的映射
  • 简化XML配置中的类名书写
  • 提供类型解析和实例化功能

test_SqlSessionFactory() 执行流程分析

整体执行时序图

ApiTest → SqlSessionFactoryBuilder → XMLConfigBuilder → Configuration → Environment → SqlSessionFactory → SqlSession → Mapper代理 → 真实数据库查询

详细执行步骤分析

第1步: 读取配置文件

Reader reader = Resources.getResourceAsReader("mybatis-config-datasource.xml");

日志输出:

step 1: 获取MyBatis配置文件
  • 使用Resources工具类从classpath读取XML配置文件

第2步: 构建SqlSessionFactory

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);

2.1 创建XMLConfigBuilder并解析配置

step 2 解析mybatis-config.xml
step 2.1 解析环境

2.2 解析环境配置(environments)

  • 解析 <environments default="development"> 元素
  • 根据default属性选择对应的environment
  • 解析transactionManager: type="JDBC"JdbcTransactionFactory
  • 解析dataSource: type="DRUID"DruidDataSourceFactory
  • 设置数据源属性: driver、url、username、password
  • 创建Environment对象并设置到Configuration

2.3 解析映射器配置(mappers)

step 2.2 解析映射器
step 1: 获取MyBatis配置文件
step 2.2.1 解析 SQL :
        SELECT id, userId, userName, userHead
        FROM user
        where id = ?
    ,参数:{1:"id"}
step 2.2.2 获取 SQL 类型:SELECT
step 2.2.3 添加解析 SQL
step 2.2.4 注册Mapper映射器:com.yanx.yanbatis.test.dao.IUserDao
step 2.2.5 注册映射器代理工厂:interface com.yanx.yanbatis.test.dao.IUserDao
====================注册完成=============================
  • 解析User_Mapper.xml文件
  • 提取namespace: com.yanx.yanbatis.test.dao.IUserDao
  • 解析select元素,获取id、parameterType、resultType、SQL语句
  • 使用正则表达式将 #{id} 转换为 ?,并记录参数映射
  • 创建BoundSql对象封装SQL和参数信息
  • 创建MappedStatement并添加到Configuration
  • 注册Mapper接口到MapperRegistry

第3步: 打开SqlSession

SqlSession sqlSession = sqlSessionFactory.openSession();
  • DefaultSqlSessionFactory创建DefaultSqlSession实例
  • SqlSession持有Configuration引用

第4步: 获取Mapper代理对象

IUserDao userDao = sqlSession.getMapper(IUserDao.class);
step 3 执行SQL
step 3.1 获取映射器代理工厂:interface com.yanx.yanbatis.test.dao.IUserDao
step 3.2 从工厂创建映射器代理对象:interface com.yanx.yanbatis.test.dao.IUserDao
  • 通过MapperRegistry获取MapperProxyFactory
  • 创建MapperProxy动态代理对象

第5步: 执行数据库查询

User user = userDao.queryUserInfoById(1L);
step 3.3 代理对象执行SQL语句:queryUserInfoById
{dataSource-1} inited
step 3.4 处理结果集

5.1 代理拦截与方法路由

  • MapperProxy拦截方法调用
  • 通过MapperMethod执行SQL命令
  • 调用SqlSession.selectOne()方法

5.2 数据库连接与SQL执行

  • 从Environment获取DataSource
  • Druid连接池初始化: {dataSource-1} inited
  • 获取数据库Connection
  • 创建PreparedStatement并设置参数
  • 执行SQL查询获取ResultSet

Java数据源解析与数据库操作流程图

5.3 结果集处理

  • 调用resultSet2Obj()方法处理结果集
  • 使用反射根据列名调用setter方法
  • 将数据库记录映射为User对象

5.4 最终输出结果

测试结果:{"id":1,"userHead":"1_04","userId":"10001","userName":"yanx"}

执行流程关键节点总结

  1. 配置解析阶段: XMLConfigBuilder解析XML配置文件,新增Environment和DataSource配置
  2. 环境构建阶段: 创建事务工厂、数据源工厂,构建运行环境
  3. 映射器注册阶段: 解析Mapper XML,注册SQL映射和接口代理
  4. 代理创建阶段: 通过MapperRegistry创建动态代理对象
  5. SQL执行阶段: 真实的JDBC操作,包括连接获取、参数设置、SQL执行
  6. 结果映射阶段: ResultSet自动映射为Java对象

数据流转图

┌─────────────────┐    ┌──────────────────┐    ┌─────────────────┐
│mybatis-config   │───▶│XMLConfigBuilder  │───▶│  Configuration  │
│-datasource.xml  │    │                  │    │                 │
└─────────────────┘    └──────────────────┘    └─────────────────┘
                         │                         │
                         ▼                         ▼
              ┌──────────────────┐    ┌─────────────────┐
              │    Environment   │    │  MapperRegistry │
              │  +DataSource     │    │  +MappedStatement│
              │  +TxFactory      │    │                 │
              └──────────────────┘    └─────────────────┘
                         │                         │
                         ▼                         ▼
┌─────────────────┐    ┌──────────────────┐    ┌─────────────────┐
│   SqlSession    │───▶│   MapperProxy    │───▶│   真实数据库     │
│                 │    │                  │    │                 │
└─────────────────┘    └──────────────────┘    └─────────────────┘
         │                         │                         │
         ▼                         ▼                         ▼
┌─────────────────┐    ┌──────────────────┐    ┌─────────────────┐
│Connection       │    │PreparedStatement │    │   ResultSet     │
│(Druid Pool)     │    │                  │    │                 │
└─────────────────┘    └──────────────────┘    └─────────────────┘
                                                             │
                                                             ▼
                                                ┌─────────────────┐
                                                │   User Object   │
                                                │  (反射映射)      │
                                                └─────────────────┘

技术架构改进

1. 数据源管理

  • 工厂模式: DataSourceFactory支持多种数据源类型
  • 连接池技术: 集成Druid连接池,提升性能和资源管理
  • 配置化管理: 通过XML配置数据源参数

2. 事务处理

  • 事务抽象: Transaction接口定义事务行为
  • JDBC事务: JdbcTransaction实现基于JDBC的事务管理
  • 工厂创建: TransactionFactory负责创建事务实例

3. 环境配置

  • Environment封装: 统一管理环境ID、数据源、事务工厂
  • 多环境支持: 支持配置多个环境,通过default属性选择
  • Builder模式: 使用Builder模式构建Environment对象

4. SQL执行引擎

  • 真实JDBC: 从模拟执行转向真实数据库操作
  • PreparedStatement: 使用预编译语句,支持参数绑定
  • 结果映射: 自动将ResultSet映射为Java对象

5. 类型系统

  • TypeAliasRegistry: 类型别名注册机制
  • BoundSql: 绑定SQL封装,包含SQL语句和参数映射
  • 反射映射: 使用反射实现数据库字段到对象属性的自动映射

关键改进对比

相比yanbatis-03,主要改进包括:

  1. 真实数据库操作: 从模拟SQL执行转向实际JDBC操作
  2. 数据源管理: 引入数据源工厂和连接池技术
  3. 事务处理: 新增完整的事务管理机制
  4. 环境配置: 支持多环境配置和数据源配置
  5. 结果映射: 实现ResultSet到Java对象的自动映射
  6. 类型管理: 引入类型别名系统简化配置
  7. 异常处理: 完善的异常处理和日志记录

这一版本实现了从配置驱动的代理模式到真正可用的ORM框架的重要跨越,具备了MyBatis的核心数据访问能力。掌握这些核心组件的实现,对于构建自己的数据访问层或深入排查生产问题都大有裨益。欢迎在 云栈社区 分享你的实践心得。




上一篇:AI大模型工具全景指南:8大核心领域44类实用工具盘点
下一篇:深入剖析嵌入式Linux高并发Socket通信:从硬件瓶颈到量产调试
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-3-6 22:28 , Processed in 0.422214 second(s), 43 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表