使用 Mybatis 时,调用 DAO接口时是怎么调用到 SQL 的?

Mybatis 是一个流行的 Java 持久层框架,它提供了一种半自动的 SQL 映射方式,允许开发者在 Java 代码中以一种更加直观和灵活的方式来操作数据库。当你使用 Mybatis 调用 DAO 接口时,背后的工作流程大致如下:

  1. 接口定义:首先,你需要定义一个 DAO 接口,这个接口中会包含一些方法,这些方法对应于你想要执行的数据库操作。

  2. Mapper XML:对于 DAO 接口中的每一个方法,你需要在 Mybatis 的映射文件(通常是一个 XML 文件)中定义一个 <mapper> 标签,里面包含一个 <select><insert><update><delete> 标签,对应于你想要执行的 SQL 语句。

  3. 配置文件:在 Mybatis 的配置文件(通常是 mybatis-config.xml)中,你需要指定你的 Mapper XML 文件的位置,这样 Mybatis 才能找到并加载它们。

  4. SqlSessionFactory:Mybatis 使用 SqlSessionFactory 来创建 SqlSession 对象。SqlSessionFactory 是通过配置文件和映射文件构建的,它包含了所有必要的信息来执行 SQL 语句。

  5. SqlSession:SqlSession 是 Mybatis 中执行 SQL 语句的主要对象。它提供了执行 SQL 语句的方法,例如 selectOne、selectList、insert、update 和 delete 等。

  6. 调用 DAO 接口:当你调用 DAO 接口中的方法时,实际上是 Mybatis 的动态代理机制在起作用。Mybatis 会为 DAO 接口创建一个代理对象,当调用接口中的方法时,代理对象会拦截这些调用,然后根据方法名找到对应的 SQL 映射语句,并执行。

  7. 执行 SQL:Mybatis 通过代理对象,使用 SqlSession 来执行对应的 SQL 语句。执行完成后,SqlSession 会返回结果给调用者。

  8. 关闭 SqlSession:执行完毕后,应该关闭 SqlSession 以释放数据库连接资源。

这个过程涉及到了 Mybatis 的核心组件和工作流程,确保了 SQL 语句的执行和结果的返回。使用 Mybatis 的好处之一就是它允许开发者以一种声明式的方式来编写 SQL,同时还能保持代码的清晰和易于维护。

Mybatis 的内部实现细节非常丰富,下面我将通过一些关键类的源码片段来具体展示 Mybatis 的工作原理。

  1. 配置解析(XMLConfigBuilder.java)

Mybatis 使用 XMLConfigBuilder 来解析 mybatis-config.xml 文件:

public Configuration parse() {
    parseConfiguration(parser.eval(Configuration.class));
    return configuration;
}

这里,parseConfiguration 方法会填充 Configuration 对象的属性,比如数据库连接信息、类型别名、类型处理器等。
2. 创建 SqlSessionFactory(SqlSessionFactoryBuilder.java)

使用 XMLConfigBuilder 解析配置后,SqlSessionFactoryBuilder 会创建 SqlSessionFactory:

public SqlSessionFactory build(InputStream inputStream) {
    try {
        XMLConfigBuilder xmlParser = new XMLConfigBuilder(inputStream, environment, reporter);
        return build(xmlParser.parse());
    } catch (Exception e) {
        throw new BuilderException("Error building SqlSession.", e);
    }
}
  1. SqlSession 管理(DefaultSqlSessionFactory.java)

DefaultSqlSessionFactory 提供了创建 SqlSession 的方法:

public SqlSession openSession() {
    return openSessionFromDataSource(configuration.getEnvironment().getDataSource(), null, false);
}
  1. Executor 执行器(BaseExecutor.java)

BaseExecutor 是 Executor 接口的抽象实现,提供了事务和缓存管理的框架:

