文章目录
Mybatis版本3.5.2
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
看源码不要着急,一步一个脚印,多想想,多看看~
我们为什么要使用接口来开发?
答案只有两个字:解耦
1、Mybatis的执行流程
通过阅读Mybatis源码我们可以知道,我们在执行一个Mybatis程序的时候,
- 首先会通过Resources类来获取mybatis核心配置文件;
- 然后再去实例化SqlSessionFactory构造器
- 取得构造器之后,再通过XMLConfigBuilder去解析mybatis配置文件,取得配置信息
- 再实例化SqlSessionFactory
1.1 首先会通过Resources类来加载mybatis核心配置文件
1.2 通过SqlSessionFactoryBuilder的build方法来创建SqlSessionFactory
进入源码
1.2.1 进入build方法
我们可以发现,它又去调用了另一个build方法,点过去看看
点过去之后我们发现,它通过inputStream这些东西取得了一个XMLConfigBuilder对象
1.2.1.1 我们通过源码可以发现这个SqlSesionFactoryBuilder对象又调用了一个parse方法
1.2.1.2 我们进入parse方法看看做了什么
parse方法去解析了configuration节点下的子节点,解析完成之后将解析的结果放到Configuration对象中
1.2.1.3 我们返回使用Configuration对象的方法,发现它将这个Configuration又交给了一个build方法
1.2.1.4 我们进入到这个build方法之后发现,它通过这个Configuration对象创建了一个DefaultSqlSessionFactory对象
(DefaultSqlSessionFactory是SqlSessionFactory的实现类,为什么不直接new一个DefaultSqlSessionFactory对象出来?
因为我们new的话需要一个Configuration对象,但是这个对象我们直接没有,所以就直接把xml字节流给SqlSessionFactoryBuilder,我们的DefaultSqlSessionFactory就不用去找Configuration怎么来;这是一种设计模式)
1.2.2 现在我们已经有DefaultSqlSessionFactory对象了,就可以去openSession了
1.2.2.1 进入DefaultSqlSessionFactory类中我们可以发现,这个openSession方法又去调用了一个openSessionFromDataSource方法
1.2.2.2 进入这个方法后我们可以看到
- 通过我们的Configuration对象得到环境变量
- 通过环境变量去实例化了一个事务工厂TransactionFactory
- 事务工厂通过这些参数帮我们产生了transaction进行事务管理
- 又通过transaction对象创建了Executor执行器(这个Executor就相当于JDBC中的Statement用来发送执行SQL语句)
1.3 现在我们就可以得到SqlSession了,有了SqlSession我们就可以去执行sql语句了
1.3.1 我们进入sqlSession.getMapper();方法去看一下怎么执行的
1.先找到它的实现类
2.我们进入之后可以发现它的实现类又调用了一个getMapper方法
3.进入这个getMapper方法之后我们可以发现他又是通过mapperRegistry去getMapper的
4.进入mapperRegistry的getMapper
我们可以发现它通过一个HashMap来存储配置文件中的mappers标签的每个mapper接口
5.进入newInstance方法之后发现它是通过JDK动态代理帮Mapper接口生成代理类
5.代理对象的getUserList方法是走的MapperProxy的invoke方法
6.在invoke方法中又去走execute方法
进来之后我们可以发现这里先是判断我们执行的sql语句是什么,然后又去调用了一个executeWithResultHandler,我们选select类型
7.executeWithResultHandler又去调用我们DefaultSqlSession中select方法
8.这个select又调用了另一个select方法,我们可以发现他是通过executor来执行查询操作的
9.我们的executor先走二级缓存来查询
关于缓存
这里它又调用了一个query方法
10.进入这个query方法之后我们发现,它是判断二级缓存中有没有,没有的话就去一级缓存查
11.我们进入在一级缓存查询的查询方法发现,如果一级缓存中没有,它才去数据库中查询
12.从数据库中查出来之后就把它放到一级缓存中去
13.一级缓存就是一个HashMap
2、使用注解开发
2.1 开发流程
1.注解在接口上实现
@Select("select * from user")
List<User> getUsers();
2.需要在核心配置文件中绑定接口
<!--绑定接口-->
<mappers>
<mapper class="com.hao.dao.UserMapper"/>
</mappers>
3.测试
@Test
public void testGetUsers() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
//底层主要应用反射
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getUsers();
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
注解本质:反射机制实现
底层:动态代理
我们使用注解开发可以省去配置xml文件,但是不建议使用注解开发,因为注解开发存在局限性,并且不能处理复杂的场景,或者说是不能处理一对多、多对多、动态sql这些场景,这些场景在后面都会说。