关注下方公众号,可以在公众号后台回复“博客园”,免费获得作者 Java 知识体系/面试必看资料。

最近查找一个生产问题的原因,需要深入研究 ibatis 框架的源码。虽然最后证明问题的原因与 ibatis 无关,但是这个过程加深了对 ibatis 框架原理的理解。

这篇文章主要就来讲讲 ibatis 框架的原理。

可能现在很多人已不再使用 ibatis 或者说也没听 ibatis,不过肯定了解过 Mybatis。ibatis 就是 Mybatis框架的前身,虽然 ibatis 框架已经比较老,但是其核心功能与 Mybatis 一致。

 ibatis 解决的痛点

我们先看一个使用 JDBC 查询的例子。

使用原生 JDBC 查询,存在两个痛点:

1. 使用非常繁琐,且需要处理各种数据库异常,并且还需要关闭各种资源。

2. 数据转化麻烦。查询之前需要从 Java 对象属性值设置到  PreparedStatement  中,查询返回之后又需要从 `ResultSet`获取返回设置到返回对象中。

在 ibatis 中封装这些繁杂数据库连接查询代码,并处理了各类异常以及关闭各种资源。另外 ibatis 自动处理 Java 对象与数据库类型之间的自动转化,让业务代码与 SQL 代码之间做到了解耦。

数据类型转化原理

数据类型转化主要分为两类,一,传入查询的 Java 对象数据转化成 SQL 类型数据。二 查询返回的数据库信息映射到 Java 对象中。

ibatis SQL 需要定义在配置文件中,一个查询 SQL 语句配置如下:

<select id="queryName" parameterClass="com.query.QueryDO"  resultClass="com.query.QueryDO" >
select * from TEST_QUERY where ID=#id#

ibatis 框架启动过程将会解析配置文件,生成  MappedStatement 的子类。如 select 配置会生成对应的 SelectStatement 对象。

MappedStatement 相关类图如下。

在  MappedStatement 中将会保存存在两个重要的对象,ParameterMap 与 ResultMap,通过这两个对象将会完成 Java 类型与数据库类型的相互转化。

Java 对象转化成数据库类型

 以上面 select 配置为例,我们这里需要做的是从传入的 com.query.QueryDO 对象中获取属性值,然后通过 PreparedStatement.setxx 设置到查询参数中。

ibatis 解析配置中 SQL 语句时,将会获取 # 之间的内容,将其替换成 ?。然后按照顺序保存到一个 ParameterMapping[] 数组中,这个数组将会保存到 ParameterMap 对象中。

ParameterMapping 将会保存解析字段相关信息。

最终解析后的 SQL 为:

select  * from  TEST_QUERY where ID=?

该 SQL 就可以通过  connection.prepareStatement("select * from  TEST_QUERY where ID=?"); 生成 PreparedStatement 对象。

接着 ibatis 会根据 ParameterMapping 和 parameterClass 指定的类型创建合适的 dataExchange 和 parameterPlan 对象。

其中 parameterPlan 对象会按照 ParameterMapping 数组中顺序保存了变量的 setter 和 getter 方法数组。

dataExchange 会按照 ParameterMapping  数组中的顺序使用反射获取 parameterPlan getter 方法返回值生成 parameters 数组。

最后循环 ParameterMapping 数组,在 TypeHandler 调用  PreparedStatement.setxx 设置相关值。

TypeHandler 存在很多子类,通过这些子类正确处理了 Java 对象与数据库类型转化。

转化的时序图为:

时序图来源于:https://www.ibm.com/developerworks/cn/java/j-lo-ibatis-principle/index.html

数据库字段映射到 Java 对象

SQL 执行结束之后将会返回查询结果,这里将会使 SQL 查询结果转化为返回结果 com.query.QueryDO。这里需要用到上面提到 ResultMap  对象。

当 SQL 执行结束返回 ResultSet 对象之后,使用 ResultSet.getMetaData() 获取返回信息元数据对象 ResultSetMetaData 。