public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) {
    ErrorContext.instance().resource(ms.getResource()).activity("querying").object(ms.getId());
    if (closed) {
        throw new ExecutorException("Executor was closed.");
    }
    if (queryStack == 0 && ms.isFlushCacheRequired()) {
        clearLocalCache();
    }
    List<E> list;
    try {
        queryStack++;
        list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
        if (list != null && resultHandler != null) {
            resultHandler.handleRows(list);
        }
        if (list == null) {
            list = doQuery(ms, parameter, rowBounds, resultHandler, key, boundSql);
        }
    } finally {
        queryStack--;
    }
    return list;
}
  1. 动态代理(MapperProxy.java)

MapperProxy 使用 JDK 动态代理来拦截 Mapper 接口方法的调用:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if (Object.class.equals(method.getDeclaringClass())) {
        try {
            return method.invoke(this, args);
        } catch (Throwable t) {
            throw new RuntimeException("Error when attempting to invoke method '" +
                                      method.getName() + "' on Mapper Proxy.", t);
        }
    } else {
        return mapperMethod.execute(sqlSession, args);
    }
}
  1. 映射器 XML 解析(XMLMapperBuilder.java)

XMLMapperBuilder 负责解析 Mapper 的 XML 文件:

public void parse() {
    if (!configuration.isResourceLoaded(resource)) {
        configurationElement(parser.evalNode("mapper"));
        configuration.addLoadedResource(resource);
        bindMapperForNamespace();
    }
}
  1. 缓存机制(PerpetualCache.java)

PerpetualCache 是 Mybatis 缓存的基本实现:

public V get(Object key, CacheProvider provider) {
    V value = (V) cache.get(key);
    if (value == null) {
        value = provider.apply(key);
        cache.put(key, value);
    }
    return value;
}
  1. TypeHandler 和 ParameterHandler

TypeHandler 接口定义了 Java 类型和 JDBC 类型之间的转换逻辑:

public interface TypeHandler<T> {
    void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
    T getResult(ResultSet rs, int columnIndex) throws SQLException;
    T getResult(CallableStatement cs, int columnIndex) throws SQLException;
}

ParameterHandler 负责将方法参数映射到 SQL 语句的参数上:

public void setParameters(PreparedStatement ps) throws SQLException {
    for (ParameterMapping parameter : boundSql.getParameterMappings()) {
        if (parameter.getMode() != ParameterMode.OUT) {
            Object value = parameter.getObject(value);
            TypeHandler typeHandler = parameter.getTypeHandler();
            typeHandler.setParameter(ps, parameter.getI(), value, parameter.getJdbcType());
        }
    }
}
  1. 结果映射(DefaultResultSetHandler.java)

DefaultResultSetHandler 负责将 ResultSet 中的数据映射到 Java 对象:

public <E> List<E> handleRowValues(ResultSet rs, List<E> resultList, RowBounds rowBounds) throws SQLException {
    if (hasResultSetData(rs)) {
        int offset = rowBounds == null || rowBounds.getOffset() == RowBounds.NO_ROW_OFFSET ? 0 : rowBounds.getOffset();
        int limit = rowBounds == null || rowBounds.getLimit() == RowBounds.NO_ROW_LIMIT ? Integer.MAX_VALUE : rowBounds.getLimit();
        int rowNumber = 0;
        while (rs.next()) {
            if (offset > 0) {
                offset--;
                continue;
            }
            if (limit > 0) {
                limit--;
                if (limit == 0) {
                    break;
                }
            }
            Object rowValue = getRowValue(rs, null);
            resultList.add((E) rowValue);
            rowNumber++;
        }
    }
    return resultList;
}

这些代码片段展示了 Mybatis 核心组件的工作原理。然而,由于 Mybatis 的复杂性,这里只提供了部分关键代码的简要概述。要完全理解 Mybatis 的内部实现,需要深入研究每个类和接口的实现细节,以及它们之间的交互。关注威哥爱编程,一起向全栈出发。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Keysight 是德 EXR104A 实时示波器

Keysight 是德 EXR104A 实时示波器 全部 4 个通道均可提供 1 GHz 的带宽&#xff0c;强大的 8 合 1 仪器&#xff0c;出色的硬件加速绘图功能&#xff0c;可以全面升级到 2.5 GHz 带宽和 8 个通道 全部 4 个模拟通道上均可提供 1 GHz 带宽通过 ASIC 技术实现更快的测试速度有…

项目范围管理(信息系统项目管理师)

需求管理计划是对项目的需求进行定义、确定、记载、核实管理和控制的行动指南。制定需求管理计划&#xff0c;规划如何分析、记录和管理需求&#xff0c;这样才是较为稳妥的方法在信息系统集成项目中&#xff0c;需求管理贯穿于整个过程&#xff0c;他的最基本的任务就是明确需…

破解电脑卡顿难题,将数据优化,5分钟提升运行速度

当电脑变得缓慢且反应迟钝时&#xff0c;工作效率和娱乐体验都会大打折扣。而电脑卡顿是由于系统资源占用过多、磁盘空间不足等原因引起的。因此&#xff0c;我们经常需要寻找优化措施&#xff0c;提升电脑的运行速度。文章整理了4个优化方法&#xff0c;帮助你破解卡顿难题&am…

Linux下编程之内存检查

前言 我们在进行编程时&#xff0c;有时不免会无意中写出一些容易导致内存问题&#xff08;可能一时表象上正常&#xff09;的代码&#xff0c;导致的后果肯定是不好的&#xff0c;就像一颗颗“哑弹”&#xff0c;令人心慌。网上推荐的辅助工具很多&#xff0c;此篇文章…

机器学习——强化学习中的“策略π”的个人思考

这两天回顾了《西瓜书》中的最后一章——“强化学习”&#xff0c;但是忽然发现之前对于本章中的“策略π”的理解有些偏差&#xff0c;导致我在看值函数公式时有些看不明白。对此&#xff0c;我在网上查了一些资料&#xff0c;但是大部分人都是一笔带过&#xff0c;或者是照本…

Day8: 232.用栈实现队列 225. 用队列实现栈 20. 有效的括号 1047. 删除字符串中的所有相邻重复项

题目232. 用栈实现队列 - 力扣&#xff08;LeetCode&#xff09; class MyQueue { public:MyQueue() {}void push(int x) { // 出栈input.push(x);}int pop() {// 如果出栈为空&#xff0c;把入栈元素全都转移到出栈if (output.empty()) {while (!input.empty()) {int itop i…

基于小波同步压缩变换与集成深度学习的情绪识别

摘要 本研究设计了一种基于小波同步压缩变换(WSST)驱动优化集成深度学习(DL)的自动多类情绪识别(AMER)系统&#xff0c;用于识别样本依赖(subject-dependent)和样本独立(subject-independent)两种模式下的人类情感。使用WSST方法将1-D脑电(EEG)信号转换为2-D时频表征(TFR)&…

2024年6月总结及随笔之打卡网红点

1. 回头看 日更坚持了547天。 读《人工智能时代与人类未来》更新完成读《AI未来进行式》开更并更新完成读《AI新生&#xff1a;破解人机共存密码》开更并持续更新 2023年至2024年6月底累计码字1267912字&#xff0c;累计日均码字2317字。 2024年6月码字90659字&#xff0c;…

hadoop分布式云笔记系统-计算机毕业设计源码15725

摘 要 随着信息技术的飞速发展&#xff0c;人们对于数据的存储、管理和共享需求日益增长。传统的集中式存储系统在处理大规模数据时面临着性能瓶颈和扩展性问题。而 Hadoop 作为一种分布式计算框架&#xff0c;为解决这些问题提供了有效的解决方案。 本研究旨在设计并实现一种…

昇思25天学习打卡营第6天|关于函数与神经网络梯度相关技术探讨

目录 Python 库及 MindSpore 相关模块和类的导入 函数与计算图 微分函数与梯度计算 Stop Gradient Auxiliary data 神经网络梯度计算 Python 库及 MindSpore 相关模块和类的导入 Python 中的 numpy 库被成功导入&#xff0c;并简称为 np。numpy 在科学计算领域应用广泛&#x…

2、SSD基本技术

