Mybatis 框架学习2 - Mybatis 执行过程的分析

本文详细解析了MyBatis框架的执行流程,包括代理对象的创建和selectList方法的执行过程。阐述了如何通过代理对象调用selectList方法进行数据库查询,以及配置文件解析、连接信息和映射信息的使用。

对 Mybatis 执行过程的分析

  • Mybatis 在使用代理dao的方式实现增删改查时做什么事情呢?
    • 只有两件事情
      • 第一:创建代理对象
      • 第二:在代理对象中调用selectList

1. 执行查询所有分析 selectList

​ 首先是测试类中,调用 Mybatis 框架进行查询的代码:

public class MybatisTest {

    /**
     * 入门案例
     * @param args
     */
    public static void main(String[] args) throws IOException {
        // 1. 读取配置文件
        InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
        // 2. 创建 SqlSessionFactory 工厂
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(is);
        // 3. 使用工厂生产一个 SQLSession 对象
        SqlSession session = factory.openSession();
        // 4. 使用 SQLSession 创建接口的代理对象
        IUserDao userDao = session.getMapper(IUserDao.class);
        // 5. 使用代理对象执行方法
        List<User> users = userDao.findAll();
        for (User user : users) {
            System.out.println(user);
        }
        // 6. 释放资源
        session.close();
        is.close();
    }
}

​ 我们通过创建代理对象,来进行方法的执行,但是这个代理方法调用的方法,实际上是 SqlSession 对象中的 selectList 方法。

​ 在 Mybatis 的配置文件中(名字是自定义的):

<?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">
<!--mybatis 的主配置文件-->
<configuration>
    <!-- 配置环境 -->
    <environments default="mysql">
        <!--        配置mysql的环境-->
        <environment id="mysql">
            <!--            配置事务的类型-->
            <transactionManager type="JDBC"></transactionManager>
            <!--            配置数据源,也叫连接池-->
            <dataSource type="POOLED">
                <!--                配置连接数据的 4 个基本信息-->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;serverTimezone=Asia/Shanghai"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="com/review/mybatis/dao/IUserDao.xml"></mapper>
    </mappers>
</configuration>

有以下一些代码:

 <dataSource type="POOLED">
                <!--                配置连接数据的 4 个基本信息-->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;serverTimezone=Asia/Shanghai"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>

连接数据库的信息,有了它们就能够创建 Connection 对象。

<mappers>
        <mapper resource="com/review/mybatis/dao/IUserDao.xml"></mapper>
    </mappers>

这是映射的配置信息

在IUserDao.xml 中,有以下代码:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.review.mybatis.dao.IUserDao">
    <select id="findAll" resultType="com.review.mybatis.domain.User">
        select * from user
    </select>
</mapper>

其中:

<mapper namespace="com.review.mybatis.dao.IUserDao">
    <select id="findAll" resultType="com.review.mybatis.domain.User">
        select * from user
    </select>
</mapper>

这里面是需要执行的 sql 语句,有了它,就可以获取 PreparedStatement 对象。这个配置中还有封装的实体类全限定的类名。这个就决定我们用什么去查询,又封装到哪里去。

这些所有的东西,都是我们上来需要做的事情,也就是需要读成一个流,解析配置文件。

读取配置文件有很多种,用到的技术也就是解析 XML 的技术。此处使用的是 dom4j 解析xml 的技术。

在解析完 xml 之后,第二片代码创建了 Connection

<dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;serverTimezone=Asia/Shanghai"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>

,之后的那一片代码

    <mappers>
        <mapper resource="com/review/mybatis/dao/IUserDao.xml"></mapper>
    </mappers>

会读到最下面的配置文件,

<mapper namespace="com.review.mybatis.dao.IUserDao">
    <select id="findAll" resultType="com.review.mybatis.domain.User">
        select * from user
    </select>
</mapper>

而最下面的配置文件,里面就包含了我们想要的一些信息。

在解析完 xml 文件,并读取之后,Mybatis 框架调用 selectList 方法,而selectList 方法的执行过程如下:

  1. 根据配置信息创建 Connection 对象。

    • 注册驱动,获取连接
  2. 获取预处理对象 PreparedStatement 此时需要 SQL 语句

    • conn.preparedStatement(Sql);
  3. 执行查询

    • ResultSet set = PreparedStatement.executeQuery();
  4. 遍历结果集,用于封装

    List<E> list = new ArrayList<E>();
    while(set.next()) {
        E element = xxx;
        //进行封装,把每个set中的内容都添加到 element 中
        //把 element 加入到 list 中
        list.add(element);
    }
    

    继续深入,我们会发现,这个 E ,其实就是我们之前

    <mapper namespace="com.review.mybatis.dao.IUserDao">
        <select id="findAll" resultType="com.review.mybatis.domain.User">
            select * from user
        </select>
    </mapper>
    

    这一段配置文件中的全限定类名,根据这个全限定类名,使用反射获得这个对象。

    List<E> list = new ArrayList<E>();
    while(set.next()) {
        E element = (E) Class.forName(配置的全限定类名).newInstance()
        //进行封装,把每个set中的内容都添加到 element 中
        //把 element 加入到 list 中
        list.add(element);
    }
    

    在获得实体类之后,我们就可以封装了:

    List<E> list = new ArrayList<E>();
    while(set.next()) {
        E element = (E) Class.forName(配置的全限定类名).newInstance()
        // 我们的实体类属性和表中的列名是一致的。
        // 于是我们可以把表的列名看成是实体类的属性名
        // 就可以使用反射的方式来根据名称获取每个属性,并把值赋进去
        list.add(element);
    }
    
  5. 返回 list ;

    return list;
    

从以上的执行过程可以看出,要想让 selectList 方法执行,我们需要给方法提供两个信息:

  • 第一个:连接信息

  • 第二个:映射信息

    • 它包含了两个部分:

      • 第一:执行的 SQL 语句

      • 第二:封装结果的实体类全限定类名

      • 以上两个信息我们需要合在一起封装,我们可以将这两个信息组合起来定义成一个对象。为什么定义成某个对象呢?因为如果我们定义某个参数,那么在以后的开发中,如果我们想要查询表中其他的东西,我们修改了 SQL 语句,那么反映到映射信息中,就不知道哪条和哪条对应了。

        这一个对象可以取个名(随便),这里我称为 Mapper 。但是我们开发项目中如果有多个这样的Mapper,Mapper都不固定,我们就要将其存起来。这样我们需要一个 Map 将其存起来。 Key 是 String 类型,这个key是 Dao 接口和其方法:

        com.review.mybatis.dao.IUserDao.findAll()
        

        value就是 那个 Mapper 对象,其中包含了一个执行的 SQL 语句和实体类的全限定类名。

2. 创建代理对象的分析

​ 在之前的例子中,我们通过 SqlSession 的对象中的 getMapper 方法进行了代理对象的创建。

IUserDao userDao = session.getMapper(IUserDao.class);

​ 在这里面:

// 根据 dao 接口的字节码创建 dao 的代理对象
public T getMapper(Class<T> daoInterfaceClass) {
    /**
    * 类加载器: 使用和被代理对象是相同的类加载器
   	* 代理对象要实现的接口: 和被代理对象实现相同的接口
   	* 如何代理:它就是增强的方法,我们要自己来提供。
   	* 此处是一个 InvocationHandler 的接口,我们要写一个
   	* 该接口的实现类。在实现类中调用 selectList 方法。
    */
    Proxy newProxyInstance(类加载, 代理对象要实现的接口字节码数组, 如何代理);
    
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值