- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
很好奇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
查询总结:
映射总结:
最后此篇关于一次Mybaits查询的源码分析的文章就讲到这里了,如果你想了解更多关于一次Mybaits查询的源码分析的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
mybatis本身没有提供日志的实现,引入的是第三方组件。mybatis支持多个第三方日志插件,优先级由低到高为slf4J、commonsLoging、Log4J2、Log4J和JdkLog。 m
MyBatis 简介 MyBatis的前身叫iBatis,本是apache的一个开源项目, 2010年这个项目由apache software foundation 迁移到了google code
我是一名优秀的程序员,十分优秀!