MyBatis 持久层框架详细解读:Mapper代理开发

news2024/11/17 11:46:08

文章目录

  • 1. 前言
  • 2. Mapper 代理开发
  • 3. 过程剖析
  • 4. 总结

1. 前言

前面在 MyBatis 快速入门篇中,我们使用了 MyBatis 原生的开发方式操作数据库,解决了 JDBC 操作数据库时的硬编码和操作繁琐的问题。实际上,在 Java 项目中,我们更常用的是 Mapper 代理开发的方式。

image-20230126233131746

两种方式有什么不同呢?

前面在使用基本方式操作数据库时,我们使用 sqlSession 原生的方法 selectList 执行 sql 语句并处理结果集对象。示例:

List<Student> students = sqlSession.selectList("test.selectAll"); //参数是一个字符串,该字符串必须是映射配置文件的 namespace.id

该方法的参数必须是 sql 映射配置文件的 name.id ,并且是以字符串的方式传递给该方法,于是这里又出现了硬编码的问题,而且这里使用 id 的方式也不是一种方便的设计,因为我们在编码时还需要在对应的映射配置文件中寻找 id,于是出现了 Mapper 代理开发的方式来解决这个问题。

在使用 Mapper 代理开发方式操作数据库时,通过 SqlSession 类对象获取一个指定 Mapper 接口的 Mapper 代理对象,使用该代理对象就可以调用对应 Mapper 接口中的方法,而这个方法就与映射配置文件中的 id 对应,从而找到了 sql 并执行,最后处理结果集对象。示例:

//3. 执行sql
//3.1 获取StudentMapper接口的代理对象
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
List<Student> students = studentMapper.selectAll();

总的来说,Mapper 代理方式具有以下两个优点:

  • 解决了原生方式中硬编码的问题
  • 简化了后期执行 sql

2. Mapper 代理开发

从上面的例子中不难看出,使用 Mapper 代理的方式具有更多的优势,首先他不依赖于字符串的字面值,会更加的方便和安全。其次,如果你的 IDE 有代码自动补全的功能,那么它可以帮你快速的是选择映射文件的 sql 语句,而不依赖于对应的 id。

使用 Mapper 代理开发的方式,必须执行以下几个步骤:

  1. 定义与 sql 映射配置文件同名的 Mapper 接口,并将 Mapper 接口和 sql 映射配置文件防止在同一目录下
  2. 设置 sql 映射文件的 namespace 属性为 Mapper 接口的全限定名
  3. 在 Mapper 接口中定义方法,方法名就是 sql 映射文件中的sql语句的 id,并保持参数类型和返回值类型相同

下面通过案例了解 Mapper 代理开发的方式的过程,案例依然是使用入门篇中的查询学生信息,并封装为对象,存放在集合中。

第一步

org.chengzi.mapper 包下创建 StudentMapper,示例:

public interface StudentMapper {
    List<Student> selectAll();
    Student selectById(int id);
}

在 resources 下创建 org / chengzi / mapper 目录,并在该文件目录下创建 StudentMapper.xml 配置文件。这样做保证了 Mapper 接口和 sql 映射配置文件在同一文件目录下。

第二步:设置 sql 映射文件的 namespace 属性和 Mapper 接口的全限定名一致。示例:

<!--
    namespace:名称空间。必须是对应接口的全限定名
-->
<mapper namespace="org.chengzi.mapper.StudentMapper">
    <select id="selectAll" resultType="org.chengzi.pojo.User">
        select *
        from student;
    </select>
</mapper>

第三步:在 MyBatis 核心配置文件中加载 sql 映射配置文件,示例:

<mappers>
      <!--加载sql映射文件-->
      <mapper resource="org/chengzi/mapper/StudentMapper.xml"/>
</mappers>

注意:后面两步使用 / 作为文件路径分隔符

完成上面三步我们就可以编写测试代码来操作数据库,完成相关操作。示例:

public class MyBatisDemo2 {

    public static void main(String[] args) throws IOException {

        //1. 加载mybatis的核心配置文件,获取 SqlSessionFactory
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2. 获取SqlSession对象,用它来执行sql
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //3. 执行sql
        //3.1 获取StudentMapper接口的代理对象
        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> students = studentMapper.selectAll();

        System.out.println(students);
        //4. 释放资源
        sqlSession.close();
    }
}

运行结果:

image-20230128201911101

不同于 MyBatis 的基本方法,这里我们通过 sqlSession 对象对应的方法获取了 StudentMapper 接口的代理对象,使用该代理对象执行 sql 语句,封装结果集对象。返回代理对象的过程由MyBatis内部完成。

小 tips:在 MyBatis 核心配置文件中加载 sql 映射配置文件时,如果 sql 映射配置文件数量较多时,这个步骤也是比较麻烦的,MyBatis 也提供了解决这个问题的方法。

