经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 数据库/运维 » MyBatis » 查看文章
mybatis-plus查询源码详解
来源:jb51  时间:2022/3/2 13:43:08  对本文有异议

配置详情

pom.xml

  1. dependency>
  2. <groupId>com.baomidou</groupId>
  3. <artifactId>mybatis-plus-boot-starter</artifactId>
  4. <version>3.4.1</version>
  5. </dependency>

mapper

  1. public interface GenTableMapper extends BaseMapper<GenTable> {
  2. }

测试类

  1. @RunWith(SpringRunner.class)
  2. @SpringBootTest(classes = GendemoApplication.class)
  3. public class BlockqueueTestDemo {
  4. @Autowired
  5. GenTableMapper genTableMapper;
  6. @Test
  7. public void test(){
  8. List<GenTable> genTables =
  9. genTableMapper.selectList(new QueryWrapper<>());
  10. }
  11. }

debug流程

1.发现 genTableMapper 是一个代理对象类型。

在这里插入图片描述

2.进入代理对象MybatisMapperProxy , 调用其invoke 方法,方法的Class类型为BaseMapper.selectList()

在这里插入图片描述

3.其中cachedInvoker()方法会返回一个PlainMethodInvoker ,它重写了MapperMethodInvoker 接口的invoke()方法

在这里插入图片描述

4.最终会调用MybatisMapperMethodexecute()方法

在这里插入图片描述

  1. public class MybatisMapperMethod {
  2. public Object execute(SqlSession sqlSession, Object[] args) {
  3. Object result;
  4. switch (command.getType()) {
  5. case INSERT: {
  6. Object param = method.convertArgsToSqlCommandParam(args);
  7. result = rowCountResult(sqlSession.insert(command.getName(), param));
  8. break;
  9. }
  10. case UPDATE: {
  11. Object param = method.convertArgsToSqlCommandParam(args);
  12. result = rowCountResult(sqlSession.update(command.getName(), param));
  13. break;
  14. }
  15. case DELETE: {
  16. Object param = method.convertArgsToSqlCommandParam(args);
  17. result = rowCountResult(sqlSession.delete(command.getName(), param));
  18. break;
  19. }
  20. case SELECT:
  21. if (method.returnsVoid() && method.hasResultHandler()) {
  22. executeWithResultHandler(sqlSession, args);
  23. result = null;
  24. } else if (method.returnsMany()) {
  25. result = executeForMany(sqlSession, args);
  26. } else if (method.returnsMap()) {
  27. result = executeForMap(sqlSession, args);
  28. } else if (method.returnsCursor()) {
  29. result = executeForCursor(sqlSession, args);
  30. } else {
  31. Object param = method.convertArgsToSqlCommandParam(args);
  32. // TODO 这里下面改了
  33. if (IPage.class.isAssignableFrom(method.getReturnType())) {
  34. result = executeForIPage(sqlSession, args);
  35. // TODO 这里上面改了
  36. } else {
  37. result = sqlSession.selectOne(command.getName(), param);
  38. if (method.returnsOptional()
  39. && (result == null || !method.getReturnType().equals(result.getClass()))) {
  40. result = Optional.ofNullable(result);
  41. }
  42. }
  43. }
  44. break;
  45. case FLUSH:
  46. result = sqlSession.flushStatements();
  47. break;
  48. default:
  49. throw new BindingException("Unknown execution method for: " + command.getName());
  50. }
  51. if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
  52. throw new BindingException("Mapper method '" + command.getName()
  53. + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
  54. }
  55. return result;
  56. }
  57. }

5.这是经过判断会进入executeForMany(sqlSession, args)方法,此时方法和参数都显示出来了。sqlSession的类型是SqlSessionTemplate , 为什么要注意这个 sqlSession的类型?因为SqlSession是一个接口,有很多实现类,有时候我们并不知道到底调用了哪个实现类的selectList()方法,这个时候我们看类型就知道了,就可以进入SqlSessionTemplate类,找到selectList()打上断点,debug就过来了。

在这里插入图片描述

6.利用同样的方法,又调用了DefaultSqlSessionselectList()方法。

在这里插入图片描述


7.来到DefaultSqlSessionselectList() 方法中,此时已经进入到mybatis的源码范围了。executor的类型是MybatisCachingExecutor

在这里插入图片描述

8.此时要注意MybatisCachingExecutor 代理类的handler是一个Plugin

在这里插入图片描述

在这里插入图片描述

9.因为我使用到了分页插件,所以会来到com.github.pagehelperPageInterceptor

在这里插入图片描述

10.由MybatisCachingExecutor来执行查询

在这里插入图片描述

11.MybatisCachingExecutor 委派 BaseExecutor 执行查询

在这里插入图片描述

在这里插入图片描述

12.最终委派到PreparedStatementHandler来处理

在这里插入图片描述

13.最后由DefaultResultSetHandler来封装结果集

  1. @Override
  2. public List<Object> handleResultSets(Statement stmt) throws SQLException {
  3. ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
  4.  
  5. final List<Object> multipleResults = new ArrayList<>();
  6. int resultSetCount = 0;
  7. ResultSetWrapper rsw = getFirstResultSet(stmt);
  8. List<ResultMap> resultMaps = mappedStatement.getResultMaps();
  9. int resultMapCount = resultMaps.size();
  10. validateResultMapsCount(rsw, resultMapCount);
  11. while (rsw != null && resultMapCount > resultSetCount) {
  12. ResultMap resultMap = resultMaps.get(resultSetCount);
  13. handleResultSet(rsw, resultMap, multipleResults, null);
  14. rsw = getNextResultSet(stmt);
  15. cleanUpAfterHandlingResultSet();
  16. resultSetCount++;
  17. }
  18. String[] resultSets = mappedStatement.getResultSets();
  19. if (resultSets != null) {
  20. while (rsw != null && resultSetCount < resultSets.length) {
  21. ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
  22. if (parentMapping != null) {
  23. String nestedResultMapId = parentMapping.getNestedResultMapId();
  24. ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
  25. handleResultSet(rsw, resultMap, null, parentMapping);
  26. }
  27. rsw = getNextResultSet(stmt);
  28. cleanUpAfterHandlingResultSet();
  29. resultSetCount++;
  30. }
  31. return collapseSingleResultList(multipleResults);
  32. }

总结

为什么要一层一层的封装?一层一层的委派?
这里面和缓存有关,有兴趣的可以自己了解一下。

下一篇打算记录一下 mybatis-plus 的自动配置过程,有兴趣的可以持续关注一下。
文中有错误的地方不吝赐教谢谢。

到此这篇关于mybatis-plus查询源码走读的文章就介绍到这了,更多相关mybatis-plus查询内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号