MyBatis核心机制

实现MyBatis核心机制环境搭建

1.核心框架示意图

img

2.模块搭建

1.创建maven项目

CleanShot 2024-08-08 at 15.29.52@2x

2.引入依赖
<?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><parent><groupId>com.sunxiansheng</groupId><artifactId>core_mechanisms</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>sun-mybatis</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!-- 解析xml --><dependency><groupId>dom4j</groupId><artifactId>dom4j</artifactId><version>1.6.1</version></dependency><!-- mysql --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.22</version></dependency><!-- lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.30</version></dependency><!-- junit --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version></dependency></dependencies></project>
3.连接数据库
4.数据库表设计
CREATE DATABASE `sun_mybatis`;
USE `sun_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` (`age`, `birthday`, `email`, `gender`, `name`, `salary`)
VALUES (25, '1998-01-15', 'example@example.com', 1, 'John Doe', 50000.00);

3.设计图

img

读取配置文件,得到数据库连接

1.目录

CleanShot 2024-08-08 at 16.57.51@2x

2.sun-config.xml 配置文件

<?xml version="1.0" encoding="utf-8" ?>
<!-- 配置数据库连接信息 -->
<database><!-- 驱动 --><property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/><!-- 连接地址 --><property name="url" value="jdbc:mysql://bj--grp-.sql.tencentcdb.com:24169/sun_mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>    <!-- 用户名 --><!-- 用户名 --><property name="username" value=""/><!-- 密码 --><property name="password" value=""/>
</database>

3.SunConfiguration.java 读取配置文件获取数据库连接