从 ResultSetMetaData 可以获取返回结果字段名,类型等信息,然后按照顺序存入 ResultMapping 数组中。

然后按照 ResultMapping 数组中使用 TypeHandler调用 ResultSet.getxx 获取实际返回数据,保存到 columnValues 数组中。

在 ResultMap 对象会根据  ResultMapping 与 resultClass指定的类型合适的 dataExchange 和 resultPlan对象。resultPlan对象与上面的  parameterPlan 对象一样也会保存着变量的 setter 和 getter 方法数组。

最后先根据 resultClass 反射生成返回对象,然后使用反射调用 resultPlan  setter 方法,依次设置相关值。

映射返回对象时序图为:


时序图来源于:https://www.ibm.com/developerworks/cn/java/j-lo-ibatis-principle/index.html

ibatis 样板代码

上面讲完了 ibatis 数据类型的转化原理,接着我们来看下 ibatis 调用 JDBC 样板代码。

使用 ibatis 执行查询语句时,如 queryForObject ,调用到 SqlMapExecutorDelegate  。在  SqlMapExecutorDelegate  中将会会做一些前提准备,比如准备事务,最后会将 SQL 语句委托给 SqlExecutor 执行。

这里使用委托者模式,接受请求的对象将请求委托给另一个对象来处理。这种模式的优点在于解耦了业务代码与实际执行代码的联系,在于对外隐藏真正执行对象,易于扩展。

在 SqlExecutor#executeQuery  执行过程主要分为以下三步。

第一步,获取 PreparedStatement,使用 conn.prepareStatement(sql) 获取。

第二步调用 PreparedStatement.setxxx 方法设置参数。上文中的 Java 对象类型转化成 SQL 类型在这里完成。

第三步,调用 PreparedStatement.execute() 执行 SQL 语句。

第四步,使用 ResultSet 获取返回值,在这一步将会完成 数据库类型与 Java 类型的转化。

帮助链接

References

[1] 深入分析 iBATIS 框架之系统架构与映射原理: https://www.ibm.com/developerworks/cn/java/j-lo-ibatis-principle/index.html

欢迎长按下图关注公众号Java极客技术,后台回复“资料”,获取作者独家秘制精品资料

Java 极客技术公众号,是由一群热爱 Java 开发的技术人组建成立,专注分享原创、高质量的 Java 文章。如果您觉得我们的文章还不错,请帮忙赞赏、在看、转发支持,鼓励我们分享出更好的文章。

