mybatis源码学习——开篇

今天开始进行mybatis的源码学习

第一阶段,通过手写mybatis执行过程复习一下mybatis核心知识点

第二阶段,mybatis配置源码学习

第三阶段,mybatis核心执行流程源码学习

第四阶段,mybatis核心接口和类源码学习

第五阶段,mybatis包以及跟spring整合源码学习

先来回顾一下mybatis的使用方法吧。一个最简单的使用mybatis进行orm的程序肯定有以下几个要素

一、实体类

二、实体对应的表结构

三、mybatis配置文件

四、mybatis接口

五、mapper.xml

最简单的使用方式,在接口的方法上添加@Select注解并编写sql文件,mybatis解析该注解并进行数据库交互

在这里插入图片描述

问题来了,如果我们想自己实现这个过程,应该怎么做?

首先要明确我们的最终目的,就是和数据库建立连接,然后执行这个sql并获取返回值,所以第一步,我们要先解析这个sql。然而这是一个接口,无法直接调用,在mybatis中,是使用动态代理的方式来实现的,我们也可以来模仿一下

public static void main (String[] args) {
        EmpMapper empMapper = (EmpMapper) Proxy.newProxyInstance(MyMybatis.class.getClassLoader(), new 						Class[]{EmpMapper.class}, new InvocationHandler() {
            @Override
            public Object invoke (Object proxy, Method method, Object[] args) throws Throwable {
				return null;
            }
        });
        empMapper.selectEmpList(7369, "SMITH");
    }

如此通过代理类就可以获取接口方法和参数

在这里插入图片描述

接下来就是解析sql,将sql中的占位符替换成方法中的参数

解析方法中的参数并存入map

在这里插入图片描述

获取方法上的注解,解析sql并替换参数

在这里插入图片描述

parseSql方法将sql中的占位符换成方法参数值

如果出现解析方法参数存入的键是arg0,arg1的情况是,需要在idea的Java Compiler中添加-parameters参数

在这里插入图片描述

在这里插入图片描述

parseSqlArgs

在这里插入图片描述

到这sql语句就有了,后面就要执行数据库操作和结果集的映射处理

上面只是mybatis最基本的功能之一,我想说的是,按照这样的思路,我们完全可以自己写一个简化版的mybatis,用自己的方式实现mybatis的功能,比如现在我们实现了selec sql的解析,那能不能再实现update?delete?答案是肯定的。所以mybatis原理并不难,简单来说有下面几部分

在这里插入图片描述

逐个回顾一下,配置文件里是一些最基本的配置,比如数据库连接基本属性,连接池,environment等。配置文件里有个mappers标签,指向的是接口类或mapper.xml文件等mapper中心。在jdbc中sql都存放在Statement里,这个类属于java.sql,而在mybatis中对应的则是StatementHandler。执行sql就要用到执行器,接收则是ResultSetHandler

完整代码

package com.th;


