手写mybatis之实现映射器的注册和使用

news2024/10/4 17:45:48

前言


其实对于解决这类复杂的项目问题,核心在于要将主干问题点缩小,具体的手段包括:分治、抽象和知识。运用设计模式和设计原则等相关知识,把问题空间合理切割为若干子问题,问题越小也就越容易理解和处理。就像你可以把很多内容做成单个独立的案例一样,最终在进行聚合使用。

上一节编码存在两问题

1:需要编码告知 MapperProxyFactory 要对哪个接口进行代理。
2:需要自己编写一个假的 SqlSession 处理实际调用接口时的返回结果。
所以我们来解决上述存在问题
当然我们还要把上一章节中简化的 SqlSession 进行完善,由 SqlSession
定义数据库处理接口和获取 Mapper 对象的操作,并把它交给映射器代理
类进行使用。

在这里插入图片描述
映射器注册机

package com.lm.mybatis.binding;

import cn.hutool.core.lang.ClassScanner;
import com.lm.mybatis.session.SqlSession;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class MapperRegistry {
    /**
     * 将已添加的映射器代理加入到 HashMap
     */
    private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>();

    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
        if (mapperProxyFactory == null) {
            throw new RuntimeException("Type " + type + " is not known to the MapperRegistry.");
        }
        try {
            return mapperProxyFactory.newInstance(sqlSession);
        } catch (Exception e) {
            throw new RuntimeException("Error getting mapper instance. Cause: " + e, e);
        }
    }

    public <T> void addMapper(Class<T> type) {
        /* Mapper 必须是接口才会注册 */
        if (type.isInterface()) {
            if (hasMapper(type)) {
                // 如果重复添加了,报错
                throw new RuntimeException("Type " + type + " is already known to the MapperRegistry.");
            }
            // 注册映射器代理工厂
            knownMappers.put(type, new MapperProxyFactory<>(type));
        }
    }

    public <T> boolean hasMapper(Class<T> type) {
        return knownMappers.containsKey(type);
    }

    public void addMappers(String packageName) {
        Set<Class<?>> mapperSet = ClassScanner.scanPackage(packageName);
        for (Class<?> mapperClass : mapperSet) {
            addMapper(mapperClass);
        }
    }

}

MapperRegistry 映射器注册类的核心主要在于提供了 ClassScanner.scanPackage 扫描包路径,调用 addMapper 方法,给接口类创建 MapperProxyFactory 映射器代理类,并写入到 knownMappers 的 HashMap 缓存中。
另外就是这个类也提供了对应的 getMapper 获取映射器代理类的方法,其实这步就包装了我们上一章节手动操作实例化的过程,更加方便在 DefaultSqlSession 中获取 Mapper 时进行使用。
SqlSession 标准定义和实现

package com.lm.mybatis.session;

public interface SqlSession {

    <T> T selectOne(String id);

    <T> T selectOne(String statement, Object parameter);

    <T> T getMapper(Class<T> type);

}

在 SqlSession 中定义用来执行 SQL、获取映射器对象以及后续管理事务操作的标准接口。
目前这个接口中对于数据库的操作仅仅只提供了 selectOne,后续还会有相应其他方法的定义。

package com.lm.mybatis.session.defaults;

import com.lm.mybatis.binding.MapperRegistry;
import com.lm.mybatis.session.SqlSession;

public class DefaultSqlSession implements SqlSession {

    /**
     * 映射器注册机
     */
    private MapperRegistry mapperRegistry;
    public DefaultSqlSession(MapperRegistry mapperRegistry) {
        this.mapperRegistry = mapperRegistry;
    }


    @Override
    public <T> T selectOne(String statement) {
        return (T) ("你被代理了!" + statement);
    }

    @Override
    public <T> T selectOne(String statement, Object parameter) {
        return (T) ("你被代理了!" + "方法:" + statement + " 入参:" + parameter);
    }

    @Override
    public <T> T getMapper(Class<T> type) {
        return mapperRegistry.getMapper(type, this);
    }


}

通过 DefaultSqlSession 实现类对 SqlSession 接口进行实现。
在 selectOne 中是一段简单的内容返回,目前还没有与数据库进行关联,这部分在我们渐进式的开发过程中逐步实现。
SqlSessionFactory 工厂定义和实现

package com.lm.mybatis.session;

public interface SqlSessionFactory {
    /**
     * 打开一个 session
     *
     * @return SqlSession
     */
    SqlSession openSession();

}

