自己实现MyBatis 底层机制--抽丝剥茧(上)

这篇具有很好参考价值的文章主要介绍了自己实现MyBatis 底层机制--抽丝剥茧(上)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

😀前言
本篇博文是学习过程中的笔记和对于MyBatis底层机制的分析思路,希望能够给您带来帮助😊

🏠个人主页:晨犀主页
🧑个人简介:大家好,我是晨犀,希望我的文章可以帮助到大家,您的满意是我的动力😉😉

💕欢迎大家:这里是CSDN,我总结知识的地方,欢迎来到我的博客,感谢大家的观看🥰
如果文章有什么需要改进的地方还请大佬不吝赐教 先在次感谢啦😊

自己实现MyBatis 底层机制[上]

MyBatis 整体架构分析

Mybatis 核心框架示意图

自己实现MyBatis 底层机制--抽丝剥茧(上),手写机制,MyBatis,mybatis,笔记

核心框架示意图的解读

  1. mybatis 的核心配置文件
    mybatis-config.xml: 进行全局配置,全局只能有一个这样的配置文件
    XxxMapper.xml 配置多个SQL,可以有多个XxxMappe.xml 配置文件
  2. 通过mybatis-config.xml 配置文件得到SqlSessionFactory
  3. 通过SqlSessionFactory 得到SqlSession,用SqlSession 就可以操作数据了
  4. SqlSession 底层是Executor(执行器), 有两个重要的实现类基本执行器和带缓存功能的执行器, 有很多方法

自己实现MyBatis 底层机制--抽丝剥茧(上),手写机制,MyBatis,mybatis,笔记

自己实现MyBatis 底层机制--抽丝剥茧(上),手写机制,MyBatis,mybatis,笔记

  1. MappedStatement 是通过XxxMapper.xml 中定义, 生成的statement 对象
  2. 参数输入执行并输出结果集, 无需手动判断参数类型和参数下标位置, 且自动将结果集映射为Java 对象

搭建MyBatis 底层机制开发环境

1、创建Maven 项目nlc-mybatis

前面快速入门有创建步骤,这里不在描述。

2、修改nlc-mybatis\pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.nlc</groupId>
    <artifactId>nlc-mybatis</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!--定义编译器 / source / target 版本即可-->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <java.version>1.8</java.version>
    </properties>
    <!--引入必要的依赖-->
    <dependencies>
        <!--引入dom4j-->
        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6.1</version>
        </dependency>
        <!--引入mysql依赖-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>
        <!--lombok-简化entity/javabean/pojo开发 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.4</version>
        </dependency>
        <!--junit依赖-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>
</project>

3、创建数据库和表

CREATE DATABASE `nlc_mybatis`;
USE `nlc_mybatis`;
CREATE TABLE `monster` (
    `id` INT NOT NULL AUTO_INCREMENT,
    `age` INT NOT NULL,
    `birthday` DATE DEFAULT NULL,
    `email` VARCHAR(255) NOT NULL,
    `gender` TINYINT NOT NULL,
    `name` VARCHAR(255) NOT NULL,
    `salary` DOUBLE NOT NULL,
    PRIMARY KEY (`id`)
) CHARSET=utf8
INSERT INTO `monster` VALUES(NULL, 200, '2000-11-11', 'nmw@sohu.com', 1,'牛魔王', 8888.88)

4、到此: 项目开发环境搭建完成

Nlc-Mybatis 的设计思路

Mybatis 的底层实现设计

自己实现MyBatis 底层机制--抽丝剥茧(上),手写机制,MyBatis,mybatis,笔记

1. 传统方式操作数据库
  1. 得到Session对象

  2. 调用Executor的方法完成操作

  3. Executor的连接是从Configuration获取的

2.MyBatis操作数据库的方式分析
  1. 得到Session
  2. 不用直接调用Executor的方法完成操作
  3. 通过MapperProxy获取Mapper对象
  4. 调用Mapper的方法,完成数据库的操作
  5. Mapper最终还是动态代理方式,使用Executor的方法完成操作
  6. MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。

自己实现MyBatis 底层机制

实现任务阶段1- 完成读取配置文件,得到数据库连接

通过配置文件,获取数据库连接。

分析示意图

自己实现MyBatis 底层机制--抽丝剥茧(上),手写机制,MyBatis,mybatis,笔记