ibatis 核心原理解析!的更多相关文章

  1. ibatis 核心原理解析

    最近查找一个生产问题的原因,需要深入研究 ibatis 框架的源码.虽然最后证明问题的原因与 ibatis 无关,但是这个过程加深了对 ibatis 框架原理的理解. 这篇文章主要就来讲讲 ibati ...

  2. 【算法】(查找你附近的人) GeoHash核心原理解析及代码实现

    本文地址 原文地址 分享提纲: 0. 引子 1. 感性认识GeoHash 2. GeoHash算法的步骤 3. GeoHash Base32编码长度与精度 4. GeoHash算法 5. 使用注意点( ...

  3. Java并发包JUC核心原理解析

    CS-LogN思维导图:记录CS基础 面试题 开源地址:https://github.com/FISHers6/CS-LogN JUC 分类 线程管理 线程池相关类 Executor.Executor ...

  4. 「进阶篇」Vue Router 核心原理解析

    前言 此篇为进阶篇,希望读者有 Vue.js,Vue Router 的使用经验,并对 Vue.js 核心原理有简单了解: 不会大篇幅手撕源码,会贴最核心的源码,对应的官方仓库源码地址会放到超上,可以配 ...

  5. Promise核心原理解析

    作者: HerryLo 本文永久有效链接: https://github.com/AttemptWeb...... Promises对象被用于表示一个异步操作的最终完成 (或失败), 及其结果值.主要 ...

  6. NameServer 核心原理解析

    在之前的文章中,已经把 Broker.Producer 和 Conusmer 的部分源码和核心的机制介绍的差不多了,但是其实 RocketMQ 中还有一个比较关键但是我们平时很容易忽略的组件--Nam ...

  7. 【转】GeoHash核心原理解析

    好久没更新过博客了,先转载一篇文章吧. 源地址:http://www.cnblogs.com/LBSer/p/3310455.html 引子 机机是个好动又好学的孩子,平日里就喜欢拿着手机地图点点按按 ...

  8. GeoHash核心原理解析

    http://www.cnblogs.com/LBSer/p/3310455.html 引子 机机是个好动又好学的孩子,平日里就喜欢拿着手机地图点点按按来查询一些好玩的东西.某一天机机到北海公园游玩, ...

  9. [转]GeoHash核心原理解析

    原文出处: zhanlijun    引子 机机是个好动又好学的孩子,平日里就喜欢拿着手机地图点点按按来查询一些好玩的东西.某一天机机到北海公园游玩,肚肚饿了,于是乎打开手机地图,搜索北海公园附近的餐 ...

随机推荐

  1. 深度残差网络(ResNet)

    引言 对于传统的深度学习网络应用来说,网络越深,所能学到的东西越多.当然收敛速度也就越慢,训练时间越长,然而深度到了一定程度之后就会发现越往深学习率越低的情况,甚至在一些场景下,网络层数越深反而降低了 ...

  2. Vue兄弟组件(非父子组件)状态共享与传值

      前言:网上大部分文章写的有点乱,很少有讲得易懂的文章. 所以,我写了篇在我能看得懂的基础上又照顾到大家的文章 =.= 作者:X1aoYE 备注:此文原创,转载请注明~  内容里的<br> ...

  3. POJ 2987:Firing(最大权闭合图)

    http://poj.org/problem?id=2987 题意:有公司要裁员,每裁一个人可以得到收益(有正有负),而且如果裁掉的这个人有党羽的话,必须将这个人的所有党羽都裁除,问最少的裁员人数是多 ...

  4. springMVC java.lang.IllegalStateException: getOutputStream() has already bee

    在导出文件的时候,一直报这个错误. 网上一般的做法是out.clear();或者使用servlet或者Action返回null. 试过了这些方法都不成功. 最后直到试了在jsp重定向的方法才成功了. ...

  5. PLT与GOT

    0x01  什么是PLT和GOT 名称: PLT : 程序链接表(PLT,Procedure Link Table) GOT : 重局偏移表(GOT, Global Offset Table) 缘由: ...

  6. 如何让使用create-react-app构建的项目在build过程中如何不生成.map文件

    避免create-react-app的项目在build的过程中生成 .map 文件的方法:主要是更改 package.json 里面的 build 命令!正式进入修改步骤前,推荐安装 cross-en ...

  7. SpringCloud解析之Ribbon

    Ribbon是分布式微服务架构中负载均衡的一个解决方案,我们只需要引入ribbon依赖,然后初始化一个RestTemplate对象,在其上添加@LoadBalanced注解,就可以实现请求的负载均衡, ...

  8. BASE64Encoder及BASE64Decoder的正确用法

    一直以来Base64的加密解密都是使用sun.misc包下的BASE64Encoder及BASE64Decoder的sun.misc.BASE64Encoder/BASE64Decoder类.这人个类 ...

  9. [MySQL]快速解决"Table '.\sjzlf\zbp_post' is marked as crashed and should be repaired"故障

    为了不冒失修复,故采取保守做法,我们知道 MySQL 一个高效的管理工具便是 PhpMyAdmin,而在该管理软件中就包含了对表的检查.分析.修复.优化功能,比起网上提供的含糊命令行来说更安全更简便. ...

  10. mybatis学习(五)(动态mybatis(多条件查询))

    有时候要查询条件是多条件的,尤其是使用mybatis的时候如何创建sql语句呢? 这里mybatis有自己的办法,如下: 案例:通过传入map,根据map里面的数据来查询 mapper配置如下: &l ...