- 1、传统方式
- 1、编写测试类
- 2、如何将配置文件读取成字节输入流
- 3、如何解析配置文件的呢?
- 源码剖析-执行SQL流程
- 4、openSession如何生成SqlSession
- 5、sqlSession调用方法的具体流程
- 6、执行器executor源码剖析
- 7、StatementHandler的源码剖析
- 1、点击进入parameterize方法
- 2、点击进入默认实现类
- 3、点击进入setParameters方法查看如何赋值
- 4、点击进入实现类
- 5、实现了StatementHandler委托typeHandler操作
- 6、点击进入SimpleExecutor类的query
- 7、点击进入query方法的实现类
- 8、点击进入handleResultSets方法
- 9、点击进入其实现类
- 10、点击进入getFirstResultSet
- 11、将 ResultSet 对象,封装成 ResultSetWrapper 对象进行返回
- 12、再点击进入handleResultSets方法的handleResultSet方法
- 13、处理 ResultSet ,将结果添加到 multipleResults 中
- 2、Mapper代理的方式
- 设计模式
1、传统方式
1、编写测试类
2、如何将配置文件读取成字节输入流
// 1. 读取配置文件,读成字节输入流,注意:现在还没解析
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
1、点击进入getResourceAsStream方法
2、点击进入getResourceAsStream的重载方法
3、根据配置文件的路径加载为字节输入流
3、如何解析配置文件的呢?
// 2. 解析配置文件,封装Configuration对象 创建DefaultSqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
1、点击进入build方法
build方法1、是解析配置文件。2、是创建SqlSessionFactory实现类对象
2、点击进入重载方法
3、点击进入parse方法
4、点击进入parseConfiguration方法
解析 XML 成 Configuration 对象
5、点击进入properties解析方法
6、对properties标签进行解析并将结果存到Configration对象中
7、同时解析 标签
还有很多细节的部分。
8、点击进入build方法(参数是封装后的Configration)
9、创建DefaultSqlSessionFactory对象
最后将封装好的对象,进行返回。然后就能从里面取出对应的方法进行使用了。
源码剖析-执行SQL流程
SqlSession:
SqlSession是一个接口, 它有两个实现类:DefaultSqlSession(默认) 和 SqlSessionManager(弃用,不做介绍)
SqlSession是MyBatis中用于和数据库交互的顶层类, 通常将它与ThreadLocal绑定, 一个会话使用一个SqlSession(是线程不安全的), 并且在使用完毕后需要close。
public class DefaultSqlsession implements SqlSession{
private final Configuration configuration;
private final Executor executor;
sqlsession中的两个最重要的参数, configuration与初始化时的相同, Executor为执行器
Executor:
Executor也是一个接口, 他有三个常用的实现类:
- Batch Executor(重用语句并执行批量更新)
- Reuse Executor
- simple Executor(普通的执行器, 默认)
继续分析, 初始化完毕后, 我们就要执行SQL了
(重用预处理语句preparedstatements)
4、openSession如何生成SqlSession
// 3. 生产了DefaultSqlsession实例对象 设置了事务不自动提交 完成了executor对象的创建
SqlSession sqlSession = sqlSessionFactory.openSession();
1、点进入openSession
2、进入DefaultSqlSessionFactory实现类
进入到实现类工厂
3、点击进入默认执行器的类型
(调用的是无参的openSession方法嘛!)
4、点击进入defaultExecutorType
5、ExecutorType.SIMPLE类型
6、点击进入openSessionFromDataSource方法
7、创建实现类对象
5、sqlSession调用方法的具体流程
上面已经返回的是new DefaultSqlSession对象,返回Sqlsession,接下来可以调用Sqlsession里面的方法了。
第五小步截图有清晰的分析。
// 4.(1)根据statementid,从Configuration中map集合中获取到了指定的MappedStatement对象
//(2)将查询任务委派了executor执行器
List<Object> objects = sqlSession.selectList("namespace.id");
1、点击进入selectList
2、点击进入DefaultSqlSession实现类
3、继续点击进入重载方法
4、继续点击进入重载方法
5、最终调用执行器的query方法
6、执行器executor源码剖析
1、点击进入query方法
2、点击进入query的实现类
3、在BaseExecutor父类中查看具体实现
4、点击进入query的方法
5、进入queryFromDatabase方法去数据库中取
6、点击进入doQuery查看数据库真正的读操作
7、点击进入实现类
8、点击进入调用预编译
9、初始化 StatementHandler 对象
10、委托StatementHandler的query方法去执行
7、StatementHandler的源码剖析
(自定义封装的是通过反射封装到对象,这里是通过StatementHandler处理,具体如下:)
1、点击进入parameterize方法
2、点击进入默认实现类
3、点击进入setParameters方法查看如何赋值
4、点击进入实现类
5、实现了StatementHandler委托typeHandler操作
@SuppressWarnings("Duplicates")
@Override
public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
// 遍历 ParameterMapping 数组
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings != null) {
for (int i = 0; i < parameterMappings.size(); i++) {
// 获得 ParameterMapping 对象
ParameterMapping parameterMapping = parameterMappings.get(i);
if (parameterMapping.getMode() != ParameterMode.OUT) {
// 获得值
Object value;
String propertyName = parameterMapping.getProperty();
if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
// 获得 typeHandler、jdbcType 属性
TypeHandler typeHandler = parameterMapping.getTypeHandler();
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) {
jdbcType = configuration.getJdbcTypeForNull();
}
// 设置 ? 占位符的参数
try {
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (TypeException | SQLException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
}
}
}
}
}
6、点击进入SimpleExecutor类的query
handler.query(stmt, resultHandler);进行了查询,并将结果集封装。具体如下:
7、点击进入query方法的实现类
8、点击进入handleResultSets方法
9、点击进入其实现类
10、点击进入getFirstResultSet
11、将 ResultSet 对象,封装成 ResultSetWrapper 对象进行返回
12、再点击进入handleResultSets方法的handleResultSet方法
将_ResultSet 结果添加到 multipleResults 中_
13、处理 ResultSet ,将结果添加到 multipleResults 中
具体的添加如下:
2、Mapper代理的方式
1、使用方式如下
1、先添加一个接口类及接口方法
2、使用JDK动态代理对mapper接口产生代理对象
3、添加扫描的配置文件
4、用3的方式扫描接口、当完成2的操作后,还要去做build操作.
具体要看源码进行查看
2、build方法的源码剖析
1、先点击如build方法
2、再继续进入
3、点击进入parse方法
4、点击进入parseConfiguration方法
5、点击进入mapperElement方法
6、点击进入addMappers方法
7、再点击进入mapperRegistry
8、点击进入MapperRegistry对象
9、每一个接口对应着一个工厂
3、getMapper方法的源码剖析
mapperProxyFactory的先创建,然后实例化MapperProxy对象。再进行实例化newInstance
MapperProxy实现了InvocationHandler接口,必然上面调用时候会执行invoke
invoke方法里面调用mapperMethod.execute()方法,去判断&执行底层sql
1、点击进入getMapper方法
2、点击进入实现类
3、再点击进入configuration.getMapper
4、点击进入mapperRegistry.getMapper方法
5、点击进入newInstance方法
代理工厂是如何创建实例的。怎么返回的代理对象直接能调用方法了呢?具体如下:
6、点击进入MapperProxy
进到_MapperProxyFactory类中的newInstance方法,又是通过_MapperProxy对象进行实例化来操作的。
7、通过newProxyInstance验证底层执行动态代理
下面这个是调用上面的 newInstance
8、点击进入mapperProxy方法
参数是mapperProxy,那么他的对象是什么呢,点进去看其类如何。
执行动态代理的时候,底层调用任何方法。都会去调用MapperProxy里面的invoke方法。
因为MapperProxy实现了InvocationHandler,当方法调用时,都会进到其里面的invoke方法。
4、invoke方法源码剖析
1、点击进入MapperProxy
2、点击进入execute方法
直接看到invoke方法。
3、点击进入executeForMany
因为当前接口的返回方法中的返回值 一个List集合。
4、具体还是sqlSession去操作
设计模式
https://blog.csdn.net/TNT_D/article/details/96832857?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromBaidu-1.edu_weight&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromBaidu-1.edu_weight
java 连接数据库实现增删改查的底层原理(源码)_TNT_D的…_CSDN博客
MyBatis的源码剖析例子https://blog.csdn.net/l1028386804/article/details/118079011