代码实现
  1. 创建nlc-mybatis\src\main\resources\nlc_config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<database>
    <!--配置连接数据库的信息-->
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <!--配置连接mysql-url
                1. jdbc:mysql 协议
                2. 127.0.0.1:3306 : 指定连接mysql的ip+port
                3. mybatis: 连接的DB
                4. useSSL=true 表示使用安全连接
                5. &amp; 表示 & 防止解析错误
                6. useUnicode=true : 使用unicode 作用是防止编码错误
                7. characterEncoding=UTF-8 指定使用utf-8, 防止中文乱码
                8. 不要背,直接使用即可
        -->
    <property name="url" value="jdbc:mysql://localhost:3306/nlc_mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
    <property name="username" value="root"/>
    <property name="password" value="123456"/>
</database>
  1. 创建nlc-mybatis\sqlsession\NlcConfiguration.java
public class NlcConfiguration {

    //属性-类的加载器
    private static ClassLoader loader =
            ClassLoader.getSystemClassLoader();

    //读取xml文件信息,并处理
    public Connection build(String resource) {

        Connection connection = null;

        try {
            //加载配置nlc_mybatis.xml 获取到对应的InputStream
            InputStream stream =  loader.getResourceAsStream(resource);
            SAXReader reader = new SAXReader();
            Document document = reader.read(stream);
            //获取到nlc_mybatis.xml 的根元素 <database>
            Element root = document.getRootElement();
            System.out.println("root=" + root);
            //解析root元素,返回Connection 
            connection = evalDataSource(root);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return connection;
    }

    //方法会解析nlc_config.xml 信息,并返回Connection
    //eval: 评估/解析
    private Connection evalDataSource(Element node) {
        if (!"database".equals(node.getName())) {
            throw new RuntimeException("root 节点应该是<database>");
        }
        //连接DB的必要参数
        String driverClassName = null;
        String url = null;
        String username = null;
        String password = null;

        //遍历node下的子节点,获取属性值
        for (Object item : node.elements("property")) {
            Element i = (Element) item;//i 就是 对应property节点
            String name = i.attributeValue("name");
            String value = i.attributeValue("value");

            //判断是否得到name 和 value
            if (name == null || value == null) {
                throw new RuntimeException("property 节点没有设置name或者value属性");
            }
            switch (name) {
                case "url":
                    url = value;
                    break;
                case "username":
                    username = value;
                    break;
                case "driverClassName":
                    driverClassName = value;
                    break;
                case "password":
                    password = value;
                    break;
                default:
                    throw new RuntimeException("属性名没有匹配到...");
            }
        }

        Connection connection = null;

        try {
            //要求JVM查找并加载指定的类到内存中,此时将"com.mysql.jdbc.Driver" 当做参数传入,
            // 就是告诉JVM,去"com.mysql.jdbc"这个路径下找Driver类,将其加载到内存中。
            Class.forName(driverClassName);
            connection = DriverManager.getConnection(url,username,password);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return connection; //返回Connection
    }

}
完成测试
  1. 编写nlc-mybatis\src\test\java\com\nlc\test\NlcMybatisTest.java
public class NlcMyBatisTest {

    @Test
    public void build() {
        NlcConfiguration nlcConfiguration = new NlcConfiguration();
        Connection connection = nlcConfiguration.build("nlc_mybatis.xml");
        System.out.println("connection--" + connection);
    }
}
测试效果

自己实现MyBatis 底层机制--抽丝剥茧(上),手写机制,MyBatis,mybatis,笔记

实现任务阶段2- 编写执行器,输入SQL 语句,完成操作

说明:通过实现执行器机制,对数据表操作。

分析示意图

说明:我们把对数据库的操作,会封装到一套Executor 机制中,程序具有更好的扩展性,结构更加清晰.

自己实现MyBatis 底层机制--抽丝剥茧(上),手写机制,MyBatis,mybatis,笔记

自己实现MyBatis 底层机制--抽丝剥茧(上),手写机制,MyBatis,mybatis,笔记

代码实现

  1. 创建nlc-mybatis\src\main\java\com\nlc\entity\Monster.java

如果使用@Data注解需要全参构造器可以添加@AllArgsConstructor,但是无参构造器必须要显示调用,否则会被全参构造器覆盖。

/**
 * Monster 和 monster表有映射关系
 * @Getter 就会给所有属性 生成对应的getter
 * @Setter 就会给所有属性 生成对应的setter
 * @ToString 生成 toString...
 * @NoArgsConstructor 生成无参构造器
 * @AllArgsConstructor 生成要给全参构造器
 * @Data 会生成上面除全参构造器的所有注解
 * 如何选择主要还是看自己需要
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Monster {

    private Integer id;
    private Integer age;
    private String name;
    private String email;
    private Date birthday;
    private double salary;
    private Integer gender;

}
  1. 创建nlc-mybatis\src\main\java\com\nlc\nlcmybatis\sqlsession\Executor.java
public interface Executor {
    //泛型方法
    public <T> T query(String statement, Object parameter);
}
  1. 创建nlc-mybatis\src\main\java\com\nlc\nlcmybatis\sqlsession\NlcExecutor.java
public class NlcExecutor implements Executor {

    //属性
    private NlcConfiguration nlcConfiguration =
            new NlcConfiguration();

    // 根据 sql 查找结果
    @Override
    public <T> T query(String sql, Object parameter) {
        //得到连接Connection
        Connection connection = getConnection();
        //查询返回的结果集
        ResultSet set = null;
        PreparedStatement pre = null;

        try {
            pre = connection.prepareStatement(sql);
            //设置参数, 如果参数多, 可以使用数组处理.
            pre.setString(1, parameter.toString());
            set = pre.executeQuery();
            //把set数据封装到对象-monster
            //说明: 这里做了简化处理
            //认为返回的结果就是一个monster记录
            //完善的写法是一套反射机制.
            Monster monster = new Monster();

            //遍历结果集, 把数据封装到monster对象
            while (set.next()) {
                monster.setId(set.getInt("id"));
                monster.setName(set.getString("name"));
                monster.setEmail(set.getString("email"));
                monster.setAge(set.getInt("age"));
                monster.setGender(set.getInt("gender"));
                monster.setBirthday(set.getDate("birthday"));
                monster.setSalary(set.getDouble("salary"));
            }
            return (T) monster;

        } catch (Exception throwables) {
            throwables.printStackTrace();
        } finally {
            try {
                if (set != null) {
                    set.close();
                }
                if (pre != null) {
                    pre.close();
                }
                if (connection != null) {
                    connection.close();
                }
            } catch (Exception throwables) {
                throwables.printStackTrace();
            }
        }

        return null;
    }
    
     //编写方法,通过NlcConfiguration对象,返回连接
    private Connection getConnection() {
        Connection connection =   nlcConfiguration.build("nlc_mybatis.xml");
        return connection;
    }
}

完成测试

  1. 修改nlc-mybatis\src\test\java\com\nlc\test\NlcMybatisTest.java , 增加测试方法
@Test
    public void query() {
        Executor executor = new NlcExecutor();
        Monster monster =
                executor.query("select * from monster where id=?", 1);
        System.out.println("monster-- " + monster);
    }
  1. 测试效果

自己实现MyBatis 底层机制--抽丝剥茧(上),手写机制,MyBatis,mybatis,笔记

😄总结

  1. 了解底层的机制可以帮助我们更好的学习,阅读优秀的源码可以增长我们的功力。
  2. 适当的debug可以解决我们的疑惑,底层是一个非常庞大的集成,把握主干就可以了。
  3. 过于追根究底只会影响自己的心绪,会耗费大量时间精力。
  4. 如果自己感兴趣的话,可以多研究一下,会发现其中的乐趣,点到即止。

文章到这里就结束了,如果有什么疑问的地方请指出,诸大佬们一起来评论区一起讨论😁
希望能和诸大佬们一起努力,今后我们一起观看感谢您的阅读🍻
如果帮助到您不妨3连支持一下,创造不易您们的支持是我的动力🤞文章来源地址https://www.toymoban.com/news/detail-615484.html

到了这里,关于自己实现MyBatis 底层机制--抽丝剥茧(上)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 自己实现 SpringMVC 底层机制 系列之-实现任务阶段 6-完成控制器方法获取参数-@RequestParam

    😀前言 自己实现 SpringMVC 底层机制 系列之-实现任务阶段 6-完成控制器方法获取参数-@RequestParam 🏠个人主页:尘觉主页 🧑个人简介:大家好,我是尘觉,希望我的文章可以帮助到大家,您的满意是我的动力😉😉 在csdn获奖荣誉: 🏆csdn城市之星2名 ⁣⁣⁣⁣ ⁣⁣⁣⁣ ⁣⁣⁣

    2024年02月11日
    浏览(45)
  • 深入实现 MyBatis 底层机制的任务阶段4 - 开发 Mapper 接口和 Mapper.xml

    😀前言 在我们的自定义 MyBatis 底层机制实现过程中,我们已经深入研究了多个任务阶段,包括配置文件的读取、数据库连接的建立、执行器的编写,以及 SqlSession 的封装。每个任务阶段都为我们揭示了 MyBatis 内部工作原理的一部分,为构建完整的底层框架打下了坚实的基础

    2024年02月09日
    浏览(47)
  • 实现SpringMVC底层机制(三)

    1.将方法的httpservletrequest和httpservletresponse参数封装到参数数组进行反射调用 1.修改SunDispatcherServlet.java的executeDispatch方法 2.debug测试 2.封装http请求参数 1.需求分析 2.自定义注解RequestsParam 3.修改MonsterService接口,添加方法 4.修改MonsterServiceImpl.java添加方法 5.修改SunDispatcherServlet.

    2024年04月28日
    浏览(39)
  • 实现SpringMVC底层机制(二)

    1.修改SunWebApplicationContext.java 2.修改SunDispatcherServlet.java 1.需求分析 2.编写Monster.java 3.自定义Service注解 4.编写Service接口MonsterService.java 5.编写Service实现类MonsterServiceImpl.java 6.修改SunWebApplicationContext.java的executeInstance方法,增加对Service注解的扫描 7.debug测试 1.自定义Autowired注解 2

    2024年04月27日
    浏览(35)
  • 手动开发-实现SpringMVC底层机制--小试牛刀

    在这里说的底层机制的实现主要是指:前端控制器、Controller、Service注入容器、对象自动装配、控制器方法获取参数、视图解析、返回json数据。 前端控制器就是核心控制器。在这里我们可以设计一个Servlet来充当核心控制器: LingDispatcherServlet.java .这个控制器的作用主要是接收

    2024年02月08日
    浏览(51)
  • Spring系列五:手动实现Spring底层机制

    上文中, 我们学习到了 Spring系列四:AOP切面编程 接下来我们学习, 手动实现Spring底层机制 ● java的类加载器 3 种 Bootstrap类加载器---------------------对应路径jrelib Ext类加载器------------------------------对应路径jrelibext App类加载器-----------------------------对应路径classpath ●classpath 类路

    2024年02月12日
    浏览(52)
  • 【Spring】手动实现Spring底层机制-问题的引出

    🎄欢迎来到@边境矢梦°的csdn博文🎄 🎄本文主要梳理手动实现Spring底层机制-问题的引出 🎄 🌈我是边境矢梦°,一个正在为秋招和算法竞赛做准备的学生🌈 🎆喜欢的朋友可以关注一下 🫰🫰🫰 ,下次更新不迷路🎆 Ps: 月亮越亮说明知识点越重要 (重要性或者难度越大)🌑

    2024年02月09日
    浏览(46)
  • 【Redis进阶】一文搞懂Redisson的看门狗机制底层实现

    看门狗机制是Redission提供的一种自动延期机制,这个机制使得 Redission提供的分布式锁是可以自动续期的 。 看门狗机制提供的默认超时时间是30*1000毫秒,也就是30秒 如果一个线程获取锁后,运行程序到释放锁所花费的时间大于锁自动释放时间(也就是看门狗机制提供的超时时

    2024年02月16日
    浏览(56)
  • 精华推荐 |【Redis技术探索】「底层架构原理」帮你彻底搞定Sentinel的实现原理运作机制

    最美好的生活方式是和一群志同道合的人,一起奔跑在理想的路上,回头有一路的故事,低头有坚定的脚步,抬头有清晰的远方! 👮‍ Sentinel出现的前提背景 在前面Redis技术系列的章节中,我们介绍了相关Redis持久化机制和Redis主从架构的探究。两者的相辅相成实现了Redis的

    2023年04月09日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包