一、準備基本代碼
注:本文的一切內容都是基於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://你的數據庫地址:3306/庫名"/>
<property name="username" value="你的用戶名"/>
<property name="password" value="你的密碼"/>
</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對象。創建出的類對象以MapperProxy進行承載,在MapperProxy對象進行執行Sql時,則是將sql交予自身所持有的final的SqlSession來進行處理。在SqlSession中,採用的是懶漢單例模式來處理JdbcConnection,以此來達到事物處理的效果。