




已阅读5页,还剩6页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
MyBatis 源码分析 SQL 语句执行的完整流程 MyBatis 是支持定制化 SQL 存储过程以及高级映射的优秀的持久层框架 MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集 MyBatis 可以对配置和原生 Map 使用 简单的 XML 或注解 将接口和 Java 的 POJOs Plain Old Java Objects 普通的 Java 对象 映射成数据库中的记录 如何新建 MyBatis 源码工程请点击 MyBatis 源码分析 IDEA 新建 MyBatis 源码工 程 MyBatis 框架主要完成的是以下 2 件事情 根据 JDBC 规范建立与数据库的连接 通过反射打通 Java 对象与数据库参数交互之间相互转换的关系 MyBatis 框架是一种典型的交互式框架 先准备好交互的必要条件 然后构建一个交互的环境 在交互环境中划分会话 在会话中与数据库进行交互数据 1 MyBatis 主要的类 Configuration MyBatis 所有的配置信息都维持在 Configuration 对象之中 SqlSession 作为 MyBatis 工作的主要顶层 API 表示和数据库交互的会话 完成必要数据库增删改查功能 Executor MyBatis 执行器 是 MyBatis 调度的核心 负责 SQL 语句的生成和查询缓存的维护 StatementHandler 封装了 JDBC Statement 操作 负责对 JDBC statement 的操作 如设置参数 将 Statement 结果集转换成 List 集合 ParameterHandler 负责对用户传递的参数转换成 JDBC Statement 所需要的参数 ResultSetHandler 负责将 JDBC 返回的 ResultSet 结果集对象转换成 List 类型的集合 TypeHandler 负责 java 数据类型和 jdbc 数据类型之间的映射和转换 MappedStatement MappedStatement 维护了一条节点的封装 SqlSource 负责根据用户传递的 parameterObject 动态地生成 SQL 语句 将信息封装到 BoundSql 对象中 并返回 BoundSql 表示动态生成的 SQL 语句以及相应的参数信息 以上几个类在 SQL 操作中都会涉及 在 SQL 操作中重点关注下 SQL 参数什么时候写入和结果集怎么转换为 Java 对象 这两个过程正好对应的类是 PreparedStatementHandler 和 ResultSetHandler 类 图片来自 深入理解 mybatis 原理 MyBatis 的架构设计以及实例分析 2 SQL 执行流程 MyBatis 主要设计目的还是为了让我们在执行 SQL 时对输入输出的数据的管理更加方便 所以方便的让我们写出 SQL 和方便的获取 SQL 的执行结果是 MyBatis 的核心竞争力 下面就用一 个例子来从源码角度看一下 SQL 的完整执行流程 新建配置文件 conf xml conf xml 首先建立数据表 这里就以 user 表为例 复制代码 DROP TABLE IF EXISTS user CREATE TABLE user id INT NOT NULL PRIMARY KEY AUTO INCREMENT name VARCHAR 32 NOT NULL password VARCHAR 32 NOT NULL sex int email VARCHAR 32 phone VARCHAR 16 admin VARCHAR 16 复制代码 然后新建与数据表对应的类 User User 再新建 usre 表的配置文件 userMapper xml 最后新建测试类 复制代码 MyBatis 测试类 public class TestMain public static void main String args throws IOException String resouce conf xml InputStream is Resources getResourceAsStream resouce 构建 sqlSession 工厂 SqlSessionFactory sqlSessionFactory new SqlSessionFactoryBuilder build is 获取 sqlSession SqlSession session sqlSessionFactory openSession User user try 第一种方式 直接执行已映射的 SQL 语句 String statement com luoxn28 dao UserDao getById user session selectOne statement 1 System out println user finally session close 第二种方式 执行更清晰和类型安全的代码 UserDao userDao session getMapper UserDao class user userDao getById 1 System out println user 复制代码 由于我们分析的是 SQL 的执行流程 那就重点关注下 user session selectOne statement 1 这行代码 注意 传进去的参数是 1 session 是 DefaultSqlSession 类型的 因为 sqlSessionFactory 默认生成的 SqlSession 是 DefaultSqlSession 类型 selectOne 会调用 selectList 复制代码 DefaultSqlSession 类 public List selectList String statement Object parameter RowBounds rowBounds try MappedStatement ms configuration getMappedStatement statement CURD 操作是交给 Excetor 去处理的 return executor query ms wrapCollection parameter rowBounds Executor NO RESULT HANDLER catch Exception e throw ExceptionFactory wrapException Error querying database Cause e e finally ErrorContext instance reset 复制代码 在 DefaultSqlSession selectList 中的各种 CURD 操作都是通多 Executor 进行的 这里 executor 的类型是 CachingExecutor 接着跳转到其中的 query 方法中 CachingExecutor 类 public List query MappedStatement ms Object parameterObject RowBounds rowBounds ResultHandler resultHandler throws SQLException BoundSql boundSql ms getBoundSql parameterObject 获取绑定的 sql 命令 比如 SELECT FROM xxx CacheKey key createCacheKey ms parameterObject rowBounds boundSql return query ms parameterObject rowBounds resultHandler key boundSql getBoundSql 为了获取绑定的 sql 命令 在创建完 cacheKey 之后 就进入到 CachingExecutor 类中的另一个 query 方法中 复制代码 CachingExecutor 类 Override public List query MappedStatement ms Object parameterObject RowBounds rowBounds ResultHandler resultHandler CacheKey key BoundSql boundSql throws SQLException Cache cache ms getCache if cache null flushCacheIfRequired ms if ms isUseCache SuppressWarnings unchecked List list List tcm getObject cache key if list null list delegate query ms parameterObject rowBounds resultHandler key boundSql tcm putObject cache key list issue 578 and 116 return list return delegate query ms parameterObject rowBounds resultHandler key boundSql 复制代码 这里真正执行 query 操作的是 SimplyExecutor 代理来完成的 接着就进入到了 SimplyExecutor 的父类 BaseExecutor 的 query 方法中 复制代码 SimplyExecutor 的父类 BaseExecutor 类 SuppressWarnings unchecked Override public List query MappedStatement ms Object parameter RowBounds rowBounds ResultHandler resultHandler CacheKey key BoundSql boundSql throws SQLException ErrorContext instance resource ms getResource activity executing a query object ms getId if closed throw new ExecutorException Executor was closed if queryStack 0 List list try queryStack localCache 是一级缓存 如果找不到就调用 queryFromDatabase 从数据库中查找 list resultHandler null List localCache getObject key null if list null handleLocallyCachedOutputParameters ms key parameter boundSql else list queryFromDatabase ms parameter rowBounds resultHandler key boundSql finally queryStack if queryStack 0 for DeferredLoad deferredLoad deferredLoads deferredLoad load issue 601 deferredLoads clear if configuration getLocalCacheScope LocalCacheScope STATEMENT issue 482 clearLocalCache return list 复制代码 因为是第一次 SQL 查询操作 所以会调用 queryFromDatabase 方法来执行查询 复制代码 SimplyExecutor 的父类 BaseExecutor 类 private List queryFromDatabase MappedStatement ms Object parameter RowBounds rowBounds ResultHandler resultHandler CacheKey key BoundSql boundSql throws SQLException List list localCache putObject key EXECUTION PLACEHOLDER try list doQuery ms parameter rowBounds resultHandler boundSql finally localCache removeObject key localCache putObject key list if ms getStatementType StatementType CALLABLE localOutputParameterCache putObject key parameter return list 复制代码 从数据库中查询数据 进入到 SimplyExecutor 中进行操作 复制代码 SimplyExecutor 类 public List doQuery MappedStatement ms Object parameter RowBounds rowBounds ResultHandler resultHandler BoundSql boundSql throws SQLException Statement stmt null try Configuration configuration ms getConfiguration StatementHandler handler configuration newStatementHandler wrapper ms parameter rowBounds resultHandler boundSql 子流程 1 SQL 查询参数的设置 stmt prepareStatement handler ms getStatementLog StatementHandler 封装了 Statement 子流程 2 SQL 查询操作和结果集的封装 return handler query stmt finally closeStatement stmt 复制代码 注意 在 prepareStatement 方法中会进行 SQL 查询参数的设置 也就是咱们最开始传递进来的参数 其值为 1 handler query stmt 方法中会进行实际的 SQL 查询操作和结果集的封装 封装成 Java 对象 当流程走到这里时 程序已经压栈有一定深度了 因为接下来程序分析会兵分两路 一方面深入到 SQL 查询及结果集的设置子流程 1 中 然后再深入到 SQL 查询操作和 结果集的封装子流程 2 因为还会回到这里 所以就来一张调用栈的特写吧 子流程 1 SQL 查询参数的设置 复制代码 SimplyExecutor 类 private Statement prepareStatement StatementHandler handler Log statementLog throws SQLException Statement stmt 获取一个 Connection Connection connection getConnection statementLog stmt handler prepare connection transaction getTimeout handler parameterize stmt 设置 SQL 查询中的参数值 return stmt 复制代码 通过 getConnection 方法来获取一个 Connection 调用 prepare 方法来获取一个 Statement 这里的 handler 类型是 RoutingStatementHandler RoutingStatementHandler 的 prepare 方法调用 的是 PrepareStatementHandler 的 prepare 方法 因为 PrepareStatementHandler 并没有覆盖其父类的 prepare 方法 其实最后调用的是 BaseStatementHandler 中的 prepare 方法 是不是绕晕了 那就再看一遍吧 调用 parameterize 方法来设置 SQL 的参数值 这里最后调用的是 PrepareStatementHandler 中的 parameterize 方法 而 PrepareStatementHandler parameterize 方法调用 的是 DefaultParameterHandler 中的 setParameters 方法 PrepareStatementHandler 类 Override public void parameterize Statement statement throws SQLException parameterHandler setParameters PreparedStatement statement 复制代码 DefaultParameterHandler 类 Override public void setParameters PreparedStatement ps ErrorContext instance activity setting parameters object mappedStatement getParameterMap getId List parameterMappings boundSql getParameterMappings if parameterMappings null for int i 0 i parameterMappings size i 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 typeHandler parameterMapping getTypeHandler JdbcType jdbcType parameterMapping getJdbcType if value null try typeHandler setParameter ps i 1 value jdbcType catch TypeException e throw new TypeException Could not set parameters for mapping parameterMapping Cause e e catch SQLException e throw new TypeException Could not set parameters for mapping parameterMapping Cause e e 复制代码 到这里为止 已经给 Statement 设置了最初传递进去的参数 值为 1 了 那么接着分析流程 2 流程 2 SQL 查询及结果集的设置 RoutingStatementHandler 类 Override public List query Statement statement throws SQLException return delegate query statement 复制代码 RoutingStatementHandler 类 Override public List query Statement statement throws SQLException 这里就到了熟悉的 PreparedStatement 了 PreparedStatement ps PreparedStatement statement 执行 SQL 查询操作 ps execute 结果交给 ResultHandler 来处理 return resultSetHandler handleResultSets ps 复制代码 复制代码 DefaultResultSetHandler 类 封装返回值 将查询结果封装成 Object 对象 Override public List handleResultSets Statement stmt throws SQLException ErrorContext instance activity handling results object mappedStatement getId final List multipleResults new ArrayList int resultSetCount 0 ResultSetWrapper rsw getFirstResultSet stmt List resultMaps mappedStatement getResultMaps int resultMapCount resultMaps size validateResultMapsCount rsw resultMapCount while rsw null handleResultSet rsw resultMap multipleResults null rsw getNextResultSet stmt cleanUpAfterHandlingResultSet resultSetCount String resultSets mappedStatement getResultSets if resultSets null while rsw null 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 复制代码 ResultSetWrapper 是 ResultSet 的包装类 调用 getFirstResultSet 方法获取第一个 ResultSet 同时获取数据库的 MetaData 数据 包括数据表列名 列的类型 类序号等 这些信息都存储在 ResultSetWrapper 类中了 然后调用 handleResultSet 方法来来进行结果集的封装 复制代码 DefaultResultSetHandler 类 private void handleResultSet ResultSetWrapper rsw ResultMap resultMap List multipleResults ResultMapping parentMapping throws SQLException try if parentMapping null handleRowValues rsw resultMap null RowBounds DEFAULT parentMapping else if resultHandler null DefaultResultHandler defaultResultHandler new DefaultResultHandler objectFactory handleRowValues rsw resultMap defaultResultHandler rowBounds null multipleResults add defaultResultHandler getResultList else handleRowValues rsw resultMap resultHandler rowBounds null finally issue 228 close resultsets closeResultSet rsw getResultSet 复制代码 这里调用 handleRowValues 方法来进行值的设置 复制代码 DefaultResultSetHandler 类 public void handleRowValues ResultSetWrapper rsw ResultMap resultMap ResultHandler resultHandler RowBounds rowBounds ResultMapping parentMapping throws SQLException if resultMap hasNestedResultMaps ensureNoRowBounds checkResultHandler handleRowValuesForNestedResultMap rsw resultMap resultHandler rowBounds parentMapping else 封装数据 handleRowValuesForSimpleResultMap rsw resultMap resultHandler rowBounds parentMapping 复制代码 复制代码 DefaultResultSetHandler 类 封装数据 private void handleRowValuesForSimpleResultMap ResultSetWrapper rsw ResultMap resultMap ResultHandler resultHandler RowBounds rowBounds ResultMapping parentMapping throws SQLException DefaultResultContext resultContext new DefaultResultContext skipRows rsw getResultSet rowBounds while shouldProcessMoreRows resultContext rowBounds Object rowValue getRowValue rsw discriminatedResultMap storeObject resultHandler resultContext rowValue parentMapping rsw getResultSet 复制代码 复制代码 DefaultResultSetHandler 类 private Object getRowValue ResultSetWrapper rsw ResultMap resultMap throws SQLException final ResultLoaderMap lazyLoader new ResultLoaderMap createResultObject 为新创建的对象 数据表对应的类 Object resultObject createResultObject rsw resultMap lazyLoader null if resultObject null boolean foundValues resultMap getConstructorResultMappings isEmpty if shouldApplyAutomaticMpings resultMap false 这里把数据填充进去 metaObject 中包含了 resultObject 信息 foundValues applyAutomaticMappings rsw resultMap metaObject null foundValues foundValues applyPropertyMappings rsw resultMap metaObject lazyLoader null foundValues foundValues lazyLoader size 0 foundValues resultObject foundValues resultObject n
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025-2030工业互联网平台建设与制造业智能化转型战略咨询报告
- 疫情下的食品供应链安全-洞察及研究
- 2025-2030工业互联网平台商业化模式创新与市场增长预测报告
- 2025-2030工业互联网平台发展现状与投资机会分析研究报告
- 2025-2030工业互联网安全防护体系构建与风险评估分析报告
- 2025-2030工业互联网安全威胁情报共享机制构建分析报告
- 2025-2030工业互联网产业园数字化转型解决方案研究
- 企业社会责任战略规划-洞察及研究
- 开采风险预警系统构建-洞察及研究
- 森林砍伐对土壤碳循环影响-洞察及研究
- 河北省石家庄第二十八中学2023-2024学年八年级上学期10月月考语文试题
- 大学语文17北方省公开课金奖全国赛课一等奖微课获奖课件
- YYT 0664-2008 医疗器械软件 软件生存周期过程
- 小学六年级分数乘法练习题【基础题】
- 2024版人教版英语初一上单词默写表
- 双下肢乏力护理查房
- GB/T 22084.2-2024含碱性或其他非酸性电解质的蓄电池和蓄电池组便携式密封蓄电池和蓄电池组第2部分:金属氢化物镍电池
- 个人律师费收款收据
- 欢乐的那达慕混声合唱谱
- 《生物医学工程》课件
- 智能机器人技术与应用
评论
0/150
提交评论