import org.apache.ibatis.annotations.Select;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class MyMybatis {

    public static void main (String[] args) {
        EmpMapper empMapper = (EmpMapper) Proxy.newProxyInstance(MyMybatis.class.getClassLoader(), new Class[]{EmpMapper.class}, new InvocationHandler() {
            @Override
            public Object invoke (Object proxy, Method method, Object[] args) throws Throwable {

                // 通过参数来完成替换功能,因此需要先去解析参数
                Map<String, Object> stringObjectMap = parseArgs(method, args);
                // 获取方法上的注解
                Select select = method.getAnnotation(Select.class);
                if (select != null) {
                    //核心逻辑处理
                    String[] value = select.value();
                    String sql = value[0];
                    // 解析sql并替换参数
                    sql = parseSql(sql, stringObjectMap);
                    System.out.println(sql);
                }
                // 数据库操作
                // jdbc解析
                // 结果集的映射处理
                // ResultSet一个值一个值封装到对象中去
                return null;
            }
        });
        empMapper.selectEmpList(7369, "田皓");
    }

    /**
     * 解析sql
     * @param sql
     * @param map
     * @return
     */
    public static String parseSql (String sql, Map<String, Object> map) {

        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < sql.length(); i++) {
            char c = sql.charAt(i);
            if (c == '#') {
                // “#”后面的“{”下标
                int index = i + 1;
                char nextChar = sql.charAt(index);
                if (nextChar != '{') {
                    throw new RuntimeException("sql语句有错误,不是以{开头的");
                }
                StringBuilder argBuilder = new StringBuilder();
                // 截取占位符括号中的字符
                i = parseSqlArgs(argBuilder, sql, index);
                String argName = argBuilder.toString();
                Object value = map.get(argName);
                builder.append(value.toString());
                continue;
            }
            builder.append(c);
        }
        return builder.toString();
    }

    /**
     * 解析并截取sql占位符中的参数
     * @param argBuilder
     * @param sql
     * @param index
     * @return
     */
    public static int parseSqlArgs (StringBuilder argBuilder, String sql, int index) {
        index++;
        for (; index < sql.length(); index++) {
            char c = sql.charAt(index);
            if (c != '}') {
                argBuilder.append(c);
                continue;
            }
            if (c == '}') {
                return index;
            }
        }
        throw new RuntimeException("sql语句错误,没有以}结尾");
    }

    public static Map<String, Object> parseArgs (Method method, Object[] args) {
        Map<String, Object> map = new HashMap<String, Object>();
        // 获取方法的参数
        Parameter[] parameters = method.getParameters();
        int index[] = {0};
        Arrays.asList(parameters).forEach(parameter -> {
            String name = parameter.getName();
            map.put(name, args[index[0]]);
            index[0]++;
        });
        return map;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: MyBatis 是一个开源的持久层框架,可以方便地将 SQL 语句和 Java 对象进行映射。如果您想要学习 MyBatis 源码,可以按照以下步骤进行: 1. 了解 MyBatis 的架构和设计原理。可以阅读官方文档和相关书籍,例如《MyBatis 技术内幕》。 2. 下载 MyBatis 的源代码,并导入到 IDE 中。MyBatis 使用 Maven 进行构建,您可以使用 IDE 的 Maven 插件来下载依赖项。 3. 查看 MyBatis 的源代码结构。MyBatis 的主要代码在 `mybatis-3` 模块中,包括 `src/main/java` 和 `src/main/resources` 目录。其中,`src/main/java` 目录包含了 MyBatis 的核心代码,例如 `org.apache.ibatis.session.SqlSession` 类;`src/main/resources` 目录包含了 MyBatis 的配置文件和映射文件。 4. 阅读 MyBatis 的源代码。可以从 MyBatis 的入口处 `org.apache.ibatis.session.SqlSessionFactoryBuilder` 开始,深入了解 MyBatis 的初始化流程、SQL 语句的执行流程、映射文件的解析和缓存等。 5. 调试 MyBatis 的源代码。可以使用 IDE 的调试功能,对 MyBatis 进行单步调试,观察代码的执行流程,加深对 MyBatis 的理解。 6. 学习 MyBatis 的单元测试。MyBatis 的单元测试位于 `src/test/java` 目录中,可以通过单元测试来了解 MyBatis 的各个功能点的使用方法和测试用例。 7. 参与 MyBatis 的开发。如果您对 MyBatis 源码有深入的了解,并希望为 MyBatis 做出贡献,可以参与 MyBatis 的开发,贡献代码和文档,提交 issue 和 PR。MyBatis 的开发社区非常活跃,可以在官方网站和 GitHub 上找到相关信息。 希望这些步骤对您学习 MyBatis 源码有所帮助。 ### 回答2: MyBatis是一个开源的Java持久层框架,通过操作对象与数据库关系映射来提供数据持久化的功能。了解MyBatis源码学习和使用该框架的重要一步。 首先,MyBatis源码结构比较清晰,主要分为核心模块和附属模块。核心模块包括XML配置解析、SQL语句解析、参数处理、数据库连接管理等功能的实现,是实现MyBatis基本功能的核心部分。附属模块包括缓存、事务、插件等额外功能的实现,可以根据需要进行扩展和配置。 学习MyBatis源码可以从以下几个方面入手: 1. 配置文件解析:MyBatis通过XML配置文件来进行相关的配置,了解配置文件的解析过程可以帮助理解MyBatis的初始化过程和各项配置的作用。 2. SQL语句解析与执行:MyBatis将SQL语句封装成MappedStatement对象进行管理,了解MappedStatement的生成过程,以及SQL语句的解析、参数处理和执行过程,可以深入了解MyBatis的SQL执行原理。 3. 会话管理和事务处理:MyBatis采用SqlSessionFactory和SqlSession来管理数据库连接和事务,在MyBatis源码中可以学习到如何管理数据库连接池、事务的提交和回滚等核心功能的实现。 4. 缓存机制:MyBatis提供了一级缓存和二级缓存的功能,了解缓存的生成和更新过程,以及缓存的命中和失效原理,可以提高数据库查询性能。 总之,通过学习MyBatis源码,可以加深对该框架的理解,掌握其内部实现原理,有助于在使用时更加灵活和高效地进行开发。同时,也为以后解决一些特殊问题提供了更多的思路和方法。 ### 回答3: MyBatis是一个优秀的持久层框架,学习源码有助于理解其底层原理和设计思想。 首先,可以从MyBatis的入口开始学习,即SqlSessionFactoryBuilder类。该类负责解析配置文件、创建Configuration对象,并通过Configuration对象创建SqlSessionFactory实例。 接下来,可以学习Configuration类,该类负责管理整个MyBatis的配置信息。其中包括了数据库连接信息、映射文件信息、缓存信息等。在该类内部,会调用XMLMapperBuilder类解析映射文件,在解析映射文件过程中,会创建MappedStatement对象,该对象表示一条SQL语句的映射信息。 学习MappedStatement对象可以了解MyBatis的SQL语句解析过程。该对象包含了SQL语句的相关信息,包括参数映射关系、返回结果映射关系等。在执行SQL语句时,会使用ParameterHandler类处理参数,通过ResultSetHandler类处理查询结果。 同时,学习到Executor接口及其实现类,可以了解MyBatis的执行过程。Executor负责执行SQL语句,其中包括了写操作的update方法和读操作的query方法。在执行过程中,会通过StatementHandler类创建PreparedStatement对象,并通过ResultSetHandler类处理执行结果。 最后,还可以学习MyBatis的事务处理和缓存机制。Transaction接口及其实现类负责事务管理,通过JDBC的事务机制实现了事务的提交和回滚。而Cache接口及其实现类负责缓存查询结果,在查询时会先从缓存中查找结果。 总结来说,通过学习MyBatis源码可以深入理解其底层原理和设计思想。从SqlSessionFactory的创建开始,到Configuration的配置解析、MappedStatement的创建,再到Executor的执行过程和Transaction的事务管理,以及Cache的缓存机制,逐步掌握MyBatis的各个组件和它们之间的交互关系。这对于我们使用MyBatis开发项目,解决问题和优化性能都具有积极的意义。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

紫荆之后-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值