源碼閱讀之Mybatis初體驗

源碼下載

源碼地址:
https://github.com/mybatis/mybatis-3
文檔地址:
https://mybatis.org/mybatis-3/getting-started.html

Getting started

下載項目,導入項目後
導入mysql依賴

 <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.35</version>
    </dependency>

1.在根目錄下創建 mybatis-config.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>
  <properties resource="jdbc.properties"/>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="mapper/test.xml"/>
  </mappers>
</configuration>

2.創建jdbc.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://****/ccms
username=****
password=****

3.根目錄下創建mapper文件夾,在其下面創建test.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="org.apache.ibatis.custom.mapper.DemoMapper">

	<select id="selectOne" resultType="org.apache.ibatis.custom.Demo">
		select * from ccms_uers where user_account_id = 1
	</select>
</mapper>

4.創建相應的實體對象和mapper接口

進入主題

先上圖(網絡獲取)
比較完整的描述了mybatis的工作流程
創建main方法

public class MainTest {
	
	public static void main(String[] args) throws IOException {
		
		String resource = "mybatis-config.xml";
		
		InputStream inputStream = Resources.getResourceAsStream(resource);
		
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		
		SqlSession sqlSession = sqlSessionFactory.openSession();
		
		Demo demo1 = sqlSession.selectOne("org.apache.ibatis.custom.mapper.DemoMapper.selectOne");
		
		System.out.println(demo1);
		
		DemoMapper demoMapper = sqlSession.getMapper(DemoMapper.class);
		
		Demo demo2 = demoMapper.selectOne();
		
		System.out.println(demo2);
	}
}

SqlSessionFactory

分析這一句代碼都做了什麼工作
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

1. new SqlSessionFactoryBuilder() 使用的建築者模式,根據傳入的輸入流創建了一個XMLConfigBuilder對象,在XMLConfigBuilder中給了configuration、parsed、environment、parser四個變量賦值。然後通過重載的build()方法,返回了一個DefaultSqlSessionFactory。
在這裏插入圖片描述
執行到黃色行時, XMLConfigBuilder中的
configuration 爲默認對象;
parsed = false;
environment = null;
parser 爲默認對象;

下面看下一句代碼,return build(parser.parse());
parser.parse()
在這裏插入圖片描述
此時通過Expressions視圖可以看到,parser.evalNode("/configuration")獲取到的內容就是resources下jdbc.properties的內容
在這裏插入圖片描述
parseConfiguration()
通過 propertiesElement(root.evalNode(“properties”));方法將jdbc.properties中的內容解析成鍵值對,並設置到mybatis-config.xml中對應的${}的內容。並設置
XMLConfigBuilder中的 XPathParser parser的variables屬性
BaseBuilder中的 Configuration configuration的variables屬性
parser.setVariables(defaults);
configuration.setVariables(defaults);

mapperElement(root.evalNode(“mappers”));
root.evalNode(“mappers”)獲取的是mybatis-config.xml中的mapper標籤的內容,格式如下:
在這裏插入圖片描述
environmentsElement(root.evalNode(“environments”));
通過該方法反射實例化dataSource在這裏插入圖片描述
mapperElement(root.evalNode(“mappers”));
通過該方法循環解析mapper文件,將cachae-ref、cache、parameterMap、resultMap、sql、操作數據庫方式(select、inser、update、delete)等分別存儲在這裏插入圖片描述
此時,執行結束後,成功返回SqlSessionFactory

sqlSessionFactory.openSession();

在這裏插入圖片描述
sqlSession.selectOne(“org.apache.ibatis.custom.mapper.DemoMapper.selectOne”);
在這裏插入圖片描述

到此,demo1的結果就已經查詢出來了。

sqlSession.getMapper(DemoMapper.class)
筆者看到這裏已經有點懵圈了,DemoMapper是在什麼時候加載的,爲什麼sqlSession可以獲取到DemoMapper對象。
帶着這種疑惑,從頭再跟蹤一下SqlSessionFactory 的創建過程。

就是在實例化SqlSessionFactory 時調用的parse()中,調用的bingMapperForNamespace(),如下圖(黃色行)
在這裏插入圖片描述
然後調用下圖方法
在這裏插入圖片描述
下圖可見,加入的map對象爲clase對象和mapper代理對象的鍵值對。
在這裏插入圖片描述
到這裏,一切豁然開朗,sqlSession對象保存了所有mapper的代理對象,通過mapper加方法名作爲key,在sqlSession對象的configuration屬性中的mappedStatements集合中,獲取對應的MappedStatement ,然後通過 Executor對象執行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章