如果 Mapper 接口名称和 sql 映射文件名称相同,并在同一目录下,则可以使用包扫描的方式简化 sql 映射文件的加载,只需要在核心配置文件中将加载 sql 映射配置文件的部分修改为:

<mappers>
    <!--加载sql映射文件-->
    <!-- <mapper resource="org/chengzi/mapper/UserMapper.xml"/>-->
    <!--Mapper代理方式-->
    <package name="org.chengzi.mapper"/>
</mappers>

3. 过程剖析

在使用 Mapper 代理开发时,我们通过 SqlSessionFactory 类的 openSession() 方法获取了 SqlSession 类对象,接着通过 SqlSession 类对象获取指定 Mapper接口的 Mapper 代理对象。

在获取 Mapper 代理对象时,我们可以找到对应的 Mapper 接口,在同一个目录下可以找到对应的与该接口同名的 sql 映射文件。使用代理对象调用对应Mapper接口中的方法,该方法对应着 sql映射配置文件中的 id 属性,通过 id 属性可以找到 对应的 sql 语句,进而执行了sql语句并封装结果集对象。

例如在上面案例中,studentMapper 代理对象执行了 selectAll() 方法,返回 List 对象,其实其底层还是执行了下面的语句:

 List<User> users = sqlSession.selectList("test.selectAll"); 

4. 总结

使用 MyBatis 原生方式开发,部分过程依赖于字符串常量值,存在硬编码的问题,同时使用命令空间和 sql 唯一标识作为执行 sql 的参数,在编写代码时比较麻烦。使用 Mapper 代理的方式具有更多的优势,首先他不依赖于字符串的字面值,会更加的方便和安全。其次,如果你的 IDE 有代码自动补全的功能,那么它可以帮你快速的是选择映射文件的 sql 语句,而不依赖于对应的 id。

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

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

相关文章

MVC和MVVM的区别

一、MVC mvc&#xff1a;是一种代码架构设计模式&#xff0c;前端中的mvc最主要的作用就是将视图和数据模型进行分离 &#xff08;1&#xff09; 为什么需要 MVC 简单理解&#xff1a;也就是为什么需要将视图和数据模型进行分离 <select id"drinkSelect">&…

宕机后,如何避免 Redis 的数据丢失?

前言 如果有人问你&#xff1a;"你会把 Redis 用在什么业务场景下&#xff1f;" 我想你大概率会说&#xff1a;"我会把它当作缓存使用&#xff0c;因为它把后端数据库中的数据存储在内存中&#xff0c;然后直接从内存中读取数据&#xff0c;响应速度会非常快。…

Lua 文件I/O

Lua 文件I/O 参考至菜鸟教程。 Lua I/O 库用于读取和处理文件。分为简单模式&#xff08;和C一样&#xff09;、完全模式。 简单模式&#xff08;simple model&#xff09;拥有一个当前输入文件和一个当前输出文件&#xff0c;并且提供针对这些文件相关的操作。完全模式&#…

C++Primer13.6.2节练习

练习13.49&#xff1a; StrVec类的移动构造函数和移动赋值运算符 //移动构造函数 StrVec::StrVec(StrVec&& s)noexcept :elements(s.elements), first_free(s.first_free), cap(s.cap) {//令移后源对象进入状态-----对其运行析构函数是安全的s.elements s.first_fre…

关于网络编程

Socket套接字Socket API是网络编程最核心的部分。Socket套接字是由系统提供用于网络通信的技术&#xff0c;是基于TCP/IP协议的网络通信的基本操作单元。基于Socket套接字的网络程序开发就是网络编程。Socket API与传输层密切相关&#xff0c;由于传输层有UDP和TCP两种协议类型…

使用Idea中将单个java类打包成jar包

开工第一天&#xff0c;正在暗自爽&#xff0c;领导让帮个忙&#xff0c;给一个工具类打成jar包&#xff0c;供其他项目组使用&#xff0c;这就开始了尝试。 其实网上已经有好多人写过了&#xff0c;只是尝试了几篇&#xff0c;坑得不轻&#xff0c;自己做下笔记&#xff0c;留…

表格控件Aspose.Cells for .NET 授权须知

支持的平台 Aspose.Cells 可作为 .NET、Java、C 和 Python 的四种不同产品使用&#xff0c; .NET Framework.NET Standard 2.0Xamarin.AndroidXamarin.iOSXamarin.MacCOMMonoWindows Azure Aspose.Cells 下载&#xff08;qun&#xff1a;761297826&#xff09;https://www.ev…

python 高阶函数

传入函数 要理解“函数本身也可以作为参数传入”&#xff0c;可以从Python内建的map/reduce函数入手。 我们先看map。map()函数接收两个参数&#xff0c;一个是函数&#xff0c;一个是序列&#xff0c;map将传入的函数依次作用到序列的每个元素&#xff0c;并把结果作为新的l…

