mybatis-plus查詢源碼詳解
配置詳情
pom.xml
dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>mapper
public interface GenTableMapper extends BaseMapper<GenTable> {
}測試類
@RunWith(SpringRunner.class)
@SpringBootTest(classes = GendemoApplication.class)
public class BlockqueueTestDemo {
@Autowired
GenTableMapper genTableMapper;
@Test
public void test(){
List<GenTable> genTables =
genTableMapper.selectList(new QueryWrapper<>());
}
}
debug流程
1.發(fā)現(xiàn) genTableMapper 是一個代理對象類型。

2.進入代理對象MybatisMapperProxy , 調用其invoke 方法,方法的Class類型為BaseMapper.selectList()

3.其中cachedInvoker()方法會返回一個PlainMethodInvoker ,它重寫了MapperMethodInvoker 接口的invoke()方法

4.最終會調用MybatisMapperMethod的execute()方法

public class MybatisMapperMethod {
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) {
case INSERT: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
case UPDATE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
break;
}
case DELETE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
break;
}
case SELECT:
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) {
result = executeForCursor(sqlSession, args);
} else {
Object param = method.convertArgsToSqlCommandParam(args);
// TODO 這里下面改了
if (IPage.class.isAssignableFrom(method.getReturnType())) {
result = executeForIPage(sqlSession, args);
// TODO 這里上面改了
} else {
result = sqlSession.selectOne(command.getName(), param);
if (method.returnsOptional()
&& (result == null || !method.getReturnType().equals(result.getClass()))) {
result = Optional.ofNullable(result);
}
}
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + command.getName());
}
if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
throw new BindingException("Mapper method '" + command.getName()
+ " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
}
return result;
}
}
5.這是經(jīng)過判斷會進入executeForMany(sqlSession, args)方法,此時方法和參數(shù)都顯示出來了。sqlSession的類型是SqlSessionTemplate , 為什么要注意這個 sqlSession的類型?因為SqlSession是一個接口,有很多實現(xiàn)類,有時候我們并不知道到底調用了哪個實現(xiàn)類的selectList()方法,這個時候我們看類型就知道了,就可以進入SqlSessionTemplate類,找到selectList()打上斷點,debug就過來了。

6.利用同樣的方法,又調用了DefaultSqlSession的selectList()方法。

7.來到DefaultSqlSession的selectList() 方法中,此時已經(jīng)進入到mybatis的源碼范圍了。executor的類型是MybatisCachingExecutor

8.此時要注意MybatisCachingExecutor 代理類的handler是一個Plugin


9.因為我使用到了分頁插件,所以會來到com.github.pagehelperPageInterceptor中

10.由MybatisCachingExecutor來執(zhí)行查詢

11.MybatisCachingExecutor 委派 BaseExecutor 執(zhí)行查詢


12.最終委派到PreparedStatementHandler來處理

13.最后由DefaultResultSetHandler來封裝結果集
@Override
public List<Object> handleResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
final List<Object> multipleResults = new ArrayList<>();
int resultSetCount = 0;
ResultSetWrapper rsw = getFirstResultSet(stmt);
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
validateResultMapsCount(rsw, resultMapCount);
while (rsw != null && resultMapCount > resultSetCount) {
ResultMap resultMap = resultMaps.get(resultSetCount);
handleResultSet(rsw, resultMap, multipleResults, null);
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
String[] resultSets = mappedStatement.getResultSets();
if (resultSets != null) {
while (rsw != null && resultSetCount < resultSets.length) {
ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
if (parentMapping != null) {
String nestedResultMapId = parentMapping.getNestedResultMapId();
ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
handleResultSet(rsw, resultMap, null, parentMapping);
}
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
return collapseSingleResultList(multipleResults);
}總結
為什么要一層一層的封裝?一層一層的委派?
這里面和緩存有關,有興趣的可以自己了解一下。
下一篇打算記錄一下 mybatis-plus 的自動配置過程,有興趣的可以持續(xù)關注一下。
文中有錯誤的地方不吝賜教謝謝。
到此這篇關于mybatis-plus查詢源碼走讀的文章就介紹到這了,更多相關mybatis-plus查詢內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
springboot+redis實現(xiàn)微博熱搜排行榜的示例代碼
本文主要介紹了springboot+redis實現(xiàn)微博熱搜排行榜的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-05-05
Mybatis實現(xiàn)自定義類型轉換器TypeHandler的方法
Mybatis實現(xiàn)自定義的轉換器非常的簡單,只需要三步就可以實現(xiàn)自定義類型轉換器TypeHandler,非常不錯,具有參考借鑒價值,感興趣的朋友一起看下吧2016-07-07
SpringCloud之熔斷監(jiān)控Hystrix Dashboard的實現(xiàn)
這篇文章主要介紹了SpringCloud之熔斷監(jiān)控Hystrix Dashboard的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-09-09