package com.sunxiansheng.mybatis.sqlsession;import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.List;/*** Description: 读取xml配置文件** @Author sun* @Create 2024/8/8 16:25* @Version 1.0*/
public class SunConfiguration {private static final Logger log = LoggerFactory.getLogger(SunConfiguration.class);private static ClassLoader loader = ClassLoader.getSystemClassLoader();/*** 读取xml文件** @param resource 这个必须是类路径下的文件路径,不用带第一个斜杠,sun-config.xml就可以* @return*/public Connection build(String resource) {InputStream resourceAsStream = loader.getResourceAsStream(resource);// 使用dom4j解析配置文件SAXReader saxReader = new SAXReader();try {// 获取文档Document document = saxReader.read(resourceAsStream);// 根元素Element rootElement = document.getRootElement();// 根元素下的所有property元素List<Element> property = rootElement.elements("property");// 初始化连接信息String driverClassName = null;String url = null;String username = null;String password = null;// 遍历property元素获取连接信息for (Element element : property) {String name = element.attributeValue("name");String value = element.attributeValue("value");switch (name) {case "driverClassName":driverClassName = value;log.info("加载驱动类:{}", value);break;case "url":url = value;log.info("加载url:{}", value);break;case "username":username = value;log.info("加载用户名:{}", value);break;case "password":password = value;log.info("加载密码:{}", value);break;default:throw new RuntimeException("未知的property属性名");}}// 类加载驱动类Class.forName(driverClassName);return DriverManager.getConnection(url, username, password);} catch (DocumentException | ClassNotFoundException | SQLException e) {log.error("解析xml配置文件失败", e);throw new RuntimeException(e);}}}

4.SunConfigurationTest.java 测试

package com.sunxiansheng.mybatis.sqlsession;import org.junit.Test;import java.sql.Connection;/*** Description: 读取xml配置文件** @Author sun* @Create 2024/8/8 16:25* @Version 1.0*/
public class SunConfigurationTest {@Testpublic void build() {SunConfiguration sunConfiguration = new SunConfiguration();Connection build = sunConfiguration.build("sun-config.xml");System.out.println("build = " + build);}}

使用SunExecutor来执行SQL

1.目录

CleanShot 2024-08-09 at 13.02.47@2x

2.Monster.java

package com.sunxiansheng.mybatis.entity;import lombok.Data;import java.io.Serializable;
import java.util.Date;@Data
public class Monster implements Serializable {private Integer id;private Integer age;private Date birthday;private String email;private Byte gender;private String name;private Double salary;private static final long serialVersionUID = 1L;
}

3.Executor.java

package com.sunxiansheng.mybatis.sqlsession;/*** Description: 执行器接口** @Author sun* @Create 2024/8/9 12:37* @Version 1.0*/
public interface Executor {public <T> T query(String sql, Object parameter);}

4.SunExecutor.java 具体的执行器

package com.sunxiansheng.mybatis.sqlsession;import com.sunxiansheng.mybatis.entity.Monster;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;/*** Description: 执行器** @Author sun* @Create 2024/8/9 12:39* @Version 1.0*/
public class SunExecutor implements Executor{public static final SunConfiguration configuration = new SunConfiguration();private static final Logger log = LoggerFactory.getLogger(SunExecutor.class);@Overridepublic <T> T query(String sql, Object parameter) {// 获取DB连接Connection connection = configuration.build("sun-config.xml");log.info("获取连接:{}", connection);ResultSet resultSet = null;PreparedStatement preparedStatement = null;// 实体类Monster monster = new Monster();try {// sql预处理preparedStatement = connection.prepareStatement(sql);// 填参数preparedStatement.setString(1, parameter.toString());// 执行查询resultSet = preparedStatement.executeQuery();// 将结果封装到实体类中(写死了)while (resultSet.next()) {monster.setId(resultSet.getInt("id"));monster.setAge(resultSet.getInt("age"));monster.setBirthday(resultSet.getDate("birthday"));monster.setEmail(resultSet.getString("email"));monster.setGender(resultSet.getByte("gender"));monster.setName(resultSet.getString("name"));monster.setSalary(resultSet.getDouble("salary"));}log.info("查询结果:{}", monster);} catch (Exception e) {throw new RuntimeException(e);} finally {// 关闭资源try {if (resultSet != null) {resultSet.close();}if (preparedStatement != null) {preparedStatement.close();}if (connection != null) {connection.close();}} catch (Exception e) {throw new RuntimeException(e);}}// 这里的T是由类型推断来指定的,也就是使用什么类型接受,就返回什么类型return (T) monster;}}

5.SunConfigurationTest.java 测试

@Test
public void executor() {SunExecutor sunExecutor = new SunExecutor();// 这里是使用的类型推断自动转换类型Monster monster = sunExecutor.query("select * from monster where id = ?", 1);
}

将SqlSession封装到执行器

1.目录

CleanShot 2024-08-09 at 13.17.02@2x

2.SunSqlSession.java

package com.sunxiansheng.mybatis.sqlsession;/*** Description: SqlSession** @Author sun* @Create 2024/8/9 13:08* @Version 1.0*/
public class SunSqlSession {// 执行器(操作db)private Executor executor = new SunExecutor();// 配置(用于获取连接)private SunConfiguration configuration = new SunConfiguration();public <T> T selectOne(String statement, Object parameter) {return executor.query(statement, parameter);}
}

3.测试

@Test
public void selectOne() {SunSqlSession sunSqlSession = new SunSqlSession();Monster monster = sunSqlSession.selectOne("select * from monster where id = ?", 1);System.out.println("monster = " + monster);
}

开发MapperBean和Function

1.目录

CleanShot 2024-08-09 at 13.39.36@2x

2.MonsterMapper.java

package com.sunxiansheng.mapper;import com.sunxiansheng.entity.Monster;/*** Description: MonsterMapper** @Author sun* @Create 2024/8/9 13:21* @Version 1.0*/
public interface MonsterMapper {public Monster getMonsterById(Integer id);}

3.MonsterMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<mapper namespace="com.sunxiansheng.mapper.MonsterMapper"><select id="getMonsterById" resultType="com.sunxiansheng.entity.Monster">select * from monster where id = ?</select>
</mapper>

4.Function.java 记录对应的mapper.xml的方法信息

package com.sunxiansheng.mybatis.config;import lombok.Data;/*** Description: 记录对应的mapper.xml的方法信息** @Author sun* @Create 2024/8/9 13:31* @Version 1.0*/
@Data
public class Function {/*** sql类型*/private String sqlType;/*** 方法名*/private String funcName;/*** SQL语句*/private String sql;/*** 返回类型*/private Object resultType;}

5.MapperBean.java 将mapper接口信息进行封装

package com.sunxiansheng.mybatis.config;import java.util.List;/*** Description: 将mapper接口信息进行封装** @Author sun* @Create 2024/8/9 13:35* @Version 1.0*/
public class MapperBean {/*** 接口全路径*/private String interfaceName;/*** 方法列表*/private List<Function> functions;}

读取xml文件解析MapperBean

1.目录

CleanShot 2024-08-09 at 14.03.00@2x

2.Function.java 加链式调用注解

CleanShot 2024-08-09 at 14.03.31@2x

3.MapperBean.java 加Data注解

CleanShot 2024-08-09 at 14.03.51@2x

4. SunConfiguration.java 增加解析MapperBean的方法

/*** 读取mapper.xml文件,构建MapperBean* @param path* @return*/
public MapperBean readMapper(String path) {// 要返回的结果MapperBean mapperBean = new MapperBean();// 使用类加载器读取配置文件ClassLoader loader = ClassLoader.getSystemClassLoader();InputStream resourceAsStream = loader.getResourceAsStream(path);// 解析xml文件SAXReader saxReader = new SAXReader();try {// 获取文档Document document = saxReader.read(resourceAsStream);// 获取根元素Element rootElement = document.getRootElement();// 获取根元素的属性:namespaceString namespace = rootElement.attributeValue("namespace");// 获取子元素List<Element> elements = rootElement.elements();// 遍历子元素List<Function> functions = elements.stream().map(element -> {Function function = new Function();// 获取sql类型String sqlType = element.getName();// 获取方法名String funcName = element.attributeValue("id");// 获取返回类型String resultType = element.attributeValue("resultType");// 获取sql语句String sql = element.getTextTrim();// 封装到Function对象中function.setSqlType(sqlType).setFuncName(funcName).setResultType(resultType).setSql(sql);return function;}).collect(Collectors.toList());// 构建MapperBeanmapperBean.setInterfaceName(namespace);mapperBean.setFunctions(functions);} catch (DocumentException e) {throw new RuntimeException(e);}// 输出mapperBean的日志log.info("mapperBean:{}", mapperBean);return mapperBean;
}

5.SunConfigurationTest.java 测试