Java:基于注解的Spring使用【AOP容器】和事务管理

目录 第十五章 AOP前奏15.1 代理模式15.2 为什么需要代理【程序中】15.3 手动实现动态代理环境搭建15.4 手动实现动态代理关键步骤第十六章 Spring中AOP【重点】16.1 AspectJ框架【AOP框架】16.2 使用AspectJ步骤&#xff08;入门&#xff09;16.3 Spring中AOP概述16.4 Spring中…

AMQP 0-9-1 模型解释

官方文档链接&#xff1a;https://www.rabbitmq.com/tutorials/amqp-concepts.html 文章目录1. AMQP协议是什么2. AMQP模型2.1 工作过程2.2 深入理解3. 交换机3.1 默认交换机3.2 直连交换机3.3 扇形交换机3.4 主题交换机3.5 头交换机3.6 交换机小结4. Queue队列队列属性队列创建…

BM7 链表中环的入口结点

目录 描述 输入描述&#xff1a; 返回值描述&#xff1a; 示例1 示例2 示例3 思路&#xff1a; 代码 描述 给一个长度为n链表&#xff0c;若其中包含环&#xff0c;请找出该链表的环的入口结点&#xff0c;否则&#xff0c;返回null。 例如&#xff0c;输入{1,…

DW 2023年1月Free Excel 第九次打卡 Excel数据透视

第九章 Excel数据透视 数据下载地址与参考链接&#xff1a;https://d9ty988ekq.feishu.cn/docx/Wdqld1mVroyTJmxicTTcrfXYnDd 数据透视是Excel中个强大的数据处理和分析工具&#xff0c;能够快速实现数据的汇总与统计分析&#xff0c;本节重点讲解Excel数据透视的相关操作。 1…

NSSCTF Round#7 Team ez_rce和0o0讲解

强烈建议NSSCTF延长时间&#xff0c;大过年的逛亲戚回来就剩两个小时了。。。。 ez_rce <!-- A EZ RCE IN REALWORLD _ FROM CHINA.TW --> <!-- By 探姬 --> <?PHPif(!isset($_POST["action"]) && !isset($_POST["data"]))show_s…

MySQL8中jdbc的url设置

JDBC spring.datasource.urljdbc:mysql://${MYSQL_HOST:localhost}:3306/xxxx?sslModeREQUIRED&characterEncodingUTF-8&connectionTimeZoneGMT%2B8&forceConnectionTimeZoneToSessiontruesslMode:设置为REQUIRED表示必须启用ssl加密传输&#xff1b;characterEn…

svn客户端add无法添加上子文件夹及其子文件——解决办法

1、问题描述 svn客户端add文件夹后&#xff0c;无法添加上子文件夹及其子文件&#xff0c;需要先add最外层文件夹&#xff0c;再逐层add子文件夹&#xff0c;最后add最里层子文件夹中的文件&#xff0c;很影响add速度啊。现象如下图所示&#xff1a; 正常情况下&#xff0c;add…

公派访问学者申请优势有哪些?

人的一生&#xff0c;若从职业生涯论&#xff0c;无非为官、为学、为商三条路。为官者&#xff0c;出国访学一年半载&#xff0c;对仕途并无太大作用&#xff0c;并且在此期间有可能丧失国内提拔的大好机会;为学者&#xff0c;公派访问学者是对学术水平的认可&#xff0c;并且对…

vue.js 实现导入json解析成动态el-table树表格(接口文档功能)

一、需求描述&#xff1a;前段时间接到一个需求是做一个类似接口文档的显示功能&#xff0c;将一段json数据贴到里面就可以自动解析出json数据的每个字段的类型和层级关系&#xff0c;用element组件的树表格的形式展示&#xff0c;并且可以手动新增、修改和删除某个数据字段。二…

Vue路由和路由器简介

前言 路由(route)是vue中非常重要的技术&#xff0c;几乎每一个用vue所写的项目都会用到路由&#xff0c;它是一个vue的插件库&#xff0c;专门实现SPA应用 路由(route)的简介 说到路由&#xff0c;大多数人会想到路由器(router),可以这么说&#xff0c;路由器上的每一个口都…

Python类变量和实例变量

类变量&#xff08;类属性&#xff09;类变量指的是在类中&#xff0c;但在各个类方法外定义的变量。举个例子&#xff1a;class CLanguage : # 下面定义了2个类变量name "CSDN社区"add "http://csdn.net" # 下面定义了一个say实例方法 defsay(self, conte…

【Linux】进程信号的产生与捕捉、核心转储

目录 一、信号的引入 二、信号捕捉 三、核心转储 四、系统调用发送信号 五、软件条件产生信号 六、硬件异常产生信号 一、信号的引入 Linux信号本质是一种通知机制&#xff0c;用户 or 操作系统通过发送一定的信号&#xff0c;通知进程&#xff0c;某些事件已经发生&…