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

Mybatis 实现原理

Mybatis 手撸专栏

MapperProxyFactory

Mapper是什么?

Mapper由两个文件组成
1 Java文件(映射器类/IDAO)用户定义的数据库操作接口:想要对数据库进行的操作

public interface IUserService {
    queryNameById();
    queryAgeById();
}

2 XML文件(XML映射文件)操作的具体实现:SQL语句

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.IUserService">
    <select id="queryNameById" parameterType="java.lang.Integer" resultType="java.lang.String">
    	SELECT name FROM user WHERE id = #{id}
    </select>
    <select id="queryAgeById" parameterType="java.lang.Integer" resultType="java.lang.String">
    	SELECT age FROM user WHERE id = #{id}
    </select>
</mapper>

在 XML 文件中,通过 namespace,可以找到对应 IDAO类,后面会用到

MapperProxy

通过IDAO接口 + XML文件,可以完成对数据库的操作
那么,IDAO接口和XML文件,是如何联系在一起的?
通过代理类
将IDAO接口和XML文件封装到代理类中
之后,通过这个代理类,当调用IDAO接口中的方法时,最终会调用XML中对应SQL语句
这个代理类就是MapperProxy,如图
在这里插入图片描述

public class MapperProxy implements InvocationHandler {
    private Class IDAO;
    private HashMap<String, String> xmlFile;
    public MapperProxy(Class IDAO, HashMap<String, String> xmlFile) {
        this.IDAO = IDAO;
        this.xmlFile = xmlFile;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return xmlFile.get(method.getName());
    }
}

测试如下

HashMap<String, String> xmlFile = new HashMap<>();
xmlFile.put("queryNameById", "SELECT name FROM user WHERE id = 1");
xmlFile.put("queryAgeById", "SELECT age FROM user WHERE id = 1");
MapperProxy mapperProxy =  new MapperProxy(IUserService.class, xmlFile);
IUserService o = (IUserService) Proxy.newProxyInstance(IUserService.class.getClassLoader(), new Class[]{IUserService.class}, mapperProxy);
System.out.println(o.queryNameById());		// SELECT name FROM user WHERE id = 1

测试的时候,每次都要调用 Proxy.newProxyInstance,很麻烦;于是,封装到 MapperProxy 中

public Object getProxyObject(){
    return Proxy.newProxyInstance(IDAO.getClassLoader(), new Class[]{IDAO}, this);
}

// 之后就可以
MapperProxy mapperProxy =  new MapperProxy(IUserService.class, xmlFile);
IUserService o = (IUserService) mapperProxy.getProxyObject();
System.out.println(o.queryNameById());		// SELECT name FROM user WHERE id = 1

MapperProxyFactory

相同的IDAO接口,可有不同的实现方式,甚至,所使用的数据库也可能不同

因此,干脆将IDAO封装到一个类中,之后通过 newInstance(xmlFIle) 的方式生成 MapperProxy 代理对象

另外,Proxy.newProxyInstance 的逻辑也封装到 newInstance 中

这个类就是MapperProxyFactory
在这里插入图片描述

public class MapperProxyFactory<T> {
    private Class<T> IDAO;
    public MapperProxyFactory(Class<T> IDAO) {
        this.IDAO = IDAO;
    }
    public T newInstance(HashMap<String, String> xmlFIle) {
        final MapperProxy mapperProxy = new MapperProxy(IDAO, xmlFIle);
        return (T) Proxy.newProxyInstance(IDAO.getClassLoader(), new Class[]{IDAO}, mapperProxy);
    }
}

使用如下

IUserService o = new MapperProxyFactory<>(IUserService.class).newInstance(xmlFile);
System.out.println(o.queryNameById());

第2章:创建简单的映射器代理工厂

这里的 sqlSession 理解为 XML 文件,mapperInterface 理解为 IDAO,后面就使用作者的了
在这里插入图片描述

MapperRegistry 及 SqlSession 封装

MapperRegistry

MapperProxyFactory 只是针对一个IDAO接口,并不能添加、删除;那么,就必定需要一个集中式管理的类
这个类就是 MapperRegistry,相当于封装了多个 IDAO 接口,用于集中式管理IDAO接口

SqlSession

之前定义的 sqlsession (xmlFile)为一个 HashMap,现将其封装成一个对象,并由 SqlSessionFactory 构造,该工厂持有 MapperRegistry(封装多个IDAO服务)
通过该工厂,可创建 SqlSession,但此时 SqlSession 中未定义具体实现

为何要创建一个 SqlSessionFactory ?直接 new SqlSession 不行吗?
诶,好像还真可以~
如果要强行解释的话,那么我的强行解释就是,Factory,从语义上可以理解为创建 xxx 的工厂,很规范。。。。。容易理解

第3章:实现映射器的注册和使用

在这里插入图片描述

XML解析

Configuration 类

