返回顶部
首页 > 资讯 > 精选 >MyBatis中Mapper生效的示例分析
  • 881
分享到

MyBatis中Mapper生效的示例分析

2023-06-20 20:06:46 881人浏览 泡泡鱼
摘要

小编给大家分享一下mybatis中Mapper生效的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一、MyBatis基本使用一切都从最简单的开始,所以先来

小编给大家分享一下mybatis中Mapper生效的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

一、MyBatis基本使用

一切都从最简单的开始,所以先来回顾一下其基本的使用(不会吧不会吧,最基本的hello world别忘了)。

步骤:

首先我们要创建一个Maven工程

添加MyBatis的依赖及MySQL依赖,如下:

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --><dependency>    <groupId>org.mybatis</groupId>    <artifactId>mybatis</artifactId>    <version>3.5.6</version></dependency><dependency>    <groupId>Mysql</groupId>    <artifactId>mysql-connector-java</artifactId>    <version>5.1.49</version></dependency>

再添加一个测试单元依赖吧,等会要通过测试单元进行测试

<dependency>    <groupId>junit</groupId>    <artifactId>junit</artifactId>    <version>4.12</version></dependency>

OK,到这一步项目的基本环境就搭建完毕了,下面就是正式的使用 MyBatis 框架相关的内容了。

1.1 编写配置文件

在资源目录下面创建下面两个配置文件:

这里我们先准备数据库连接信息的配置类:jdbc.properties

jdbc.driver=com.mysql.jdbc.Driverjdbc.url=jdbc:mysql://127.0.0.1:3306/mybatistest?useUnicode=true&amp;characterEncoding=utf-8jdbc.username=rootjdbc.passWord=root

接着就是最重要的一个配置类了:MyBatisConfig.xml

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configuration    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"    "Http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration>    <!-- 导入数据库配置文件的信息-->    <properties resource="jdbc.properties"></properties>    <!-- 配置setting属性-->    <settings>        <!-- 开启了一个驼峰命名规则-->        <setting name="mapUnderscoreToCamelCase" value="true"/>        <!-- 日志-->        <setting name="logImpl" value="STDOUT_LOGGING"></setting>    </settings>    <!-- 配置数据库-->    <environments default="development">        <environment id="development">            <transactionManager type="JDBC"/>            <!-- 配置连接池 -->            <dataSource type="POOLED">                <property name="driver" value="${jdbc.driver}"/>                <property name="url" value="${jdbc.url}"/>                <property name="username" value="${jdbc.username}"/>                <property name="password" value="${jdbc.password}"/>            </dataSource>        </environment>    </environments>    <!--  mappers中注册我们所有写的dao接口的实现(映射)文件-->    <mappers>        <mapper resource="/.../IUserMapper.xml"/>        <!-- 如果映射文件有十几百个的话,可以用下面的全局注册    <package name="文件所在包路径"></package>    <package name="cn.liuliang.Dao"></package>    -->    </mappers></configuration>

1.2 编写Mapper接口及测试方法

Mapper接口类

public interface IUserMapper {         List<User> findAll();}

开始测试

public class MyBatisTest {    @Test    public void test01() throws IOException {        // 读取配置文件        InputStream in= Resources.getResourceAsStream("MyBatisConfig.xml");        // 创建sqlSessionFactory        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);        // 获得会话        SqlSession session=sqlSessionFactory.openSession();        // 得到代理        IUserMapper iUserMapper =session.getMapper(IUserMapper.class);        // 查询数据库        List<User> userList= iUserMapper.findAll();        for (User user : userList) {            System.out.println(user);        }    }}

1.3 结果

MyBatis中Mapper生效的示例分析

SQL和结果都打印出来了?。

以后,只要是对数据库的操作,我们就只需要编写 Mapper 接口和其对应的 xml 文件就可以非常快速操作数据库,对比以前原生JDBC操作什么拼接SQL、结果集映射、资源关闭一大堆操作让我们开发人员来处理,也太鸡肋了吧!所以对于这个 MyBatis 持久层框架我只想说(牛逼)。

下面就要全程高能哦!但其实也很简单了,它就只是把原生操作的 JDBC 进行了封装,暴露出按照它所定义的简单规则走而已,多的不说了,你们有资格一睹 MyBatis 源码的芳容了。

MyBatis中Mapper生效的示例分析

二、源码分析

既然要分析源码了,那么从什么地方入手呢!— 测试方法

通过测试方法,我们可以知道 MyBatis 会先加载资源文件(MyBatisConfig.xml),因为这文件是一切的开始,通过这个文件可以知道数据源、特性(日志,驼峰命名…)、Mapper 文件等一系列信息。

2.1 通过配置文件构建出 SqlSessionFactory

第一个类名出现了:SqlSessionFactory ,它的类图如下:

MyBatis中Mapper生效的示例分析

简单熟悉一下图中出现的名字吧:

SqlSessionFactory接口:SqlSessionFactory 负责创建 SqlSession 对象,其中只包含了多个 openSession() 方法的重载,可以通过其参数指定事务的隔离级别、底层使用 Executor 的类型以及是否自动提交事务等方面的配置。

DefaultSqlSessionFactory类:一个具体的工厂,实现了 SqlSessionFactory 接口。它主要提供了两种创建 DefaultSqlSession 对象的方式:

  1. 通过数据源获取数据库连接,并创建 Executor 对象及 DefaultSqlSession 。

  2. 通过用户提供的数据连接对象,DefaultSqlSessionFactory 会使用该数据库连接对象创建 Executor 对象及 DefaultSqlSession。

SqlSessionManager类:同时实现了 SqlSession 接口和 SqlSessionFactory 接口 ,也就同时提供了SqlSessionFactory 创建 SqlSession 以及 SqlSession 操纵数据库的功能。

SqlSession接口:是mybatis的核心操作类,其中对数据库的crud都封装在这个中,是一个顶级接口,其中默认实现类是DefaultSqlSession这个类。

  • DefaultSqlSession类:默认 SqlSession 接口的 CRUD 实现类,且 DefaultSqlsession 不是线程安全的(对于线程安全,关注session和connnect的关系就好了)

好了开始分析,从第一行代码入手:

// 读取配置文件InputStream in= Resources.getResourceAsStream("MyBatisConfig.xml");// 创建sqlSessionFactorySqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);

SqlSessionFactoryBuilder # build

public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {    // ...    // 根据文件流,创建 XMLConfigBuilder 对象    XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);    // 先解析 配置文件,然后构建出 SqlSessionFactory对象    return build(parser.parse());    // ...}

最终会创建一个 DefaultSqlSessionFactory 对象返回出去

public SqlSessionFactory build(Configuration config) {    return new DefaultSqlSessionFactory(config);}

流程如下:

MyBatis中Mapper生效的示例分析

2.2 获取 SqlSession 对象

在获取到会话工厂之后,就是根据工厂获得具体的会话了。

代码入口:

// 获得会话SqlSession session=sqlSessionFactory.openSession();

调用:DefaultSqlSessionFactory # openSession()

public SqlSession openSession() {  return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);}

最终来到:DefaultSqlSessionFactory # openSessionFromDataSource()

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {    Transaction tx = null;    try {        // 根据配置文件 configuration 获取对应的会话环境(包括事物,数据源)        final Environment environment = configuration.getEnvironment();        // 获取事物工厂        final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);        // 根据数据源,配置事物,autoCommit:是否自动提交事物        tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);        // 根据配置获取执行器(最终都是它执行对应的数据库操作)        final Executor executor = configuration.newExecutor(tx, execType);        // 准备好上面的信息之后,都封装到默认会话对象中返回出去        return new DefaultSqlSession(configuration, executor, autoCommit);    } catch (Exception e) {        closeTransaction(tx); // may have fetched a connection so lets call close()        throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);    } finally {        ErrorContext.instance().reset();    }}

在获取 SqlSession 对象的过程中,都是根据默认的会话工厂,从工厂中获取对应的会话。这样在我看来非常的不错,因为获取一个数据库的操作会话是需要配置非常多的属性的,包括数据源配置、事物配置等。但是有了这个创建会话工厂类之后,那么一切就变得简单起来了,工厂囊括了所有的细节,只需要我们调一个对外的 api 我们就可以获得对应的 SqlSession 对象(工厂帮我们做了细节),进而操作数据库,读了上面的代码就是一个很好的提现?。

提一点:

配置文件(MyBatisConfig.xml)构造出默认会话工厂(SqlSessionFactory),工厂再创建出具体的操作数据库会话(SqlSession)

2.3 根据 SqlSession 获取 Mapper 代理

在上面,已经分析了如何获取一个会话的源码,那我们得到一个会话之后,就是要根据具体的 Mapper 接口获得对应的操作数据库代理对象了,就是下面这段代码:

// 得到代理IUserMapper iUserMapper =session.getMapper(IUserMapper.class);

点进去看看

因为 session 对象是由 DefaultSqlSessionFactory 创建出来的 DefaultSqlSession,所以该代码位于此类中

public <T> T getMapper(Class<T> type) {    // 根据配置类,获取 Mapper     return configuration.getMapper(type, this);}

点进去:Configuration # getMapper

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {    // 从 mapperReGIStry 中获取具体 Mapper    return mapperRegistry.getMapper(type, sqlSession);}

MapperRegistry:可以理解为 Mapper 接口的注册中心,里面存放了所有 Mapper 接口相关属性。

MapperRegistry# getMapper

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {    // knownMappers,一个Map,存放 Mapper 代理工厂    // 在初始化的时候根据配置文件已经将所有配置的 Mapper 接口注册到此了    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);    if (mapperProxyFactory == null) {        throw new BindingException("Type " + type + " is not known to the MapperRegistry.");    }    try {        // 具体代理生成        return mapperProxyFactory.newInstance(sqlSession);    } catch (Exception e) {        throw new BindingException("Error getting mapper instance. Cause: " + e, e);    }}

点进具体代理:MapperProxyFactory # newInstance

public T newInstance(SqlSession sqlSession) {    // 根据 SqlSession 和 Mapper 接口生成代理对象    final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);    // 真正代理,如下    return newInstance(mapperProxy);}// 下面就是根据 jdk 原生 API 进行代理了,由此返回代理对象给用户使用protected T newInstance(MapperProxy<T> mapperProxy) {    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);}

以上就是 Mapper 接口被代理的全部流程了,其中先是根据会话去获得对应的 Mapper 但其内部调用的是 Mapper 注册中心(MapperRegistry)获取,这里面有所有配置的 Mapper 接口,在 MapperRegistry 中维护了一个 Map 键为 Class 值是 MapperProxyFactory ,这样就可以获得要代理 Mapper 接口的代理工厂,最后通过这个工厂生成我们想要的 Mapper 返回用户。

流程不复杂,就是里面出现了很多 MapperXXX 相关的类,那么下面我梳理一下这些类关系图如下:

MyBatis中Mapper生效的示例分析

对于具体的代理执行类这一步就要到执行这一块了,当用户通过我们返回的代理类(Mapper 接口)执行对应方法时,就会走到图中涉及的类。

按照惯例,来个流程图吧!

MyBatis中Mapper生效的示例分析

2.4 通过 Mapper 代理,执行方法操作数据库

上面的所有分析,都是为了等到一个具体的操作数据库的一个桥梁,那就是 Mapper 代理了(iUserMapper)。

接下来就是分析最后一步了,真正操作数据库,代码如下:

// 查询数据库List<User> userList= iUserMapper.findAll();for (User user : userList) {    System.out.println(user);}

对于 iUserMapper 对象,我们知道他是代理去执行的,所以直接点进去的话根本行不通,那么我们可以通过 Debug 进去看看。

MyBatis中Mapper生效的示例分析

MapperProxy # invoke

@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {    try {        // 方法的类为 object 直接通过原始 JDK 去执行        if (Object.class.equals(method.getDeclarinGClass())) {            return method.invoke(this, args);        } else {            // 根据方法,获得方法的执行器后再执行代理方法            return cachedInvoker(method).invoke(proxy, method, args, sqlSession);        }    } catch (Throwable t) {        throw ExceptionUtil.unwrapThrowable(t);    }}

我们先进入 MapperProxy # cachedInvoker 这个方法看看

private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {    try {        // 先查缓存,有就返回,没有就创建        MapperMethodInvoker invoker = methodCache.get(method);        if (invoker != null) {            return invoker;        }        return methodCache.computeIfAbsent(method, m -> {            // ...            // 返回 PlainMethodInvoker 类型的 Mapper 方法执行器            return new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));            // ...        });    } catch (RuntimeException re) {        Throwable cause = re.getCause();        throw cause == null ? re : cause;    }}

接着进入 PlainMethodInvoker# invoke 这个方法

public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {    // 调用 mapperMethod 对象的 execute 方法去真正执行了    return mapperMethod.execute(sqlSession, args);}

真正执行的开始 execute

MapperMethod # execute

public Object execute(SqlSession sqlSession, Object[] args) {    // 这里面内容比较多,我简单分析一下    // 1)封装参数    // 2)根据对应的执行类型(INSERT,UPDATE,DELETE,SELECT),执行对应的方法    // 3)根据参数,执行类型封装对应的 sql    // 4)操作原生 JDBC API 执行数据库操作    // 5)封装结果集,返回出去}

我们 Debug 这个方法最后一步,看看结果:

MyBatis中Mapper生效的示例分析

到此,我们的 Mapper 接口及文件生效的原理,就全部过了一边,是不是觉得不是很难呢!

在分析这一块源码时,本人理解的步骤就是:

  • 一步步点进源码看。

  • 画出流程图,不清楚的就 Debug。

  • 很重要一点,对很多出现类似名字的类,一定要画出类图,搞清楚关系在往下走(助于理解每个类的职责)。

  • 最后,那就是写点笔记了,毕竟好记性不如烂笔头。

2.5 整体流程图

MyBatis中Mapper生效的示例分析

以上是“MyBatis中Mapper生效的示例分析”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网精选频道!

--结束END--

本文标题: MyBatis中Mapper生效的示例分析

本文链接: https://lsjlt.com/news/299984.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • MyBatis中Mapper生效的示例分析
    小编给大家分享一下MyBatis中Mapper生效的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一、MyBatis基本使用一切都从最简单的开始,所以先来...
    99+
    2023-06-20
  • 解析 MyBatis 中 Mapper 生效的来龙去脉
    目录一、MyBatis基本使用1.1 编写配置文件1.2 编写Mapper接口及测试方法1.3 结果二、源码分析2.1 通过配置文件构建出 SqlSessionFactory2.2 ...
    99+
    2024-04-02
  • MyBatis Mapper中的通用example举例分析
    本篇内容介绍了“MyBatis Mapper中的通用example举例分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!MyBatis通用M...
    99+
    2023-06-22
  • 原理分析Java Mybatis中的Mapper
    目录准备1.pom文件2.user类-数据库3.实体类4.dao 层5.Mapper 文件源码分析1.断点2.查看源码总结准备 1.pom文件 <dependencies&g...
    99+
    2024-04-02
  • spring-mybatis与原生mybatis使用的示例分析
    小编给大家分享一下spring-mybatis与原生mybatis使用的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!原生mybatis使用方法:String resource = &...
    99+
    2023-05-30
    spring mybatis
  • Mybatis-Plus代码生成器的示例分析
    小编给大家分享一下Mybatis-Plus代码生成器的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧! 实战 数据库脚本 创建一张商品表test_goodsCREATE&nbs...
    99+
    2024-04-02
  • mybatis plus自动生成器的示例分析
    这篇文章将为大家详细讲解有关mybatis plus自动生成器的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。mybatis plus自动生成器解析使用这个可以超快速生成entity s...
    99+
    2023-06-29
  • 分析mybatis中@Mapper注解的componentModel属性
    本篇内容主要讲解“分析mybatis中@Mapper注解的componentModel属性”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“分析mybatis中@M...
    99+
    2024-04-02
  • Mybatis中缓存的示例分析
    这篇文章主要为大家展示了“Mybatis中缓存的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Mybatis中缓存的示例分析”这篇文章吧。缓存Mybat...
    99+
    2024-04-02
  • mybatis中foreach collection的示例分析
    这篇文章主要介绍mybatis中foreach collection的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!在SQL开发过程中,动态构建In集合条件查询是比较常见的用法,在Mybatis中提供了for...
    99+
    2023-05-31
    mybatis foreach collection
  • Mybatis-Plus的示例分析
    这篇文章主要介绍了Mybatis-Plus的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。Mybatis-Plus1.快速入门地址:安装 | MyBatis-Plus...
    99+
    2023-06-20
  • mybatis属性的示例分析
    这篇文章给大家分享的是有关mybatis属性的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。前言MyBatis是基于“数据库结构不可控”的思想建立的,也就是我们希望数据库...
    99+
    2024-04-02
  • 如何进行Java Mybatis中的Mapper原理分析
    如何进行Java Mybatis中的Mapper原理分析,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。准备1.pom文件 <depen...
    99+
    2023-06-26
  • MyBatis中逆向工程的示例分析
    这篇文章主要介绍了MyBatis中逆向工程的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。MyBatis的逆向工程一:什么是逆行工程...
    99+
    2024-04-02
  • Mybatis分页插件的示例分析
    这篇文章主要介绍Mybatis分页插件的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!Mybatis分页插件的实例详解1.前言:我们知道,在MySQL中,分页的sql是使用l...
    99+
    2024-04-02
  • kubernetes中云原生的示例分析
    这篇文章主要为大家展示了“kubernetes中云原生的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“kubernetes中云原生的示例分析”这篇文章吧。一: 云原生云原生包含了一组应用...
    99+
    2023-06-04
  • Spring集成MyBatis的示例分析
    这篇文章主要为大家展示了“Spring集成MyBatis的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Spring集成MyBatis的示例分析”这篇文...
    99+
    2024-04-02
  • SpringBoot整合MyBatis的示例分析
    这篇文章主要介绍了SpringBoot整合MyBatis的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1.整合MyBatis操作前面一篇提到了SpringBoot整...
    99+
    2023-06-15
  • 在IDEA中maven配置MyBatis的示例分析
    这篇文章给大家分享的是有关在IDEA中maven配置MyBatis的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一.MyBatis简介1)MyBatis 是一款优秀的持久层框架2)MyBatis 避免了...
    99+
    2023-06-20
  • Port Mapper反射DDoS攻击预警的示例分析
    这篇文章跟大家分析一下“Port Mapper反射DDoS攻击预警的示例分析”。内容详细易懂,对“Port Mapper反射DDoS攻击预警的示例分析”感兴趣的朋友可以跟着小编的思路慢慢深入来阅读一下,希望阅读后能够对大家有所帮助。下面跟着...
    99+
    2023-06-19
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作