主要之前也是没怎么用过源生的orm框架,这边最近看了几个视频讲解mybatis的,然后自己也手写了一下简易源码,这里学习记录一下
一.orm框架发展史
源生JDBC ——> 数据库DbUtils(Apache DbUtils,Spring JDBC Template)–>orm(Mybatis Hibernate)
1.然后我们先看一下 如果直接在JDBC中查询数据库会怎么。
这种写法 有很多不太友好的地方。
第一:硬编码 我将SQL语句直接放在程序中。
第二:如果每次查询都这么做的话,大量代码会重复。
第三:结果集处理很麻烦,我需要知道数据库表里对应的字段类型是什么,才能通过rs去拿相应类型的结果值。
第四:需要手动的取关闭连接管理,你不关闭的话,很容易造成内存泄漏
2.Apache Dbutils 主要是解决了对于结果集的封装
这块的话,没怎么仔细玩过,我大概知道他传入了一个数据源,然后用queryRunner进行查询,queryRunner本身封装了各种查询,然后里面是可以传入BeanHanndler,返回相应的结果集。大概的用法如下图:
这些源生的工具类, 解决了方法的封装,数据库管理,以及映射的结果集
但是 依旧没有解决 1.SQL硬编码(数据库操作与业务操作相互耦合)2.传入的参数只能按照顺序来(不能传入一个pojo实体对象) 3.没有实现实体类与数据库记录的映射(不能用Blog.save()) 4.没有一些比高级的用法:比如说缓存
3.接着我们就有了orm框架
Mybatis与Hibernate的最大区别在于对于底层jdbc封装的强度,Hibernate无法自定义SQL,优化起来比较困难
二.Mybatis核心对象与流程图
对了,这个是Mybatis3的官方中文版AIP说明:
http://www.mybatis.org/mybatis-3/zh/
这里面涉及到的几个核心对象:
1.Configuration类 这个类主要是配置类 配置mapper接口与pojo的映射,配置SQL语句,数据库连接信息等等
2.mapper接口类:声明SQL语句的实体方法
3.代理对象,因为仅仅只是声明了接口类,没有具体的实现,所以我们要有一个代理类去代理mapper接口
4.sqlSession 数据库会话层,根据配置类,可以生成代理的Mapper类,同时调用executor执行器的方法
5.executor:对于底层jdbc的封装,用于操作jdbc,被sqlsession持有
整个流程图的大体意思是这样的 用户调用mapper接口,然后sqlSession根据配置类去生成接口的代理类,同时根据mapper接口找到配置类里的对应的SQL语句,丢给executor执行,executor操作数据库
三.源码实现
1. 这个是我主要的测试类:
2.然后这个是我的资源类
事实上 最一开始为了方便 我用了properties,然后用ResourceBundle去读取资源文件。但是像这种的我既要表示 接口mapper类与接口方法,又要体现SQL语句,又要对应pojo类的,不太适合用properties的key value形式展示。所以这里才会有–的分割符,用于拆分
3.我们先看一下,sqlsessionFactory会话工厂类
bulid方法用于初始化读取porperties配置,openSqlSession用于生成默认的sqlSession
看一下Configuration类,配置类里面主要做了两件事情。一:解析配置文件 生成包括接口方法与bean的映射。以及接口方法和SQL的映射。二:调用相关的执行器,之前也说过执行器是最后与数据库 DB进行交互的。这边有两个执行器,一个是simpleExecutor,一个是CacheExecutor(装饰了基本执行器)。
再利用sqlSessionFactory获取到对应的DefaultSqlSession之后,我们从SqlSession中获取Mapper的时候,获取的是他的代理对象
通过MapperproxyFactory工厂类创建了MapperProxy的代理类,这边直接用的是JDK的动态代理,所以我们还要有一个实现InvocationHandler的代理类
具体代码如下:
能够看到的是 proxy代理类中直接组装statement,然后丢给了sqlSession去执行
然后很明显的通过拿到的statement 我们从之前初始化的配置类里拿到真正的SQL语句交给executor处理。executor在之前的代码内就已经决定是simpleExecutor还是CacheExecutor了。
同样的,在executor中执行中,我们调用了StatementHandler,而这个则是用了底层的jdbc操作。于此同时,这边还有对paramter与result结果集的Handler映射处理。
在最后,当我完成参数与结果集和数据库的映射之后,我要返回一个POJO对象,所以这边要调用反射区填充数据
然后 就差不多了 我们跑一下看一下效果
Git地址