最近有读者后台留言,面试官问了他一个问题:MyBatis 如何找到要执行的 SQL 语句的?
今天展开聊聊。
要回答这个问题,我们需要搭建一个 mybatis 应用案例来深入研究 mybatis 的执行逻辑原理,这样我们就能知道 mybatis 如何找到要对应执行的 sql 语句。
idea
快速创建一个
maven
项目,pom.xml
添加如下依赖:
<!-- mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.1.0</version>
</dependency>
<!--mysql驱动-->
<dependency>
   <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.23</version>
</dependency>
在 pom.xml 文件中配置 build 节点指定配置文件路径,如下:
<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
            <include>**/*.properties</include>
            <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
        <resource>
            <directory>src/main/java</directory>
            <includes>
            <include>**/*.properties</include>
            <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>
在 resource 目录下新建 mybatis-config.xml 文件和建 mapper 文件夹存放 sql 文件并且指定数据源连接地址和数据库账号密码、指定加载 mapper.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>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://192.168.192.133:3306/test?useUnicode=true&useSSL=false&serverTimezone=UTC&characterEncoding=utf8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mapper/MyMapper.xml" />
    </mappers>
</configuration>
定义mapper接口:
public interface MyMapper {
    //根据id查询用户 
     User getOne(@Param("id") int id);
     // 查询全部用户
     List<User> getAll();
}
定义对象
public class User {
    private Integer id;
    private String name;
    private Integer age;
    
    ....
}
mapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.it55.mybatis.mapper.MyMapper">
    <select id="getOne" parameterType="Integer" resultType="com.it55.mybatis.domain.User">
    select * from user where id=#{id}
  </select>
    <select id="getAll" resultType="com.it55.mybatis.domain.User">
    select * from user
  </select>
</mapper>
数据库表的准备,这里很简单使用了一张 User 表字段和上述对象一一对应这里就不贴出来了,创建一个 main 方法作为程序的入口 ,完整的项目目录如下图示:


启动main方法,看运行结果:
 
运行没错的话这个最简单的mybatis案例,就搭建成功了,而我们接下来要做的就是一步一步来解析这个过程,代码中的指定配置文件和以流方式加载文件这两步不是代码的关键点我们直接从创建SqlSessionFactory对象说起
3.创建 sqlSessionFactory 对象过程中mybatis做了哪些事情?
 
 
节点下信息到Configuration对象中


节点的信息都被加载到了configuration对象的environment成员变量中,那在
 
    
    
    
 
     
     
     SqlSession sqlSession = sqlSessionFactory.openSession();
    
    
     

sqlSessionFactory对象调用openSession方法给SqlSession对象实例化了configuration和executor
5.运行sql语句的方式
5.1sqlSession运行sql语句的方式1

    
    
    
 
     
     
     User one =sqlSession.selectOne("com.it55.mybatis.mapper.MyMapper.getOne", 1);
    
    
     
 
!
到此
本文的第三个问题已经得到了答案。
mybatis在创建sqlSessionFactory对象时会将mappers节点下的mapper配置加载到MappedStatements中key就是mapper接口中方法的全限定命名也就是mapper.xml文件中每个数据库操作标签的id,值就是整个MappedStatement对象这个对象中包含了数据库语句等信息,在程序执行数据库操作之前根据mapper方法的全限定命名作为key在MappedStatement对象中找到相对应的MappedStatement对象从对象中可以得到要执行的sql语句
5.2 sqlSession运行sql语句的方式2
    
    
    
     
     
     
 M
 
     
     
     yMapper mapper = sqlSession.getMapper(MyMapper.class);
    
    
     

通过sqlSession.getMapper()方式返回的mapper接口对象是mybatis为原mapper接口动态生成一个代理对象
,我们可以通过返回值来证实这一结论,如下图所示:
 
通过上图注意mapper的值:org.apache.ibatis.binding.MapperProxy@71c8becc,可以发现返回的mapper接口并不是我们自己创建的接口而是mybatis为我们动态生成的mapper对象。
6. 通过代理对象调用getOne()方法做了哪些事儿?


 
在这个execute方法中,根据数据库的操作类型选择一个执行方法,在debug控制台中我们可以看到我们的数据操作类型为“SELECT“,所以最终会sqlSession.selectOne(commandName, param)方法,而这个方法接下来如何执行已经在上文的给出了明确的指引。到此通过mapper代理方式执行mapper方法的逻辑已经走完了后面的都是调用sqlsession方法里面的数据库操作方法了
最后
本文分享自微信公众号 - Java后端(web_resource)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