package com.lm.mybatis.session.defaults;

import com.lm.mybatis.binding.MapperRegistry;
import com.lm.mybatis.session.SqlSession;
import com.lm.mybatis.session.SqlSessionFactory;

public class DefaultSqlSessionFactory implements SqlSessionFactory {
    private final MapperRegistry mapperRegistry;

    public DefaultSqlSessionFactory(MapperRegistry mapperRegistry) {
        this.mapperRegistry = mapperRegistry;
    }

    @Override
    public SqlSession openSession() {
        return new DefaultSqlSession(mapperRegistry);
    }

}

默认的简单工厂实现,处理开启 SqlSession 时,对 DefaultSqlSession 的创建以及传递 mapperRegistry,这样就可以在使用 SqlSession 时获取每个代理类的映射器对象了。
增加接口测试

package com.lm.test.dao;

public interface ISchoolDao {
    String querySchoolName(String uId);
}

   @Test
    public void test02() {
        // 1. 注册 Mapper
        MapperRegistry registry = new MapperRegistry();
        registry.addMappers("com.lm.test.dao");

        // 2. 从 SqlSession 工厂获取 Session
        SqlSessionFactory sqlSessionFactory = new DefaultSqlSessionFactory(registry);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 3. 获取映射器对象
        IUserDao userDao = sqlSession.getMapper(IUserDao.class);
        // 4. 测试验证
        String res = userDao.queryUserName("10001");
        logger.info("测试结果:{}", res);

    }
}

测试结果如下
在这里插入图片描述

好了到这里就结束了手写mybatis之实现映射器的注册和使用的学习,大家一定要跟着动手操作起来。需要的源码的 可si我获取;

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【论文阅读】Segment Anything Model for Road Network Graph Extraction

【论文阅读】Segment Anything Model for Road Network Graph Extraction (CVPRW 2024) Paper链接&#xff1a;https://openaccess.thecvf.com/content/CVPR2024W/SG2RL/html/Hetang_Segment_Anything_Model_for_Road_Network_Graph_Extraction_CVPRW_2024_paper.html 文章目录…

基于SSM医疗信息管理系统(源码+定制+参考)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

vue文件的认识

1.package.json 项目包文件 里面包含许多可以在命令提示符中运行的命令&#xff0c;这里使用vue3创建的项目&#xff0c;所以dev是“vite”。 2.main.js 整个项目的入口文件&#xff0c;createApp创建应用实例 createApp(App).mount(#app) 这句话意思是以App作为参数生成一…

ElasticSearch备考 -- Search scroll

一、题目 Search for all documents in all indices As above, but use the scroll API to return the first 100 results while keeping the search context alive for 2 minutes Use the scroll id included in the response to the previous query and retrieve the next ba…

启用vnc访问Dell 服务器IDRAC 7虚拟控制台

Dell IDRAC 7 版本太老&#xff0c;SSL证书过期&#xff0c;IDRAC的Java和本地远程虚拟机控制台访问不了&#xff0c;怎么办&#xff1f; 可以启用vnc访问IDRAC 虚拟控制台

Vue2如何在网页实现文字的逐个显现

目录 Blue留言&#xff1a; 效果图&#xff1a; 实现思路&#xff1a; 代码&#xff1a; 1、空字符串与需渲染的字符串的定义 2、vue的插值表达式 3、函数 4、mounted()函数调用 结语&#xff1a; Blue留言&#xff1a; 在国庆前夕&#xff0c;突发奇想&#xff0c;我想…

SAP HCM 自定义累计期间

需求是按3月&#xff5e;8月&#xff0c;9月&#xff5e;次年2月&#xff0c;做为累计期间&#xff0c;怎么处理&#xff1f;

微信小程序hbuilderx+uniapp+Android 新农村综合风貌旅游展示平台

目录 项目介绍支持以下技术栈&#xff1a;具体实现截图HBuilderXuniappmysql数据库与主流编程语言java类核心代码部分展示登录的业务流程的顺序是&#xff1a;数据库设计性能分析操作可行性技术可行性系统安全性数据完整性软件测试详细视频演示源码获取方式 项目介绍 小程序端…

5G NR coreset 简介

文章目录 5G 为何引入CORESETCORESET介绍CORESET 分类 5G 为何引入CORESET 在LTE系统中&#xff0c;PDCCH频域占据整个带宽&#xff0c;始于占据每个RB的前1~3个OFDM 符号&#xff0c;这种情况下&#xff0c;UE 只需知道PDCCH 所占据的OFDM 符号数&#xff0c;就可以确定PDCCH…

内存对齐

内存对齐的基本规则是&#xff1a;只能在自己所占字节的整数倍的内存地址上存放&#xff08;结构体也是如此&#xff09;。 假如定义一下变量&#xff1a; 对应的存储格式为&#xff1a; 由于变量C占四个字节&#xff0c;所以从12开始。 对于整个结构体而言&#xff1a;结构体…

【Web】portswigger 服务端原型污染 labs 全解

目录 服务端原型污染 为什么服务器端原型污染更难检测&#xff1f; 通过受污染的属性反射检测服务器端原型污染 lab1:通过服务器端原型污染进行权限提升 无需污染属性反射即可检测服务器端原型污染 状态代码覆盖 JSON 空格覆盖 字符集覆盖 lab2:检测没有污染属性反射的…

Pikachu-xss防范措施 - href输出 js输出

总体原则&#xff1a; 输入做过滤&#xff0c;输出做转义 过滤&#xff1a;根据业务需要进行过滤&#xff0c;如&#xff1a;输入点要求输入手机号&#xff0c;则只允许输入手机号格式的数字&#xff1b; 转义&#xff1a;所有输出到前端的数据&#xff0c;都根据输出点进行转…

银河麒麟V10如何快速进入单用户模式?

银河麒麟V10如何快速进入单用户模式&#xff1f; 1. 进入GRUB菜单2. 编辑启动项3. 登录系统4. 修改启动参数5. 退出单用户模式 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 银河麒麟高级服务器操作系统V10在系统维护或故障排查时&#xf…

70.【C语言】动态内存管理(重点)(3)

承接69.【C语言】动态内存管理(重点)(2)文章 目录 4.calloc函数 cplusplus网的翻译 提炼要点 使用 5.recalloc函数 使用说明 作用 调整内存空间的几种情况 1.原有空间之后有足够大的空间 2.原有空间之后没有足够大的空间 建议 代码 用recalloc函数来实现malloc函…

学习C语言(22)

整理今天的学习内容 1.常见的动态内存的错误 &#xff08;1&#xff09;对NULL指针进行解引用操作 &#xff08;2&#xff09;对动态开辟空间的越界访问 &#xff08;3&#xff09;对非动态开辟内存使用free释放 &#xff08;4&#xff09;使用free释放一块动态开辟内存的一部…

抖音巨量千川涨粉操作流程,值得学习

抖音巨量千川涨粉操作流程值得学习:rjxbb0616 1、找到抖音合作码&#xff08;在抖音APP里&#xff1a;我-右上角三条杠-设置-账号与安全-我的合作码&#xff09;复制合作码发给合作商。 2、合作商在千川平台上发布一个虚拟的热门作品到抖音&#xff0c;然后在千川账户建立目标账…

mysql连接池

MySQL连接池 什么是数据库连接池&#xff1f; ​ 定义&#xff1a;数据库连接池&#xff08;Connection pooling&#xff09;是程序启动时建立一定数量的数据库连接&#xff0c;并将这些连接组成 一个连接池&#xff0c;由程序动态地对池中的连接进行申请&#xff0c;使用&am…

HTML:相关概念以及标签

目录 什么是网页? 什么是HTML语言? 语法规范 HTML基本结构标签 DOCTYPE,lang以及字符集 HTML常用标签 5>图像标签(重要) 除此之外还有几个调整图片属性的标签 图像标签总结 什么是网页? 我们平时使用电脑和手机都是离不开网站和网页的,那么什么是网页呢?什么又是网…

Yolov8改进轻量级网络Ghostnetv2

1,理论部分 轻量级卷积神经网络 (CNN) 专为移动设备上的应用程序而设计,具有更快的推理速度。卷积运算只能捕获窗口区域中的局部信息,这会阻止性能进一步提高。将自我注意引入卷积可以很好地捕获全局信息,但会在很大程度上阻碍实际速度。在本文中,我们提出了一种硬件友好…

【技术分析】嘉楠科技SoC芯片K230

概述 K230是嘉楠科技Kendryte系列AIoT芯片中的最新一代SoC芯片&#xff0c;该芯片采用全新的多异构单元加速计算架构&#xff0c;集成的玄铁C908具有2个高能效RISCV计算核心&#xff0c;内置新一代KPU&#xff08;Knowledge Process Unit&#xff09;智能计算单元&#xff0c;…