很好奇Mybaits是怎麼將xml和mapper對應起來的,用一段比較簡單的demo去debug追蹤一下原始碼看看
先用xml設定的方式,看懂了再去看註解的方式是怎麼實現的
Mybaits是如何從xml中載入到mapper的
<?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>
<typeAliases>
<package name="com.github.yeecode.mybatisdemo"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/test?serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/github/yeecode/mybatisdemo/UserMapper.xml"/>
</mappers>
</configuration>
在xml中有mapper
標籤,應該是從這裡載入到設定
範例程式碼
public static void main(String[] args) {
// 第一階段:MyBatis的初始化階段
String resource = "mybatis-config.xml";
// 得到組態檔的輸入流
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream(resource);
} catch (IOException e) {
e.printStackTrace();
}
// 得到SqlSessionFactory
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(inputStream);
// 第二階段:資料讀寫階段
try (SqlSession session = sqlSessionFactory.openSession()) {
// 找到介面對應的實現
UserMapper userMapper = session.getMapper(UserMapper.class);
// 組建查詢引數
User userParam = new User();
userParam.setSchoolName("Sunny School");
// 呼叫介面展開資料庫操作
List<User> userList = userMapper.queryUserBySchoolName(userParam);
// 列印查詢結果
for (User user : userList) {
System.out.println("name : " + user.getName() + " ; email : " + user.getEmail());
}
}
}
從UserMapper userMapper = session.getMapper(UserMapper.class);
此處開始debug,看看是怎麼獲取到mapper的
一路點進來發現是從一個Map中去獲取mapper物件
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>();
那麼是從什麼時候填充knownMappers
的呢
這個物件的方法不只有獲取mapper,還有新增mapper,找一個新增方法繼續斷底點
找到是找到了,但是不知道什麼時候呼叫的,可以通過IDEA的呼叫棧
最後發現了,是載入xml的時候,去解析mapper
標籤裡的值,然後再通過類載入器去載入資源,最後載入到knownMappers
中,還有去解析xml中的sql的過程
這樣子xml就和mapper就對應起來了,雖然知道了mapper和xml的對應關係,但是不知道怎麼通過呼叫mapper裡的方法,去找到對應的sql
在對 List<User> userList = userMapper.queryUserBySchoolName(userParam);
debug時,沒有進入到mapper方法中,而是會進入到一個代理類中
剛剛在getMapper()
中給UserMapper
建立了代理,那麼大概知道是mapper和xml是怎麼關聯的了,當呼叫mapper時,會被MapperProxy
代理,去執行查詢方法時,通過上邊的knownMappers
獲取到mapper對應的xml,這樣代理類就知道要呼叫的方法和對應的sql的哪裡
最終時通過mapperMethod.execute(sqlSession, args);
去執行查詢的,點進去一看發現對各種sql型別做了處理
select的查詢原來通過返回值來選擇不同的處理
很好奇這些屬性是怎麼判斷的,找到對應的類繼續斷點
原來是在execute
之前去賦值,而且這個方法會把呼叫方法對應的xml中的方法找到
通過獲取到方法的返回值,然後再去做對比,我這個方法返回的是list
,就命中了returnMany
,在繼續斷點,找到了真正執行的方法
這裡就已經將關聯的xml資訊帶過來了
繼續看會看到快取相關的程式碼,如果命中了快取就直接返回了,我這裡沒有就繼續開了一個執行緒往下執行,delegate
是一個Executor
最後的查詢到了這裡,就是呼叫mysql的包了,在statement
中,已經把sql、引數和連線設定什麼的都封裝好了
查詢完後把結果返回到statement
,但是返回的內容很多,查詢結果記錄在這裡
查詢總結:
將結果對映到實體類上這段程式碼有點繞,呼叫鏈很長
首先是這裡先建立輸出的實體類,就是resultMap裡定義的物件
建立好實體後,把實體傳輸給下一個方法,填充實體
將實體欄位和結果集裡的欄位對應起來,然後根據欄位去獲取對應的值,然後把值設定到實體裡,通過迴圈遍歷全部欄位
這樣走一圈回來,一個物件就對映好了,再經過迴圈,就把全部的物件都拿到了,最後再將這些物件封裝到multipleResults
集合裡,這個集合就是返回值了
對映總結:
以上就是Mybaits讀取xml,然後查詢的過程了,整個過程還是很複雜的,很多層封裝和跳轉,但是大大的提高了我們開發的效率
然後再把總結髮一下
獲取設定總結:
SqlSessionFactoryBuilder
建立SqlSessionFactory
查詢總結:
對映總結:
本文來自部落格園,作者:阿弱,轉載請註明原文連結:https://www.cnblogs.com/aruo/p/17486845.html