发展史 上文中说SSD是以闪存为介质的存储设备&#xff0c;这只能算是现代SSD的特点&#xff0c;而不能算是定义。 HDD是磁存储&#xff0c;SSD是电存储&#xff1b;HDD的特点导致寻址到不同扇区其性能存在明显差异&#xff0c;比如寻址下个扇区和上个扇区&#xff1b;而SSD寻…

SpringBoot学习06-[SpringBoot与AOP、SpringBoot自定义starter]

SpringBoot自定义starter SpringBoot与AOP SpringBoot与AOP 使用AOP实现用户接口访问日志功能 添加AOP场景启动器 <!--添加AOP场景启动器--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</…

第十四届蓝桥杯省赛C++A组F题【买瓜】题解(AC)

70pts 题目要求我们在给定的瓜中选择一些瓜&#xff0c;可以选择将瓜劈成两半&#xff0c;使得最后的总重量恰好等于 m m m。我们的目标是求出至少需要劈多少个瓜。 首先&#xff0c;我们注意到每个瓜的重量最多为 1 0 9 10^9 109&#xff0c;而求和的重量 m m m 也最多为…

3.2ui功能讲解之graph页面

本节重点介绍 : graph页面target页面flags页面status页面tsdb-status页面 访问地址 $ip:9090 graph页面 autocomplete 可以补全metrics tag信息或者 内置的关键字 &#xff0c;如sum聚合函数table查询 instante查询&#xff0c; 一个点的查询graph查询调整分辨率 resolutio…

中原汉族与北方游牧民族舞蹈文化在这段剧中表现得淋漓尽致,且看!

中原汉族与北方游牧民族舞蹈文化在这段剧中表现得淋漓尽致&#xff0c;且看&#xff01; 《神探狄仁杰》之使团喋血记是一部深入人心的历史侦探剧&#xff0c;不仅以其曲折离奇的案情和狄仁杰的睿智形象吸引观众&#xff0c;更以其对唐代文化的精准再现而备受赞誉。#李秘书讲写…

云计算【第一阶段(23)】Linux系统安全及应用

一、账号安全控制 1.1、账号安全基本措施 1.1.1、系统账号清理 将非登录用户的shell设为/sbin/nologin锁定长期不使用的账号删除无用的账号 1.1.1.1、实验1 用于匹配以/sbin/nologin结尾的字符串&#xff0c;$ 表示行的末尾。 &#xff08;一般是程序用户改为nologin&…

JavaScript——对象的创建

目录 任务描述 相关知识 对象的定义 对象字面量 通过关键字new创建对象 通过工厂方法创建对象 使用构造函数创建对象 使用原型(prototype)创建对象 编程要求 任务描述 本关任务&#xff1a;创建你的第一个 JavaScript 对象。 相关知识 JavaScript 是一种基于对象&a…

Spring Boot配置文件properties/yml/yaml

一、Spring Boot配置文件简介 &#xff08;1&#xff09;名字必须为application,否则无法识别。后缀有三种文件类型&#xff1a; properties/yml/yaml&#xff0c;但是yml和yaml使用方法相同 &#xff08;2&#xff09; Spring Boot 项⽬默认的配置文件为 properties &#xff…

kafka线上问题:rebalance

我是小米,一个喜欢分享技术的29岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货! 大家好,我是小米。今天,我们来聊聊一个在大数据处理领域常见但又令人头疼的问题——Kafka消费组内的重平衡(rebalance)。这可是阿里巴巴面试中的经…

惠海 H6912 升压恒流芯片IC 支持2.6-40V升12V24V36V48V60V100V 10A 摄影灯 太阳能灯 UV灯 杀菌灯

1.产品描述 H6912是一款外围电路简洁的宽调光比升压调光LED恒流驱动器&#xff0c;可适用于2.6-40V输入 电压范围的LED恒流照明领域。H6912可以实现高精度的恒流效果&#xff0c;输出电流恒流精度≤士3%&#xff0c;电压工作范围为2.6-40V.可以轻松满足锂电池及中低压的应用需…