根据 mapper.xml 的信息,namespace 对应 IDAO的位置,select 等对应 SQL 语句,通过解析 XML,可获取这些内容
解析出这些内容后,必定要存储,于是用到了 Configuration 类:将 xmlFile(对数据库的操作)的信息,封装到 Configuration 类中
Configuration 类中有

  • mapperRegistry(为多个IDAO服务):根据 mapper.xml 文件下的 namespace 进行添加的
  • mappedStatements(与IDAO对应的SQL语句):类型为 HashMap<String, MappedStatement>,一个 MappedStatement 对应一条 SQL 语句
    在这里插入图片描述

XML environments 解析

Environment

这里会解析 environment(用于连接数据库的信息:driver、url、username、password),并放入 Configration类中
于是,Configuration 中多出了个 Environment 类实例的成员变量,Environment 类中有

  • id:如 development
  • transactionFactory:如 JdbcTransactionFactory
  • dataSource:如 DruidDataSource

typeAliasRegistry 类型别名注册机

Configration类中有个名为 typeAliasRegistry 的成员变量,它是 TypeAliasRegistry 类的实例,类中有个 HashMap,用于存储别名

 <select id="queryUser" resultType="com.foo.bar.baz.quz.User">
 	SELECT * FROM user WHERE id = 1
 </select>

resultType 很长是不是 ? 起个别名吧~

<configuration>
    <typeAliases>
        <typeAlias alias="user" type="com.foo.bar.baz.quz.User"/>
    </typeAliases>
</configuration>
 <select id="queryUser" resultType="user">
 	SELECT * FROM user WHERE id = 1
 </select>

new Configuration 的时候(还未解析XML文件时),会将 JdbcTransactionFactory、DruidDataSourceFactory 存放到 typeAliasRegistry 内的 HashMap
之后,根据 XML 文件中的信息,可通过 typeAliasRegistry 获取到JdbcTransactionFactory、DruidDataSourceFactory ,用于创建 Environment

在这里插入图片描述

相关文章:

  • matplotlib入门
  • JavaScript设计模式——建造者模式
  • Roson的Qt之旅 #124 QNetworkConfigurationManager网络配置管理
  • 天池Python练习02-位运算
  • 国内主机整车EEA架构汇总
  • Java刷题面试系列习题(十三)
  • linux驱动35:工作队列
  • 句向量模型之SimCSE——Pytorch
  • 简单旅游景点HTML网页设计作品 DIV布局故宫介绍网页模板代码 DW家乡网站制作成品 web网页制作与实现
  • 图解redis(四)——高可用篇
  • LQ0048 交换瓶子【无标题】
  • 《SpringBoot篇》11.JPA常用注解只需一个表
  • 不想手敲代码?Jupyter Notebook 又一利器 Visual Python
  • 【mysql体系结构】InnoDB索引页结构
  • Roson的Qt之旅 #123 QNetworkConfigurationManager网络配置管理
  • canvas 五子棋游戏
  • ES10 特性的完整指南
  • iOS帅气加载动画、通知视图、红包助手、引导页、导航栏、朋友圈、小游戏等效果源码...
  • Java 最常见的 200+ 面试题:面试必备
  • JS函数式编程 数组部分风格 ES6版
  • open-falcon 开发笔记(一):从零开始搭建虚拟服务器和监测环境
  • Python 使用 Tornado 框架实现 WebHook 自动部署 Git 项目
  • Rancher如何对接Ceph-RBD块存储
  • SegmentFault 2015 Top Rank
  • SOFAMosn配置模型
  • vue+element后台管理系统,从后端获取路由表,并正常渲染
  • 不上全站https的网站你们就等着被恶心死吧
  • 后端_ThinkPHP5
  • 基于Dubbo+ZooKeeper的分布式服务的实现
  • 开发了一款写作软件(OSX,Windows),附带Electron开发指南
  • 坑!为什么View.startAnimation不起作用?
  • 批量截取pdf文件
  • 微信小程序设置上一页数据
  • 用简单代码看卷积组块发展
  • 鱼骨图 - 如何绘制?
  • 翻译 | The Principles of OOD 面向对象设计原则
  • ​Base64转换成图片,android studio build乱码,找不到okio.ByteString接腾讯人脸识别
  • ​软考-高级-系统架构设计师教程(清华第2版)【第20章 系统架构设计师论文写作要点(P717~728)-思维导图】​
  • #pragma 指令
  • $.ajax中的eval及dataType
  • (02)vite环境变量配置
  • (4)STL算法之比较
  • (PyTorch)TCN和RNN/LSTM/GRU结合实现时间序列预测
  • (ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY)讲解
  • (附源码)ssm本科教学合格评估管理系统 毕业设计 180916
  • (每日持续更新)jdk api之StringBufferInputStream基础、应用、实战
  • (强烈推荐)移动端音视频从零到上手(上)
  • (四)模仿学习-完成后台管理页面查询
  • (四)图像的%2线性拉伸
  • (一)UDP基本编程步骤
  • (原創) 如何讓IE7按第二次Ctrl + Tab時,回到原來的索引標籤? (Web) (IE) (OS) (Windows)...
  • (转)VC++中ondraw在什么时候调用的
  • (转)利用ant在Mac 下自动化打包签名Android程序
  • (转载)虚函数剖析
  • (最全解法)输入一个整数,输出该数二进制表示中1的个数。