Mybatis工作原理

  • Post author:
  • Post category:其他



在使用mybatis之前,我们要知道不使用Mybatis的时候我们用JDBC是如何做数据库相关的操作,进而才会更加深刻的理解为什么我们要使用mybatis这种ORM框架,当然ORM框架还有一个比较有名的开源框架Hibernate,本文我会重点讲解为什么将JDBC封装成Mybatis这样一种持久层框架,在对Mybatis分析完成之后,我会对比两个ORM框架的异同点.


1.使用JDBC实现数据库连接

我们先看看我们最熟悉也是最基础的通过JDBC查询数据库数据,一般需要以下七个步骤:
(1)  加载JDBC驱动
(2)  建立并获取数据库连接
(3)  创建 JDBC Statements 对象
(4)  设置SQL语句的传入参数
(5)  执行SQL语句并获得查询结果
(6)  对查询结果进行转换处理并将处理结果返回
(7)  释放相关资源(关闭Connection,关闭Statement,关闭ResultSet)
JDBC连接数据库代码晚些更新



2.JDBC连接优化与演化到Mybatis

针对于JDBC连接中七个步骤中的有些重复冗余的部分进行封装

(1)数据库连接的创建和释放

   使用JDBC连接数据库,每一次进行数据库操作都需要进行那七个步骤,数据库连接频繁的开启和关闭本身就造成了资源的浪费,影响了系统的性能. 为了不让数据库连接频繁的创建,我们可以提前创建一定数量的连接放在一个池子里,然后需要的时候就到池子里面进行调用,使用完成后再放回这个池子了,这样就可以解决我们反复创建连接造成资源浪费的问题,而这个池子一般我们称呼它叫连接池.连接池种类多种多样,从DBCP C3p0 Druid Bone  HikoariCP(高性能),可以根据自己的需求进行选择,通过连接池我们就可以反复利用池子里已经生成的连接进行数据库访问了,减少了频繁的开启和关闭数据库连接的时间,在Java中一个连接池所产生的连接就叫做数据源(DataSouce)

(2)SQL统一存取

我们使用JDBC进行操作数据库时,SQL语句基本都散落在各个Java类中,这样有三个不足之处:
第一,可读性很差,不利于维护以及做性能调优。
第二,改动Java代码需要重新编译、打包部署。
第三,不利于取出SQL在数据库客户端执行(取出后还得删掉中间的Java代码,编写好的SQL语句写好后还要Java进行拼凑)。

   既然放在Java代码有这么多弊端,每次改动都需要重新编译成为class文件,那我们该把这些和SQL相关的代码放在哪里呢?熟悉Java Web开发的人一般都会知道xml这个文件格式,像是一般spring struts hibernate等开源框架的配置文件一般都是放在xml中, mybatis采用的也是这种方式,将SQL统一按照key value方式存放在xml配置文件中,需要调用这些SQL的时候就从根据相应的key值去拿到相应的SQL语句

(3).传入参数映射和动态SQL

   很多情况下,我们都可以通过在SQL语句中设置占位符来达到使用传入参数的目的,这种方式本身就有一定局限性,它是按照一定顺序传入参数的,要与占位符一一匹配,即使可以使用另一种方式使传参数不用按照顺序。但是,如果我们传入的参数是不确定的(条件查询,传入查询的参数也是不同的,有时是一个参数、有时可能是三个参数),那么我们就得在后台代码中自己根据请求的传入参数去拼凑相应的SQL语句,这样的话还是避免不了在Java代码里面写SQL语句。既然我们已经把SQL语句统一存放在配置文件或者数据库中了,怎么做到能够根据前台传入参数的不同,动态生成对应的SQL语句呢?
   我们正常的程序员思维是,通过if和else这类的判断来进行是最直观的,类似于JSTL中的<if test=””></if>这样的标签,那么,能不能将这类的标签引入到SQL语句中呢?假设可以,那么我们这里就需要一个专门的SQL解析器来解析这样的SQL语句,但是,if判断的变量来自于哪里呢?传入的值本身是可变的,那么我们得为这个值定义一个不变的变量名称,而且这个变量名称必须和对应的值要有对应关系,可以通过这个变量名称找到对应的值,这个时候我们想到了key-value的Map。解析的时候根据变量名的具体值来判断。

(4).结果映射

执行SQL语句、获取执行结果、对执行结果进行转换处理、释放相关资源。假如是执行查询语句,那么执行SQL语句后,返回的是一个ResultSet结果集,这个时候我们就需要通过Java代码将ResultSet对象的数据取出来,不然等到释放资源时就取不到这些结果信息了。我们从前面的优化来看,以及将获取连接、设置传入参数、执行SQL语句、释放资源这些都封装起来了,只剩下结果处理这块还没有进行封装,如果能封装起来,每个数据库操作都不用自己写那么一大堆Java代码,直接调用一个封装的方法就可以了。一般对执行结果的有哪些处理,有可能将结果不做任何处理就直接返回,也有可能将结果转换成一个JavaBean对象返回、一个Map返回、一个List返回等等,结果处理可能是多种多样的。从这里看,我们必须告诉SQL处理器两点:第一,需要返回什么类型的对象;第二,需要返回的对象的数据结构怎么跟执行的结果映射,这样才能将具体的值映射到对应的数据结构上。

(5).解决重复SQL语句问题

由于我们将所有SQL语句都放到配置文件中,这个时候会遇到一个SQL重复的问题,几个功能的SQL语句其实都差不多,有些可能是SELECT后面那段不同、有些可能是WHERE语句不同。有时候表结构改了,那么我们就需要改多个地方,不利于维护。当我们的代码程序出现重复代码时怎么办?我们可能会想到AOP,将重复的代码抽离出来成为独立的一个类,然后在各个需要使用的地方进行引用。对于SQL重复的问题,我们也可以采用这种方式,通过将SQL片段模块化,将重复的SQL片段独立成一个SQL块,然后在各个SQL语句引用重复的SQL块,这样需要修改时只需要修改一处即可。




版权声明:本文为u013741073原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。