当前位置: 首页 > news >正文

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

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

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

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

文章目录

  • 自己实现MyBatis 底层机制[上]
    • MyBatis 整体架构分析
      • Mybatis 核心框架示意图
      • 核心框架示意图的解读
    • 搭建MyBatis 底层机制开发环境
      • 1、创建Maven 项目nlc-mybatis
      • 2、修改nlc-mybatis\pom.xml
      • 3、创建数据库和表
      • 4、到此: 项目开发环境搭建完成
    • Nlc-Mybatis 的设计思路
      • Mybatis 的底层实现设计
        • 1. 传统方式操作数据库
        • 2.MyBatis操作数据库的方式分析
    • 自己实现MyBatis 底层机制
      • 实现任务阶段1- 完成读取配置文件,得到数据库连接
        • 分析示意图
        • 代码实现
        • 完成测试
        • 测试效果
    • 实现任务阶段2- 编写执行器,输入SQL 语句,完成操作
      • 分析示意图
      • 代码实现
      • 完成测试
    • 😄总结

自己实现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(执行器), 有两个重要的实现类基本执行器和带缓存功能的执行器, 有很多方法

  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 的底层实现设计

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- 完成读取配置文件,得到数据库连接

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

分析示意图

代码实现

  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-url1. jdbc:mysql 协议2. 127.0.0.1:3306 : 指定连接mysql的ip+port3. mybatis: 连接的DB4. 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 获取到对应的InputStreamInputStream 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 和 valueif (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 {@Testpublic void build() {NlcConfiguration nlcConfiguration = new NlcConfiguration();Connection connection = nlcConfiguration.build("nlc_mybatis.xml");System.out.println("connection--" + connection);}
}

测试效果

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

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

分析示意图

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

代码实现

  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 查找结果@Overridepublic <T> T query(String sql, Object parameter) {//得到连接ConnectionConnection 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 , 增加测试方法
@Testpublic void query() {Executor executor = new NlcExecutor();Monster monster =executor.query("select * from monster where id=?", 1);System.out.println("monster-- " + monster);}
  1. 测试效果

😄总结

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

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

相关文章:

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

&#x1f600;前言 本篇博文是学习过程中的笔记和对于MyBatis底层机制的分析思路&#xff0c;希望能够给您带来帮助&#x1f60a; &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章可以帮助到…...

Django后端执行成功或失败状态码

后端执行成功或失败以状态码的形式告诉前端&#xff0c;处理成功返回200系列状态码&#xff0c;执行前端then里面的代码&#xff1b;处理失败返回400/500系列状态码&#xff0c;执行catch里面的代码。 200 OK &#xff1a;服务器成功返回用户请求的数据 201 CREATED &#xff…...

Prometheus中的关键设计

1、标准先行&#xff0c;注重生态 Prometheus 最重要的规范就是指标命名方式&#xff0c;数据格式简单易读。比如&#xff0c;对于应用层面的监控&#xff0c;可以要求必须具备这几个信息。 指标名称 metric Prometheus 内置建立的规范就是叫 metric&#xff08;即 __name__…...

Centos7 安装yum

1、检查主机名和网络并且配置/etc/hosts文件 查看主机名&#xff1a;hostname 查看ip :ifconfig vi /etc/hosts//添加把主机名和IP配置进去hosts文件192.18.56.111 orcale12c2、关闭防火墙 systemctl status firewalld.service//检查防火墙状态 暂时关闭防火墙&#xff0c;下…...

无涯教程-Lua - 简介

Lua是一种轻量语言&#xff0c;它的官方版本只包括一个精简的核心和最基本的库。这使得Lua体积小、启动速度快。它用ANSI C语言编写并以源代码形式开放&#xff0c;编译后仅仅一百余K&#xff0c;可以很方便的嵌入别的程序里。和许多“大而全”的语言不一样&#xff0c;网络通信…...

【第一阶段】kotlin语言引用数据类型

Java语言中有两种数据类型 第一种&#xff1a;基本数据类型 如int double等 第二种&#xff1a;引用数据类型。如String kotlin只有一种数据类型&#xff0c;看起来都是引用数据类型&#xff0c;实际上编译器会在Java字节码中&#xff0c;修改成基本类型 //Java语言中有两种数…...

BUU [网鼎杯 2020 朱雀组]phpweb

BUU [网鼎杯 2020 朱雀组]phpweb 众生皆懒狗。打开题目&#xff0c;只有一个报错&#xff0c;不知何从下手。 翻译一下报错&#xff0c;data()函数:,还是没有头绪&#xff0c;中国有句古话说的好“遇事不决抓个包” 抓个包果然有东西&#xff0c;仔细一看这不就分别是函数和参…...

使用WebMvcConfigurationSupport后导致原来返回的json数据变为了xml的解决方法

问题 未使用WebMvcConfigurationSupport拦截时返回的数据都是JSON格式&#xff0c;使用WebMvcConfigurationSupport做拦截后数据的返回变为了XML的格式。 原因 在Spring框架中&#xff0c;WebMvcConfigurationSupport 是一个类&#xff0c;它可以用于自定义Spring MVC的配置…...

如何判断一个枚举值是否存在(Check if an Enum Value Exists in Java)

目录 Searching an Enum by NameSearching an Enum by ValueSearching an Enum by Integer ValueExceptions Thrown from Search Methods Searching an Enum by Name public enum Direction {EAST, WEST, SOUTH, NORTH;public static Direction findByName(String name) {Dire…...

网工内推 | 网络安全工程师,最高15K,有高温补贴

01 超圣信华 招聘岗位&#xff1a;网络安全工程师 职责描述&#xff1a; 1. 负责网络安全产品的售前沟通交流、现状调研、方案设计、产品测试、产品选型和招投标等工作。 2. 负责网络安全集成项目的实施管理、项目交付文档编制以及项目验收等工作。 3. 负责网络安全产品的售后…...

Android—ADB命令

文章目录 ADB常用命令 ADB常用命令 ADB常用命令如下&#xff1a; 方法描述adb help查看ADB命令帮助adb devices查看Android设备及端口号adb connect连接Android设备adb start-server开启服务adb kill-server关闭服务adb install ***.apk安装Android应用adb install -r ***.ap…...

音视频知识:MPEG-4、H264、MP4、AAC之间的关系

MPEG-4 一种编码标准。是国际标准化组织 (ISO) 主要针对消费类应用&#xff0c;已经针对运动图像压缩定义的标准。MPEG&#xff08;Moving Picture Experts Group&#xff09;标准包括 MPEG1、MPEG2与 MPEG4。 MPEG-4标准目前分为27个部分&#xff0c;统称为ISO/IEC14496国际标…...

智能门锁的无线通讯协议有哪些?主要特点是什么?

智能门锁的无线通讯协议主要有以下几种&#xff1a; Wi-Fi&#xff1a;Wi-Fi是一种基于无线局域网的无线通信协议&#xff0c;可以快速传输数据&#xff0c;并支持互联网连接。 ZigBee&#xff1a;ZigBee是一种低功耗、低成本的无线通信协议&#xff0c;适用于大量传感器和设…...

机器学习——异常检测

异常点检测(Outlier detection)&#xff0c;⼜称为离群点检测&#xff0c;是找出与预期对象的⾏为差异较⼤的对象的⼀个检测过程。这些被检测出的对象被称为异常点或者离群点。异常点&#xff08;outlier&#xff09;是⼀个数据对象&#xff0c;它明显不同于其他的数据对象。异…...

小研究 - 一种复杂微服务系统异常行为分析与定位算法(一)

针对极端学生化偏差&#xff08;&#xff25;&#xff58;&#xff54;&#xff52;&#xff45;&#xff4d;&#xff45; &#xff33;&#xff54;&#xff55;&#xff44;&#xff45;&#xff4e;&#xff54;&#xff49;&#xff5a;&#xff45;&#xff44; &#…...

代码版本管理工具 git

1. 去B站看视频学习&#xff0c;只看前39集&#xff1a; 01-Git概述&#xff08;Git历史&#xff09;_哔哩哔哩_bilibili 2.学习Linux系统文本编辑器的使用 vi编辑器操作指令分享 (baidu.com) (13条消息) nano编辑器的使用_SudekiMing的博客-CSDN博客 windows下载安装Git官…...

【计算机视觉中的 GAN 】如何稳定GAN训练(3)

一、说明 在上一篇文章中&#xff0c;我们达到了理解未配对图像到图像翻译的地步。尽管如此&#xff0c;在实现自己的超酷深度GAN模型之前&#xff0c;您必须了解一些非常重要的概念。如本文所提的GAN模型新成员的引入&#xff1a;Wasserstein distance&#xff0c;boundary eq…...

一文讲清楚地图地理坐标系

前言 我最近在做一个和地图有关的项目&#xff0c;这里本人地图采用的是mapbox&#xff0c;其中涉及一个功能需要根据用户输入的地点直接定位到地图上的对应的位置&#xff0c;本人开始想的是直接调用百度的接口根据地名直接获取坐标&#xff0c;发现在地图上的位置有偏移不够…...

助力青少年科技创新人才培养,猿辅导投资1亿元设立新基金

近日&#xff0c;在日本千叶县举办的2023年第64届国际数学奥林匹克&#xff08;IMO&#xff09;竞赛公布比赛结果&#xff0c;中国队连续5年获得团体第一。奖牌榜显示&#xff0c;代表中国参赛的6名队员全部获得金牌。其中&#xff0c;猿辅导学员王淳稷、孙启傲分别以42分、39分…...

代码随想录算法训练营之JAVA|第十八天| 235. 二叉搜索树的最近公共祖先

今天是第 天刷leetcode&#xff0c;立个flag&#xff0c;打卡60天&#xff0c;如果做不到&#xff0c;完成一件评论区点赞最高的挑战。 算法挑战链接 235. 二叉搜索树的最近公共祖先https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-search-tree/descriptio…...

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周&#xff0c;有很多同学在写期末Java web作业时&#xff0c;运行tomcat出现乱码问题&#xff0c;经过多次解决与研究&#xff0c;我做了如下整理&#xff1a; 原因&#xff1a; IDEA本身编码与tomcat的编码与Windows编码不同导致&#xff0c;Windows 系统控制台…...

springboot 百货中心供应链管理系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;百货中心供应链管理系统被用户普遍使用&#xff0c;为方…...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 &#xff09;⽤户级环境变量与系统级环境变量 全局属性&#xff1a;环境变量具有全局属性&#xff0c;会被⼦进程继承。例如当bash启动⼦进程时&#xff0c;环 境变量会⾃动传递给⼦进程。 本地变量限制&#xff1a;本地变量只在当前进程(ba…...

Python爬虫(一):爬虫伪装

一、网站防爬机制概述 在当今互联网环境中&#xff0c;具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类&#xff1a; 身份验证机制&#xff1a;直接将未经授权的爬虫阻挡在外反爬技术体系&#xff1a;通过各种技术手段增加爬虫获取数据的难度…...

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…...

DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”

目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

C++.OpenGL (14/64)多光源(Multiple Lights)

多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...

return this;返回的是谁

一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请&#xff0c;不同级别的经理有不同的审批权限&#xff1a; // 抽象处理者&#xff1a;审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...

AGain DB和倍数增益的关系

我在设置一款索尼CMOS芯片时&#xff0c;Again增益0db变化为6DB&#xff0c;画面的变化只有2倍DN的增益&#xff0c;比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析&#xff1a; 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...

Redis:现代应用开发的高效内存数据存储利器

一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发&#xff0c;其初衷是为了满足他自己的一个项目需求&#xff0c;即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源&#xff0c;Redis凭借其简单易用、…...