MyBatis执行原理
张起灵-小哥 人气:01.前言
MyBatis框架大家肯定都用过的,废话我就不再多说了,这篇文章就给大家分享一下有关MyBatis框架底层的执行原理吧(Debug!!!)
2.案例项目源码
我这里写了一个简单的MyBatis相关的maven项目,把源码分享给大家,一会的debug就以这个项目的测试代码为主。
首先给出pom依赖。
<dependencies> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.9</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.20</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> </dependencies> <build> <!--资源插件:处理src/main/java目录中的xml--> <resources> <resource> <directory>src/main/java</directory><!--所在的目录--> <includes><!--包括目录下的.properties,.xml 文件都会扫描到--> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> </resources> </build>
下面是实体类,以及数据库中表结构信息。
package com.szh.entity; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * */ @Data @NoArgsConstructor @AllArgsConstructor public class Student { private Integer id; private String name; private Integer age; private String email; }
然后是对应的mapper接口和xml映射文件。
package com.szh.dao; import com.szh.entity.Student; import java.util.List; /** * */ public interface StudentDao { List<Student> selectAll(); }
<?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.szh.dao.StudentDao"> <sql id="column"> id, name, age, email </sql> <select id="selectAll" resultType="com.szh.entity.Student"> select <include refid="column"></include> from student </select> </mapper>
接下来是数据库配置文件和mybatis核心配置文件。
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=utf-8 jdbc.username=root jdbc.password=12345678
<?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" /> <!--设置日志--> <settings> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <!--配置数据源:创建Connection对象--> <dataSource type="POOLED"> <!-- driver:驱动内容 --> <property name="driver" value="${jdbc.driver}"/> <!-- 连接数据库的url --> <property name="url" value="${jdbc.url}"/> <!-- 用户名 --> <property name="username" value="${jdbc.username}"/> <!-- 密码 --> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> </environments> <mappers> <mapper class="com.szh.dao.StudentDao"/> <!-- <package name="com.szh.dao"/>--> </mappers> </configuration>
最后给出获取mybatis中核心对象(SqlSeesion、SqlSeesionFactory这些对象)的工具类、以及测试代码。
package com.szh.utils; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.InputStream; /** * 工具类:创建SqlSession对象 */ public class MyBatisUtil { private static SqlSessionFactory factory = null; static { String config = "mybatis.xml"; try { InputStream inputStream = Resources.getResourceAsStream(config); factory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } public static SqlSession getSqlSession() { SqlSession session = null; if (factory != null) { session = factory.openSession(); } return session; } }
package com.szh; import com.szh.dao.StudentDao; import com.szh.entity.Student; import com.szh.utils.MyBatisUtil; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; /** * */ public class MyTest { @Test public void testSelectStudents() { SqlSession session = MyBatisUtil.getSqlSession(); StudentDao studentDao = session.getMapper(StudentDao.class); //com.sun.proxy.$Proxy == StudentDaoImpl System.out.println("studentDao === " + studentDao.getClass().getName()); List<Student> studentList = studentDao.selectAll(); studentList.forEach(stu-> System.out.println("stu = " + stu)); session.close(); } }
下面我们测试一下,确保项目可以正常运行,然后再进行debug。
3.MyBatis源码解析底层执行原理
3.1 读取mybatis配置文件创建出SqlSeesionFactory对象
由于我们这里要摸清MyBatis框架到底是如何执行的?如何创建SqlSeesionFactory、SqlSession这些对象的?怎样解析配置文件的?
所以debug的源头就从下面这张图开始。
然后我们按F7跟进去,这里需要按两次,因为有两个方法需要确定跟哪个?我们进到build方法中。
上图也就是跟进去的build方法,可以看到这个inputStream中读取的就是我们当前项目的 mybatis 核心配置文件了。
接下来再次F7跟进这个build方法中。
此时在下图可以看到,有一个XMLConfigBuilder这个类,从名字上大致可以猜到它就是来解析我们的 mybatis 核心配置文件(mybatis.xml)。
在 parseConfiguration 这个方法中,我们可以通过 Evaluate 计算一下这个root 的值是什么。
<configuration> <properties resource="jdbc.properties"/> <settings> <setting name="logImpl" value="STDOUT_LOGGING"/> </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> <mapper class="com.szh.dao.StudentDao"/> </mappers> </configuration>
加载全部内容