之前我們分析了Mybatis初始做的工作,以及Mapper執(zhí)行命令的部分原理,接下來(lái)我們就準(zhǔn)備開始Mybatis到底是如何去分析執(zhí)行SQL的。而這個(gè)過程十分依賴MappedStatement這個(gè)類,所以我們繼續(xù)分析之前先把這個(gè)類簡(jiǎn)單介紹一下,它主要是Mybatis初始化時(shí)通過解析mapper對(duì)應(yīng)的XML文件來(lái)生成,它的每個(gè)屬性基本上都能對(duì)上XML中的某一個(gè)配置。
demo
<select id="count" resultType="int">
SELECT
count(1)
FROM
<include refid="table"/>
</select>
<select id="queryPage" parameterType="cn.com.bsfit.model.so.EmployeeSO" resultMap="baseResultMap">
SELECT
<include refid="base_columns"/>
FROM
<include refid="table"/>
limit #{offset},#{limit}
</select>
MappedStatement 字段解析
public final class MappedStatement {
// Mapper來(lái)源,當(dāng)前Statement是哪個(gè)XML文件解析出來(lái)的。
// 例如:file [/home/hwb/git/study/studymybatis/target/classes/cn/com/bsfit/mapper/PersonMapper.xml]
private String resource;
// 全局的配置
private Configuration configuration;
// sql id , 如例子中的 count
private String id;
// fetchSize, ResultSet.next()取數(shù)據(jù)時(shí)客戶端緩存行數(shù)大小
private Integer fetchSize;
// sql超時(shí)時(shí)間
private Integer timeout;
// sql的類型,INSERT | DELETE | UPDATE | SELECT
private StatementType statementType;
// ResultSet的ResultSetType
private ResultSetType resultSetType;
// 解析了mybatis語(yǔ)法后帶占位符的Sql,例如: SELECT id, userId, userName, nickName, gender, mobilePhone, miliao, email FROM employee limit ?,?
private SqlSource sqlSource;
// mybatis 2級(jí)緩存
private Cache cache;
// 請(qǐng)求參數(shù)類型
private ParameterMap parameterMap;
// 返回結(jié)果類型
private List<ResultMap> resultMaps;
// 是否需要刷新緩存
private boolean flushCacheRequired;
// 是否使用緩存
private boolean useCache;
// 這個(gè)設(shè)置僅針對(duì)嵌套結(jié)果 select 語(yǔ)句適用:如果為 true,就是假設(shè)包含了嵌套結(jié)果集或是分組了,這樣的話當(dāng)返回一個(gè)主結(jié)果行的時(shí)候,就不會(huì)發(fā)生有對(duì)前面結(jié)果集的引用的情況。這就使得在獲取嵌套的結(jié)果集的時(shí)候不至于導(dǎo)致內(nèi)存不夠用。默認(rèn)值:false。
private boolean resultOrdered;
// SQL類型 UNKNOWN, INSERT, UPDATE, DELETE, SELECT;
private SqlCommandType sqlCommandType;
// 主鍵生成器
private KeyGenerator keyGenerator;
// 對(duì)應(yīng)XML中的keyProperty selectKey 語(yǔ)句結(jié)果應(yīng)該被設(shè)置的目標(biāo)屬性。如果希望得到多個(gè)生成的列,也可以是逗號(hào)分隔的屬性名稱列表。
private String[] keyProperties;
// keyColumn 匹配屬性的返回結(jié)果集中的列名稱。如果希望得到多個(gè)生成的列,也可以是逗號(hào)分隔的屬性名稱列表。
private String[] keyColumns;
// 對(duì)應(yīng)的ResultMap對(duì)用有內(nèi)置的ResultMap
private boolean hasNestedResultMaps;
// 如果配置了數(shù)據(jù)庫(kù)廠商標(biāo)識(shí)(databaseIdProvider),MyBatis 會(huì)加載所有的不帶 databaseId 或匹配當(dāng)前 databaseId 的語(yǔ)句;如果帶或者不帶的語(yǔ)句都有,則不帶的會(huì)被忽略。
// 在使用多個(gè)數(shù)據(jù)庫(kù)的情況下使用
private String databaseId;
// 內(nèi)部日志類
private Log statementLog;
// 默認(rèn)是XMLLanguageDriver
private LanguageDriver lang;
// 這個(gè)設(shè)置僅對(duì)多結(jié)果集的情況適用。它將列出語(yǔ)句執(zhí)行后返回的結(jié)果集并給每個(gè)結(jié)果集一個(gè)名稱,名稱是逗號(hào)分隔的
private String[] resultSets;
}
簡(jiǎn)單介紹一下它的解析邏輯
首先是在SqlSessionFactoryBean中創(chuàng)建SqlSessionFactory時(shí),通過把配置好的XML資源路徑傳遞給XMLMapperBuilder,由XMLMapperBuilder去解析XML,然后再交由XMLStatementBuilder類去具體解析某一個(gè)SQL對(duì)應(yīng)的配置,最后由MapperBuilderAssistant幫忙注冊(cè)到configuration中的Map<String, MappedStatement> mappedStatements中。
下面的圖片是Mybatis各種Builder類,它們都繼承了BaseBuilder,有興趣的同學(xué)可以自行了解下。

Builder.png
ok,今天到這里了,接下來(lái)就要開始分析Mybaits是如何執(zhí)行SQL的了。