会员登录 - 用户注册 - 设为首页 - 加入收藏 - 网站地图 Mapper XML的解析和注册使用!

Mapper XML的解析和注册使用

时间:2025-11-05 16:00:37 来源:益强数据堂 作者:IT科技类资讯 阅读:894次

一、解析前言

你是和注怎么面对功能迭代的?

其实很多程序员在刚开始做编程或者新加入一家公司时,都没有多少机会可以做一个新项目,册使大部分时候都是解析在老项目上不断的迭代更新。在这个过程你可能要学习N个前人留下的和注各式各样的风格迥异的代码片段,在这些纵横交错的册使流程中,找到一席之地,解析把自己的和注ifelse加进去。

虽然这样胡乱的册使加ifelse,刚上手就“摆烂”的解析心态,让人很难受。和注但要想在已经被压缩的册使工期下,还能交付出高质量的解析代码其实也很难完成,所以一部分研发被逼到能用就行,和注能跑就可以。册使

但说回来,其实不能逐步清理一片屎山,让代码在你的手上逐步清晰、整洁、干净,高防服务器很多时候也是作为码农自身经验的不足,不懂得系统重构、不了解设计原则、不熟悉业务背景、不清楚产品走向等等原因造成的。所以最好的办法是提升自身的能力,每接到一次需求都有一些技术上的改变,既然它是屎山,那就当做打怪升级了,修一点、改一块、补一片,总会在你手上越来越易于维护和扩展的。

二、目标

在我们渐进式的逐步实现 Mybatis 框架过程中,首先我们要有一个目标导向的思路,也就是说 Mybatis 的核心逻辑怎么实现。

其实我们可以把这样一个 ORM 框架的目标,简单的云南idc服务商描述成是为了给一个接口提供代理类,类中包括了对 Mapper 也就是 xml 文件中的 SQL 信息(类型、入参、出参、条件)进行解析和处理,这个处理过程就是对数据库的操作以及返回对应的结果给到接口。如图 4-1

图 4-1 ORM 框架核心流程

那么按照 ORM 核心流程的执行过程,我们本章节就需要在上一章节的基础上,继续扩展对 Mapper 文件的解析以及提取出对应的 SQL 文件。并在当前这个阶段,可以满足我们调用 DAO 接口方法的时候,可以返回 Mapper 中对应的待执行 SQL 语句。为了不至于把整个工程撑大,小傅哥会带着大家逐步完成这些内容,所以本章节暂时不会对数据库进行操作,待后续逐步实现

三、设计

结合上一章节我们使用了 MapperRegistry 对包路径进行扫描注册映射器,并在 DefaultSqlSession 中进行使用。那么在我们可以把这些命名空间、SQL描述、映射信息统一维护到每一个 DAO 对应的源码库 Mapper XML 的文件以后,其实 XML 就是我们的源头了。通过对 XML 文件的解析和处理就可以完成 Mapper 映射器的注册和 SQL 管理。这样也就更加我们操作和使用了。如图 4-2

图 4-2 XML 文件解析注册处理

首先需要定义 SqlSessionFactoryBuilder 工厂建造者模式类,通过入口 IO 的方式对 XML 文件进行解析。当前我们主要以解析 SQL 部分为主,并注册映射器,串联出整个核心流程的脉络。文件解析以后会存放到 Configuration 配置类中,接下来你会看到这个配置类会被串联到整个 Mybatis 流程中,所有内容存放和读取都离不开这个类。如我们在 DefaultSqlSession 中获取 Mapper 和执行 selectOne 也同样是需要在 Configuration 配置类中进行读取操作。

四、实现

1. 工程结构mybatis-step-03

└── src

├── main

│ └── java

│ └── cn.bugstack.mybatis

│ ├── binding

│ │ ├── MapperMethod.java

│ │ ├── MapperProxy.java

│ │ ├── MapperProxyFactory.java

│ │ └── MapperRegistry.java

│ ├── builder

│ │ ├── xml

│ │ │ └── XMLConfigBuilder.java

│ │ └── BaseBuilder.java

│ ├── io

│ │ └── Resources.java

│ ├── mapping

│ │ ├── MappedStatement.java

│ │ └── SqlCommandType.java

│ └── session