    @Testpublic void readMapper() {SunConfiguration sunConfiguration = new SunConfiguration();sunConfiguration.readMapper("MonsterMapper.xml");}

CleanShot 2024-08-09 at 14.05.29@2x

动态代理Mapper方法

1.目录

CleanShot 2024-08-09 at 14.58.13@2x

2.MapperProxyFactory.java 代理工厂,可以获取接口的代理对象

package com.sunxiansheng.mybatis.sqlsession;import java.lang.reflect.Proxy;/*** Description: 代理工厂** @Author sun* @Create 2024/8/9 14:14* @Version 1.0*/
public class MapperProxyFactory {public static <T> T getMapperProxy(Class<T> clazz, SunSqlSession sunSqlSession, SunConfiguration sunConfiguration) {return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, new SunMapperProxy(sunSqlSession, clazz, sunConfiguration));}}

3.SunMapperProxy.java 代理逻辑

package com.sunxiansheng.mybatis.sqlsession;import com.sunxiansheng.mybatis.config.Function;
import com.sunxiansheng.mybatis.config.MapperBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.List;/*** Description: 代理Mapper接口** @Author sun* @Create 2024/8/9 14:08* @Version 1.0*/
public class SunMapperProxy implements InvocationHandler {private static final Logger log = LoggerFactory.getLogger(SunMapperProxy.class);/*** 用于连接数据库和执行sql*/private SunSqlSession sunSqlSession;/*** mapper文件名*/private String mapperFile;/*** 配置类(可以根据mapper文件名来获取MapperBean)*/private SunConfiguration sunConfiguration;public SunMapperProxy(SunSqlSession sunSqlSession, Class<?> mapperFile, SunConfiguration sunConfiguration) {this.sunSqlSession = sunSqlSession;this.mapperFile = mapperFile.getSimpleName() + ".xml";this.sunConfiguration = sunConfiguration;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 获取方法名String methodName = method.getName();// 获取MapperBeanMapperBean readMapper = sunConfiguration.readMapper(mapperFile);// 获取Function列表,过滤出需要执行的FunctionList<Function> functions = readMapper.getFunctions();Function targetFunction = null;for (Function function : functions) {if (methodName.equals(function.getFuncName())) {targetFunction = function;break;}}// 获取Function的信息String sqlType = targetFunction.getSqlType();String sql = targetFunction.getSql();// 将sql的第一个问号使用参数替换,使用字符串处理// 根据sqlType执行sqlif (sqlType.equals("select")) {Object selected = sunSqlSession.selectOne(sql, args[0]);log.info("invoke查询结果:{}", selected);return selected;}return null;}
}

4.测试

@Test
public void getResult() {MonsterMapper mapperProxy = MapperProxyFactory.getMapperProxy(MonsterMapper.class, new SunSqlSession(), new SunConfiguration());Monster monsterById = mapperProxy.getMonsterById(1);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/407063.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CoppeliaSim(V-Rep)与ROS1、ROS2接口变迁-2024-

Webots&#xff1a;Webots与ROS1、ROS2接口变迁 Gazebo&#xff1a;Gazebo与ROS1、ROS2接口变迁 ROS1 2016&#xff1a;ROS_Kinetic_18 使用V-Rep3.3.1和Matlab2015b&#xff08;vrep_ros_bridge&#xff09;续 vrep_ros_bridge 插件 一、项目背景与目标 vrep_ros_bridge 是…

Linux系统之jobs命令的基本使用

Linux系统之jobs命令的基本使用 一、jobs命令介绍二、jobs命令的使用帮助2.1 jobs命令的help帮助信息2.2 jobs命令的语法解释 三、jobs命令的基本使用3.1 运行一个后台任务3.2 列出后台所有的作业3.3 列出进程ID3.4 只列出进程ID3.5 终止后台任务3.6 只显示运行任务3.7 只显示停…

设备状态图表-甘特图

1.背景&#xff1a;设备状态监控图表&#xff0c;监控不同状态的时间段&#xff0c;可以使用甘特图来展示效果 鼠标经过时的数据提示框 2、代码实现 <template><divref"ganttChartRefs":style"{ height: 6.2rem, width: 100% }"class"bg…

视频项目开发,EasyCVR视频融合平台为何成为关键驱动力

智慧类视频项目是基于多个系统融合&#xff0c;旨在实现更广泛联动功能&#xff0c;以满足智能化应用需求为基石的信息化项目。当前&#xff0c;智慧社区、智慧园区、智慧工厂乃至智慧城市等应用场景的需求日益增长。这些智慧项目的整合进程中&#xff0c;视频融合能力扮演着不…

burpsuite xssValidator插件(xss插件)

安装 1. 商城安装插件 2. 安装环境 Download PhantomJShttps://phantomjs.org/download.htmlGitHub - NetSPI/xssValidator: This is a burp intruder extender that is designed for automation and validation of XSS

房价下跌的大环境下,我的佣金为何能逆市增长?

声明&#xff1a;此篇为 ai123.cn 原创文章&#xff0c;转载请标明出处链接&#xff1a;https://ai123.cn/2199.html &#x1f3e0;&#x1f4b0;最近房地产市场可不太景气&#xff0c;房价跌跌不休&#xff0c;咱们中介们的佣金收入也受到了影响。你知道那种心情吗&#xff1f…

【IoTDB 线上小课 06】列式写入=时序数据写入性能“利器”?

【IoTDB 视频小课】更新来啦&#xff01;今天已经是第六期了~ 关于 IoTDB&#xff0c;关于物联网&#xff0c;关于时序数据库&#xff0c;关于开源... 一个问题重点&#xff0c;3-5 分钟&#xff0c;我们讲给你听&#xff1a; 列式写入到底是&#xff1f; 上一期我们详细了解了…

汽车冷却液温度传感器的作用与检测方法

汽车冷却系统中的关键部件之一是冷却液温度传感器&#xff0c;它的位置通常在发动机的缸体或水泵附近&#xff0c;与冷却液直接接触。该传感器的作用是监测发动机冷却液的温度&#xff0c;它采用负温度系数热敏电阻&#xff0c;这种电阻随温度升高而降低。当冷却液温度达到预定…

AcWing 850. Dijkstra求最短路 II

迪杰斯特拉的优化算法采用堆优化&#xff0c;优化之前是花费 O ( n ) O(n) O(n)时间来查找未最优点里面距离点1最小的点。现在使用堆优化&#xff0c;直接花费 O ( 1 ) O(1) O(1)时间就完事儿了。 堆里面存储 p a i r < i n t , i n t > pair<int,int> pair<int…

Java毕业论文 【二手书电子商城网站】源码见github (原创项目,从0-1自己实现)

文章目录 项目背景主要功能模块分布模块分布具体部分功能 系统架构功能演示买家部分界面&#xff1a;卖家部分界面【8002模块】&#xff1a;管理员部分界面&#xff1a; 项目github地址 项目背景 主要面向高校学生&#xff0c;将高年级同学的书回收到低年级学生的手上&#xf…

CANoe.DiVa的应用——Diva进行诊断自动化测试执行过程详解(三)

🙋‍♂️【Vector CANdelastudio配置CDD】文章合集💁‍♂️点击跳转 ——————————————————————————————————–—— 从0开始学习CANoe使用 从0开始学习车载测试 相信时间的力量 星光不负赶路者,时光不负有心人。 目录 1.工程导入2.查看用…

什么是BOM,有哪些分类?

一、什么是BOM&#xff1f; BOM是物料清单的缩写&#xff0c;也称为产品结构表或产品结构树。 BOM的作用主要是通过计算机辅助企业生产管理&#xff0c;使计算机能够识别企业所制造的产品构成和所有要涉及的物料。 在制造业中&#xff0c;BOM是一份详细记录制造某个产品时所…

【算法基础实验】图论-最小生成树Kruskal实现

预备知识 【算法基础实验】图论-UnionFind连通性检测之quick-union_union find 判断是否成环-CSDN博客 【算法基础实验】排序-最小优先队列MinPQ_最小优先队列实现-CSDN博客 理论知识 Kruskal算法是一种用于查找加权无向图的最小生成树的贪心算法。最小生成树是一个连通的子…

uniapp使用live-pusher进行人脸识别打卡(安卓跟ios)

效果图 代码 使用live-pusher <live-pusher idlivePusher class"livePusher" mode"FHD" beauty"0" whiteness"0" aspect"9:16"min-bitrate"1000" audio-quality"16KHz" device-position"fron…

Apple pencil有替代品吗?2024开学季推荐五款实惠又好用的电容笔

如果只是用于学习和办工的话&#xff0c;Apple pencil是有替代品的&#xff0c;虽然Apple Pencil的性能不错&#xff0c;但它的高昂价格让很多用户不得不开始寻求性价比更高的平替电容笔。那么&#xff0c;在众多选择中&#xff0c;如何挑选一款合适的电容笔呢&#xff1f;以下…

【iOS】Block底层分析

目录 前言Block底层结构Block捕获变量原理捕获局部变量&#xff08;auto、static&#xff09;全局变量捕获实例self Block类型Block的copyBlock作为返回值将Block赋值给__strong指针Block作为Cocoa API中方法名含有usingBlock的方法参数Block作为GCD API的方法参数Block属性的写…

光性能 -- 边模抑制比眼图

最小边模抑制比 在最坏的发射条件下&#xff0c;主模的平均光功率与最显著边模的光功率之比即最小边模抑制比。 什么是边模 理想情况下&#xff0c;光模块发射的信号应当只是有特定波长的光信号。但实际情况下不仅有一个特定波长的主信号&#xff0c;还有一些其他波长的存在&…

Java学习笔记(02)接口的使用

1、接口关键字&#xff1a;interface 2、接口内部结构的说明&#xff1a; 可以声明抽象方法&#xff0c;属性由public static final修饰&#xff0c;但都会默认。 不可以声明&#xff1a;构造器&#xff0c;代码块等。 3、格式&#xff1a;class A extends SuperA implements…

开放式耳机别人能听到吗?现在开放式耳机用防漏音效果越来越好!

回答&#xff1a; 开放式耳机的通透的设计允许一部分声音泄露出来&#xff0c;因此站在您旁边的人确实有可能听到您耳机中的声音&#xff0c;尤其是当音量设置得比较高时。开放式耳机通常提供更为自然和宽敞的听感&#xff0c;但牺牲了一定的隔音效果和隐私性。如果您需要在公…

探索提示工程 Prompt Engineering的奥妙

一、探索提示工程 1. 介绍通用人工智能和专用人工智能 人工智能&#xff08;AI&#xff09;可以分为通用人工智能&#xff08;AGI&#xff09;和专用人工智能&#xff08;Narrow AI&#xff09;。AGI是一种能够理解、学习和执行任何人类可以完成的任务的智能。与此相对&#x…