一、准备基本代码
注:本文的一切内容都是基于XML配置启动进行的分析,不适用与Spring-mybatis组合使用场景。
1.创建基本类
package com.zhou;
import com.zhou.mapper.BlogMapper;
import com.zhou.pojo.Blog;
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;
import java.util.ArrayList;
public class Demo1SessionFactory {
public static void main(String[] args) throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
//从 XML 中构建 SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
try {
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(1, new ArrayList<>());
System.out.println(blog.getId());
blog = mapper.selectBlog(10, new ArrayList<>());
System.out.println(blog.getId());
} finally {
session.close();
}
}
}
2.创建基本的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>
<!-- 引入外部资源文件 -->
<!-- 设置驼峰匹配 -->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!-- 设置包扫描(别名)
<typeAliases>
<package name="com.zhou.pojo"/>
</typeAliases>-->
<!-- 配置环境:可以配置多个环境,default:配置某一个环境的唯一标识,表示默认使用哪个环境 -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!-- 配置连接信息 -->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://192.168.1.251:3306/welian"/>
<property name="username" value="welian"/>
<property name="password" value="welian"/>
</dataSource>
</environment>
</environments>
<!-- 配置映射文件:用来配置sql语句和结果集类型等 -->
<mappers>
<mapper resource="BlogMapper.xml"/>
</mappers>
</configuration>
3.创建查询sql的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.zhou.mapper.BlogMapper">
<select id="selectBlog" parameterType="java.lang.Integer" resultType="com.zhou.pojo.Blog">
SELECT
<if test="id != null">
<foreach collection="ids" item="item">
1 AS str,
</foreach>
#{id} AS id
</if>
</select>
</mapper>
4.根据上方的mapper.xml创建对应的POJO类以及mapper接口。
package com.zhou.pojo;
public class Blog {
private Integer id;
private String str;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
}
package com.zhou.mapper;
import java.util.List;
import com.zhou.pojo.Blog;
import org.apache.ibatis.annotations.Param;
public interface BlogMapper {
Blog selectBlog(@Param("id") Integer id, @Param("ids") List<Integer> ids);
}
二、SqlSessionFactory的构建
在进行构建sqlSessionFactory时,进行了以下的两步主要操作
1.读取config配置的信息到缓存中,并将其设置到Configuration类。在这个示例中,我们采用的是xml配置的方式因此,在加载配置时会使用xml的解析器解析配置文件中的信息,使用校验文件来进行校验输入配置参数的有效性,然后创建一个xml的dom对象。
2.将mapper的sql描述信息添加到Configuration类中。然后使用读取出来的xml信息缓存,调用XMLConfigBuilder格式化工具,来创建基本的mybatis的Configuration类信息。在完成了基本配置后,将mapper.xml中的信息读取出来,然后进行结构化处理,再保存到Configuration的mappedStatements中。
在mappedStatements中的数据结构,以下方的数据结构进行存储:
由上方的debug信息可以看出,这里将每一个sql,拆分成了多个不同的节点,并且每一个标签均为不同的节点类型,节点原本的属性信息,都已经被转换为了对象的属性。利用这些属性,就可以迅速的将sql加载出来。
三、Mapper实例的构建与调用
1.创建SqlSession。在调用SqlSessionFactory进行开启SqlSession时,首先创建了一个SqlSession对象,然后像这个对象中添加了executor的信息。但是要注意的是,在一开始开启SqlSession的时候,并没有进行数据库连接。
下方的debug信息,是执行查询前的SqlSession中的属性信息,可以看到在executor对象下的transaction对象中,虽然具有dataSource对象但是并没有connection对象,即数据库连接。
在执行过一次查询以后,便拥有了一个数据库连接在executor对象中,而之后,在这个session提交前,都会使用这个connection来进行sql的执行了。
2.利用SqlSession开启一个MapperProxy类对象。
首先从SqlSession对象中,获取到Configuration的对象,然后从该对象的MapperRegistry中获取相应的类的描述信息,再使用MapperProxyFactory构造出响应的MapperProxy对象,再从该对象中获取mapper接口的实现类返回给调用端。
DefaultSqlSession类中的getMapper方法,这里在getMapper的时候,将SqlSession自身作为参数传入了,所以在每个MapperProxy对象中都是具有一个SqlSession对象信息的。
MapperRegistry类中的getMapper方法:
MapperProxyFactory类中,进行构造MapperProxy对象的方法:
3.执行查询时,是利用java的反射来对类进行的实现,利用反射来实现类以后,再使用这个对象来调用sqlSession来执行查询操作。
首先调用MapperProxy类的invoke方法,该方法中,首先利用method来构建出所需要使用的MapperMethod类对象,这个类中,只会包含基本的method描述,如入参出参等。
在构造完成MapperMethod信息后,MapperMethod会使用MapperProxy类中持有的sqlSession对象,来执行sql。在这里查询的结果只有一个对象,因此使用的是下图中的方式来执行sql。
最后再进行实际的sql执行,返回查询到的数据。
四、总结
1.初始化
mybatis在进行初始化时,首先会由SqlSessionFactoryBuilder来创建SqlSessionFactory,在创建成功后,SqlSessionFactoryBuilder对象就会结束生命周期。SqlSessionFactory中,持有mybatis的Config信息,而Config信息中,除mybatis本身的信息外,还持有数据库连接池,以及mapper.xml中的信息,这些信息都在mybatis进行初始化时进行结构化缓存到了Configuration类中。其中,mapper.xml中的信息,被进行了良好的节点分割,每一个标签都被分割成独立的节点,来供mybatis进行快速组装sql信息。
2.执行sql
在进行sql的执行时,首先需要的是开启SqlSession,SqlSession由SqlSessionFactory进行创建。开启SqlSession后,由SqlSession来进行mapper的信息初始化,所使用的则是MapperRegistry类,这个类在每次完成mapper的初始化后,就会结束生命周期,在反复创建mapper时,会需要多次的创建MapperRegistry对象。mapper对象构建完成后,在mapper中,不会直接具有JdbcConnection对象,而是引用了SqlSession对象。在SqlSession中,采用的是懒汉的单例模式来处理JdbcConnection,以此来达到事物处理的效果。