│ ├── defaults

│ │ ├── DefaultSqlSession.java

│ │ └── DefaultSqlSessionFactory.java

│ ├── Configuration.java

│ ├── SqlSession.java

│ ├── SqlSessionFactory.java

│ └── SqlSessionFactoryBuilder.java

└── test

├── java

│ └── cn.bugstack.mybatis.test.dao

│ ├── dao

│ │ └── IUserDao.java

│ ├── po

│ │ └── User.java

│ └── ApiTest.java

└── resources

├── mapper

│ └──User_Mapper.xml

└── mybatis-config-datasource.xml

工程源码:https://t.zsxq.com/bmqNFQ7

XML 解析和注册类实现关系,如图 4-2

图 4-2 XML 解析和注册类实现关系

SqlSessionFactoryBuilder 作为整个 Mybatis 的入口,提供建造者工厂,包装 XML 解析处理,并返回对应 SqlSessionFactory 处理类。通过解析把 XML 信息注册到 Configuration 配置类中,再通过传递 Configuration 配置类到各个逻辑处理类里,包括 DefaultSqlSession 中,这样就可以在获取映射器和执行SQL的时候,从配置类中拿到对应的内容了。2. 构建SqlSessionFactory建造者工厂

源码详见:cn.bugstack.mybatis.session.SqlSessionFactoryBuilder

public class SqlSessionFactoryBuilder {

public SqlSessionFactory build(Reader reader) {

XMLConfigBuilder xmlConfigBuilder = new XMLConfigBuilder(reader);

return build(xmlConfigBuilder.parse());

}

public SqlSessionFactory build(Configuration config) {

return new DefaultSqlSessionFactory(config);

}

}SqlSessionFactoryBuilder 是作为整个 Mybatis 的入口类,通过指定解析XML的IO,引导整个流程的启动。从这个类开始新增加了 XMLConfigBuilder、Configuration 两个处理类,分别用于解析 XML 和串联整个流程的对象保存操作。接下来我们会分别介绍这些新引入的对象。3. XML 解析处理

源码详见:cn.bugstack.mybatis.builder.xml.XMLConfigBuilder

public class XMLConfigBuilder extends BaseBuilder {

private Element root;

public XMLConfigBuilder(Reader reader) {

// 1. 调用父类初始化Configuration

super(new Configuration());

// 2. dom4j 处理 xml

SAXReader saxReader = new SAXReader();

try {

Document document = saxReader.read(new InputSource(reader));

root = document.getRootElement();

} catch (DocumentException e) {

e.printStackTrace();

}

}

public Configuration parse() {

try {

// 解析映射器

mapperElement(root.element("mappers"));

} catch (Exception e) {

throw new RuntimeException("Error parsing SQL Mapper Configuration. Cause: " + e, e);

}

return configuration;

}

private void mapperElement(Element mappers) throws Exception {

ListmapperList = mappers.elements("mapper");

for (Element e : mapperList) {

// 解析处理,具体参照源码

// 添加解析 SQL

configuration.addMappedStatement(mappedStatement);

}

// 注册Mapper映射器

configuration.addMapper(Resources.classForName(namespace));

}

}

}XMLConfigBuilder 核心操作在于初始化 Configuration,因为 Configuration 的使用离解析 XML 和存放是最近的操作,所以放在这里比较适合。之后就是具体的 parse() 解析操作,并把解析后的信息,通过 Configuration 配置类进行存放,包括:添加解析 SQL、注册Mapper映射器。解析配置整体包括:类型别名、插件、对象工厂、对象包装工厂、设置、环境、类型转换、映射器,但目前我们还不需要那么多,所以只做一些必要的 SQL 解析处理。4. 通过配置类包装注册机和SQL语句

**源码详见(配置项)**:cn.bugstack.mybatis.session.Configuration

public class Configuration {

/

**

* 映射注册机

*/

protected MapperRegistry mapperRegistry = new MapperRegistry(this);

/

**

* 映射的语句,存在Map里

*/

protected final MapmappedStatements = new HashMap<>();

public void addMapper(Classtype) {

mapperRegistry.addMapper(type);

}

public void addMappedStatement(MappedStatement ms) {

mappedStatements.put(ms.getId(), ms);

}

}

在配置类中添加映射器注册机和映射语句的存放;

映射器注册机是我们上一章节实现的内容,用于注册 Mapper 映射器锁提供的操作类。

另外一个 MappedStatement 是本章节新添加的 SQL 信息记录对象,包括记录:SQL类型、SQL语句、入参类型、出参类型等。详细可参照源码

5. DefaultSqlSession结合配置项获取信息

源码详见:cn.bugstack.mybatis.session.defaults.DefaultSqlSession

public class DefaultSqlSession implements SqlSession {

private Configuration configuration;

@Override

public T selectOne(String statement, Object parameter) {

MappedStatement mappedStatement = configuration.getMappedStatement(statement);

return (T) ("你被代理了!" + "n方法:" + statement + "n入参:" + parameter + "n待执行SQL:" + mappedStatement.getSql());

}

@Override

public T getMapper(Classtype) {

return configuration.getMapper(type, this);

}

}

DefaultSqlSession 相对于上一章节,小傅哥这里把 MapperRegistry mapperRegistry 替换为 Configuration configuration,这样才能传递更丰富的信息内容,而不只是注册器操作。

之后在 DefaultSqlSession#selectOne、DefaultSqlSession#getMapper 两个方法中都使用 configuration 来获取对应的信息。

目前 selectOne 方法中只是把获取的信息进行打印,后续将引入 SQL 执行器进行结果查询并返回。

五、测试

1. 事先准备

提供 DAO 接口和对应的 Mapper xml 配置

public interface IUserDao {

String queryUserInfoById(String uId);

}

SELECT id, userId, userHead, createTime

FROM user

where id = #{id}

2. 单元测试@Test

public void test_SqlSessionFactory() throws IOException {

// 1. 从SqlSessionFactory中获取SqlSession

Reader reader = Resources.getResourceAsReader("mybatis-config-datasource.xml");

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);

SqlSession sqlSession = sqlSessionFactory.openSession();

// 2. 获取映射器对象

IUserDao userDao = sqlSession.getMapper(IUserDao.class);

// 3. 测试验证

String res = userDao.queryUserInfoById("10001");

logger.info("测试结果:{}", res);

}目前的使用方式就和 Mybatis 非常像了,通过加载 xml 配置文件,交给 SqlSessionFactoryBuilder 进行构建解析,并获取 SqlSessionFactory 工厂。这样就可以顺利的开启 Session 以及完成后续的操作。

测试结果

07:07:40.519 [main] INFO cn.bugstack.mybatis.test.ApiTest - 测试结果:你被代理了!

方法:cn.bugstack.mybatis.test.dao.IUserDao.queryUserInfoById

入参:[Ljava.lang.Object;@23223dd8

待执行SQL:

SELECT id, userId, userHead, createTime

FROM user

where id = ?

Process finished with exit code 0

从测试结果我们可以看到,目前的代理操作已经可以把我们从 XML 中解析的 SQL 信息进行打印了,后续我们将结合这部分的处理继续完成数据库的操作。

六、总结

了解 ORM 处理的核心流程,知晓目前我们所处在的步骤和要完成的内容,只有非常清楚的知道这个代理、封装、解析和返回结果的过程才能更好的完成整个框架的实现。SqlSessionFactoryBuilder 的引入包装了整个执行过程,包括:XML 文件的解析、Configuration 配置类的处理,让 DefaultSqlSession 可以更加灵活的拿到对应的信息,获取 Mapper 和 SQL 语句。另外从整个工程搭建的过程中,可以看到有很多工厂模式、建造者模式、代理模式的使用,也有很多设计原则的运用,这些技巧都可以让整个工程变得易于维护和易于迭代。这也是研发人员在学习源码的过程中,非常值得重点关注的地方。

(责任编辑:数据库)

最新内容
推荐内容
  • 宏达主板(探索宏达主板的功能与优势)
  • 不同域名的含义适用领域不同吗?有什么参考?
  • 电商品牌需要怎么选择域名?新手选择域名注意什么?
  • 现在AI域名在域名市场咋样?域名AI将会赶超.com吗?
  • 探索HU4803的特性和性能(了解HU4803的优点和应用领域)
  • 未来互联网域名会不会消失?