浅谈MyBatis 如何执行一条 SQL语句

论坛 期权论坛     
niminba   2021-5-26 12:32   2135   0
<h2>前言<br>
</h2>
<p>Mybatis 是 Java 开发中比较常用的 ORM 框架。在日常工作中,我们都是直接通过 Spring Boot 自动配置,并直接使用,但是却不知道 Mybatis 是如何执行一条 SQL 语句的,而这篇文章就是来揭开 Mybatis 的神秘面纱。<br>
</p>
<h2>基础组件<br>
</h2>
<p>我们要理解 Mybatis 的执行过程,就必须先了解 Mybatis 中都有哪一些重要的类,这些类的职责都是什么?<br>
</p>
<p><strong>SqlSession</strong><br>
</p>
<p>我们都很熟悉,它对外提供用户和数据库之间交互需要使用的方法,隐藏了底层的细节。它默认是实现类是 DefaultSqlSession<br>
</p>
<p><strong>Executor</strong><br>
</p>
<p>这个是执行器,SqlSession 中对数据库的操作都是委托给它。它有多个实现类,可以使用不同的功能。</p>
<p style="text-align: center"><img alt="" src="https://beijingoptbbs.oss-cn-hangzhou.aliyuncs.com/jb/2426819-d282a9e35ef9b33a453b7fe88cabac61"></p>
<p><strong>Configuration</strong><br>
</p>
<p>它是一个很重要的配置类,它包含了 Mybatis 的所有有用信息,包括 xml 配置,动态 sql 语句等等,我们到处都可以看到这个类的身影。<br>
</p>
<p><strong>MapperProxy</strong><br>
</p>
<p>这是一个很重要的代理类,它代理的就是 Mybatis 中映射 SQL 的接口。也就是我们常写的 Dao 接口。<br>
</p>
<h2>工作流程<br>
</h2>
<h3>初步使用<br>
</h3>
<p>首先,我们需要得到一个 SqlSessionFactory 对象,该对象的作用是可以获取 SqlSession&nbsp; 对象。<br>
</p>
<div class="blockcode">
<pre class="brush:java;">
// 读取配置
InputStream resourceAsStream = Resources.getResourceAsStream("config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 创建一个 SqlSessionFactory 对象
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(resourceAsStream);
</pre>
</div>
<p>当我们得到一个 SqlSessionFactory 对象之后,就可以通过它的 openSession 方法得到一个 SqlSession 对象。<br>
</p>
<div class="blockcode">
<pre class="brush:java;">
SqlSession sqlSession = sqlSessionFactory.openSession(true);
</pre>
</div>
<p>最后,我们通过 SqlSession 对象获取 Mapper ,从而可以从数据库获取数据。<br>
</p>
<div class="blockcode">
<pre class="brush:java;">
// 获取 Mapper 对象
HeroMapper mapper = sqlSession.getMapper(HeroMapper.class);
// 执行方法,从数据库中获取数据
Hero hero = mapper.selectById(1);
</pre>
</div>
<h2>详细流程<br>
</h2>
<h3>获取 MapperProxy 对象<br>
</h3>
<p>我们现在主要关注的就是 getMapper 方法,该方法为我们创建一个代理对象,该代理对象为我们执行 SQL 语句提供了重要的支持。<br>
</p>
<div class="blockcode">
<pre class="brush:java;">
// SqlSession 对象
@Override
public &lt;T&gt; T getMapper(Class&lt;T&gt; type) {
    return configuration.getMapper(type, this);
}
</pre>
</div>
<p>getMapper&nbsp; 方法里面委托 Configuration 对象去获取对应的 Mapper 代理对象,之前说过 Configuration 对象里面包含了 Mybatis 中所有重要的信息,其中就包括我们需要的 Mapper 代理对象,而这些信息都是在读取配置信息的时候完成的,也就是执行sqlSessionFactoryBuilder.build 方法。<br>
</p>
<div class="blockcode">
<pre class="brush:java;">
// Configuration 对象
public &lt;T&gt; T getMapper(Class&lt;T&gt; type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
}
</pre>
</div>
<p>我们可以看到它又将获取 Mapper 代理对象的操作委托给了 MapperRegistry 对象(搁着俄罗斯套娃呢?),这个 MapperRegistry 对象里面就存放了我们想要的 Mapper 代理对象,如果你这么想,就错了,实际上,它存放的并不是我们想要的 Mapper 代理对象,而是 Mapper 代理对象的工厂,Mybatis 这里使用到了工厂模式。<br>
</p>
<div class="blockcode">
<pre class="brush:java;">
public class MapperRegistry {

  private final Configuration config;
  private final Map&lt;Class&lt;&#63;&gt;, MapperProxyFactory&lt;&#63;&gt;&gt; knownMappers = new HashMap&lt;&gt;();

  public MapperRegistry(Configuration config) {
    this.config = config;
  }

  @SuppressWarnings("unchecked")
  public &lt;T&gt; T getMapper(Class&lt;T&gt; type, SqlSession sqlSession) {
    final MapperProxyFactory&lt;T&gt; mapperProxyFactory = (MapperProxyFactory&lt;T&gt;) 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);
    }
  }

  public &lt;T&gt; void addMapper(Class&lt;T&gt; type) {
    if (type.isInterface()) {
      if (hasMapper(type)) {
        throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
      }
      boolean loadCompleted = false;
      try {
        knownMappers.put(type, new MapperProxyFactory&lt;&gt;(type));
        // It's important that the type is added before the parser is run
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:1060120
帖子:212021
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP