一起来看MyBatis(一)

来源:互联网 发布:maxwell软件 编辑:程序博客网 时间:2024/06/08 19:48
老规矩,在正式开始之前,咱们闲扯一会。一提到MyBatis,得先知道是啥,用来做什么的等一系列问题,然后呢?然后就用起来咯,不知道大家有时候会不会有这样一种感觉,比如谈到某种技术,像多线程,集合,Redis,Docker,存储过程等等,即使之前听过或者用过,突然脑子会一片空白,一脸懵逼,紧接着会问自己,我现在在做什么?算了,还是打游戏去吧。
1.MyBatis是什么
那今天我们要聊的MyBatis是什么呢?我们不妨来看下度娘上的解释


看完这段话,有些人更加懵逼了,比没看之前更烦躁,都是一些专业化的术语。不过我们至少能知道的是,MyBatis是有一个叫"iBatis"的家伙演变过来的,soga,原来它还有前生。并且还能够知道,原先它是apache下的一个开源项目,后来呢,它经过两次搬家,第一次是搬到了google code上,后来又搬到了Github上。

第二段话我们知道它命名的由来,并且能够知道它是一个"持久层"的框架,说到持久层的框架,大家可能听过hibernate,没听过也没关系,只是顺便提一下,大家都属于持久层框架,认个亲戚。
好了,废话了这么多,其实还是没明白MyBatis是干嘛的,我们就假装明白了它大概的做什么的,具体咱们把它用起来就会有体会了,目前最缺的是一个demo,有demo什么都好说,具体形象,文字游戏太抽象了,不易于理解。

2.引入MyBatis
既然MyBatis是一个持久层的框架,那么肯定和数据库的操作相关,这是我们的一个直观感受。说到操作数据库,大家肯定能够联想到JDBC技术,那MyBatis和JDBC的关系是怎样的呢?先给大家抛出一个概念,MyBatis实际上就是对JDBC的封装,也就是把JDBC中一些复杂的不方便的过程给封装起来,提供给开发者的是方便灵活的操作方式,这样说还是有点抽象,咱们继续往下看。

之前给大家写过一份《聊聊JDBC》,如果大家对JDBC不熟悉的话,可以先去看下那份文章。
这里默认为大家都熟悉JDBC或者已经看过之前写的那份文章,那我们知道,JDBC是Java程序操作数据库的一个媒介,通过JDBC,可以通过写Java代码对数据表中的数据进行CRUD操作,为了说明问题,我拿一张查询的截图过来。

上面的图片展现的过程比较容易理解,是通过JDBC技术,查询某个数据表中的数据,然后将查询的结果循环遍历出来赋值给实体类中的属性。我们可以把过程来写一下。
(1)加载数据库驱动类
(2)根据url,user,pass得到一个数据库连接对象
(3)构建一条sql语句
(4)根据连接对象和sql语句得到一个PreparedStatement对象,并给其中的参数赋值
(5)执行PreparedStatement对象的executeQuery()方法得到一个ResultSet结果集
(6)循环遍历ResultSet结果集中的内容赋值给Admin对象的各个属性
当然,这个过程不是很严谨,比如还需要关闭资源,不过这是一条主线。
既然说MyBatis框架是对JDBC的封装,那么哪里可以进行封装,哪里可以进行简化,我们看接下里的一个小节。

3.我们理解的MyBatis
MyBatis到底对JDBC进行了哪些封装与简化?我们从上面的过程可以看出,其中(1),(2)这两步是不是可以简化,看过我们的《数据库连接池》的同学应该可以想到,得到数据库连接对象可以交给数据库连接池去管理;第(3)步构建出一个sql语句,这是最核心的,不能简化,所以这一块在MyBatis框架中保留出来给开发者自己去写;第(4),(5)这两步在MyBatis中可以进行更好的优化管理;第(6)步这种循环遍历显然代码量比较大,也没啥意思,所以也交给MyBatis来管理。

综上所述,我们可以看出来,对于一个查询操作,以前的JDBC方式,需要进行6步,而在MyBatis中更加关心的只有第(3)步,把精力集中在sql语句的编写上,但是要注意,MyBatis框架调用的底层还是JDBC的那几个过程。这里顺便提一下,hibernate对JDBC的封装就更深了,完全不需要程序员关心sql语句的编写。

实际上,大家有没有看出来,MyBatis框架做的事情就是把数据表中的数据和实体类对象进行一个映射,只不过这里需要我们关注sql语句的编写,而hibernate框架也是做这样一件事,不过不需要关心sql语句的编写。所以hibernate是一个orm框架,MyBatis更像是一个半orm框架。
好了,说了这么多,似乎比之前直接看度娘要懂得多一点了,说来说去,MyBatis就是对JDBC代码进行了一些封装与简化呗,更加方便我们开发者使用了,没错,可以先暂时这么理解。为啥是说暂时呢?因为MyBatis除了这些,还对JDBC代码进行了很多优化,这些细节咱们先不讨论。

4.用一用MyBatis
既然说MyBatis是对JDBC代码的封装,也就是把那6步进行了一个简化,那它是如何简化的?原来每一步对应在MyBatis中又是如何的?这里我们还是以一个demo为例,好了,我要发大招咯。

(1)导入mybatis相关的jar包
这一点大家没疑问吧?在使用一门新技术时,肯定要想想把人家的jar包拿过来,说白了就是把人家写好的那些类拿过来,然后才能使用人家的技术。因为Java是面向对象的开发语言,即使前面把MyBatis说的那么神奇,归根结底还是要使用哪些类,哪些方法等等。对了,在次之前不要忘了新建工程,Java工程或者Java Web工程都可以。
那这里我就先新建一个Java Web工程,名称为"ES9D_MyBatis1",啥意思?前缀"ES9D"含义为"忆说就懂",后缀"MyBatis1"含义为...这就不说了。咱们命名也稍微正规化一点,不能瞎来。

然后就导入mybatis相关的jar包,我在网上找了一个版本3.1.1,大家自己可以去下载。另外需要说明的一点是,除了mybatis jar包,大家觉得还需要其他jar包吗?想想我们整个程序,是不是要对数据库进行操作?比如我还是用的mysql数据库,那是不是还是需要mysql数据库的jar包?没毛病吧?之前咱们使用JDBC去操作mysql数据库的时候,也用到了mysql的jar包,前面也解释过原因,这里就不赘述咯,那我就把这两个jar包导入到工程中,如下图所示。



(2)准备数据库和数据表
既然是对数据库的操作,总不能没有数据库和数据表吧?这里我使用的是mysql数据库
数据库db_es9d_mybatis
数据表t_users(id,username,password,tel)


(3)SqlMapConfig配置文件
之前如果有学过struts,hibernate,spring等框架的时候,一般都会有一个核心配置文件,说白了,学习框架,主要学习的就是如何进行一些相关的配置。咱们的MyBatis框架也不例外,它有一个核心配置文件,名称默认为"SqlMapConfig.xml",一般放到src目录下。注意,这里是默认,而不是必须,之所以我把名称写成这个,是为了给大家一种feeling,以后看到这个文件就能联想到是MyBatis框架。那这个文件作用是什么呢?怎么用呢?这个配置文件不用我们自己写,一般在网上可以找到模板,或者在mybatis的源码项目中也可以找到,无论通过哪种方式,格式还是比较简单的,我先拿一份通用的格式过来,然后咱们一起聊聊。

开头是xml文件的固定写法,没什么好说的。然后就是dtd文件的约束,也就是该xml文件中可以包含哪些标签,有一份dtd文件进行约束。然后configuration标签就是开始进行配置了。
environments:顾名思义,环境的配置,当前我们是开发环境,所以写成development
transaction:事务的配置,这里采用JDBC的事务管理方式
datasource:数据源的配置,也称为数据库连接池的配置,前面的《数据库连接池》文章中我们提到过这个概念,这里就不赘述咯
mappers:是对mapper配置文件的引入,先不说,接下来聊到mapper文件时再说
到这里为止,似乎有点明白了,这份SqlMapConfig文件主要做了哪些事情,其中比较明显的一个就是配置数据源,也就是说在JDBC的6个步骤中的(1),(2)两步是在这边进行管理的,从而能够得到数据库连接对象。那还有其他步骤呢?怎么做?继续往下看。

(4)编写实体类
既然MyBatis是对JDBC的封装,那它需要将数据表中的数据和程序中的实体类对应起来,所以我们需要准备一个与数据表t_users对应的实体类User,这点能够想通吧?如果不明白,可以看下我们的《聊聊JDBC》。


(5)编写userMapper.xml文件
咦?怎么又来一个配置文件?之前SqlMapConfig配置文件我们已经了解了它的作用,而这个配置文件又是做什么的?既然使用JDBC对数据表进行查询操作需要6个步骤,而目前我们MyBatis看上去已经做了(1),(2)两步,那其他几个步骤呢?显然如果没有其他几个步骤,何来的查询,何来的把查询结果赋值到某个实体类对象的属性中?对不对?所以该配置文件就是针对某张表和某个具体的实体类而产生的,如果数据库中有5张表,显然我们需要准备5个实体类,同时需要准备5个这样的mapper文件,当然,也可以使用注解的方式,不绝对,这里只是为了说明问题。
所以这个userMapper.xml文件的作用你可以把它理解为,数据表和实体类的关系怎样对应?JDBC中其他几个步骤在MyBatis技术中如何提现等等。重点是,你不会突然觉得这个配置文件可有可无,一定要知道它存在的意义,存在即合理。
另外,需要注意的是,一般这个配置文件的命名为实体类的名称+Mapper.xml,当然,不绝对,命名还是可以变化的,只是说这样一个约定俗成的概念。该配置文件的位置一般放到一个专门的目录中,比如"com.es9d.mapper",这样方便管理,不然配置文件一多就会显得比较凌乱。
下面我们就来看看这个配置文件中有哪些值得说的东西,同样,我截一张模板图过来。

前面的部分就不多说了,从mapper标签开始说起,发现有一个namespace属性,含义为命名空间,也就是说,该userMapper.xml文件需要一个对应的命名,而且这个命名要唯一。一般情况下,通常是包名+mapper文件名,mapper文件去除后缀即可,比如我们的userMapper.xml文件在com.es9d.mapper中,namespace的值为"com.es9d.mapper.userMapper"
select标签:说明要进行查询操作,其他先不看,看标签对中的sql语句,这里就相当于JDBC的第(3)步,构建sql语句。然后给select标签id取个值,方便程序中使用,具体怎么使用,我们到程序中再看,这里先明确一点,该名称要唯一,可读性要好,比如getUser,说明就是得到一个User对象
parameterType="int",要说这个,咱们还是回到sql语句"select * from users where id=#{id}",这句话的含义不用多说,相当于之前JDBC中的"select * from users where id=?",能理解吧?也就是#{id}表示一个占位符,具体值是什么,由程序代码中决定,而parameterType的含义就是指定该占位符的值类型,int就表示是整型。另外,这个步骤是不是相当于做了JDBC中的(4)根据连接对象和sql语句得到一个PreparedStatement对象,并给其中的参数赋值。
resultType="com.es9d.domain.User",表示从返回的结果集中循环遍历出一个User对象,也就是resultType的含义是指定返回的类型,我们select目的是得到一个User对象,所以要写成"com.es9d.domain.User",注意是类的全路径。

(6)将userMapper.xml文件配置到SqlMapConfig文件中

如图所示,将userMapper.xml文件在核心配置文件SqlMapConfig文件中配置一下,交给核心配置文件管理。这里实际上比较容易理解,既然SqlMapConfig文件是MyBatis的核心配置文件,那一切就以它为中心呗,你写好一个userMapper.xml文件要想生效用到,就交给它管理。

(7)根据id查询得到一个User对象
好了,上面写了几个步骤,那咱们就通过程序来看看能够根据id查询成功并且得到一个User对象,具体步骤是什么呢?

a.得到核心配置文件SqlMapConfig文件的内容
既然SqlMapConfig是核心配置文件,一切都要以它为中心,那咱们是不是先要取到其中的内容?怎么取呢?取完之后放到哪里?

写法比较固定,如果不能理解,记住也可以,这样就可以把SqlMapConfig.xml文件的内容加载到一个InputStream输入流中,也就是在InputStream输入流中就可以拿到核心配置文件的所有内容。

b.根据核心配置文件的输入流得到一个工厂

至于为什么会要有这样一个工厂,实际上这和设计模式相关。就算我们不知道mybatis该如何使用,但是最起码我们要有一个判断,就是要找到mybatis中某个某些类来调用这些类的方法属性,因为这是面向对象的开发思想决定的。
而在mybatis框架中,核心的一个类就是sqlsession,而要想得到这样一个sqlsession类,就得需要一个sqlsessionfactory,用的是工厂设计模式,这里我们就不展开说咯。

c.根据sqlsessionfactory得到sqlsession

其中openSession这个方法是重载的,也就是可以传入参数,一般常用的是传入一个boolean值,主要是为了控制事务是否自动进行提交。先有这么一个概念,后面这个知识点咱们会具体说。

d.定义一个sql标识符
回想一下我们前面所做的事情,SqlMapConfig文件中没什么好说的了,userMapper.xml文件还是有一些可以说道说道的,想想看,我们要做什么?我们需要根据id来查询得到User对象,而在userMapper.xml文件中是不是写了一个select标签,并且有一个id的值,这个标签的作用就是根据id来进行查询users表,忘记了的可以回头看下userMapper.xml文件。
那接下来的工作就是如何通过java代码使用这个select标签进行查询,肯定是先要定位到这个标签,怎么定位?就要找到userMapper.xml文件,然后找到其中的select标签。
userMapper.xml文件有一个命名空间还记得吗?这就能对应到该配置文件,com.es9d.mapper.userMapper。那怎么定位到select标签呢?很简单,它有一个id,组合起来就是"com.es9d.mapper.userMapper.getUser",这样就可以准确地定位到select标签,然后使用select标签去进行查询操作。
这里说定义一个sql标识符也就是这个含义,如下图所示


e.调用sqlsession的方法得到User对象
万事俱备,只欠东风,想一想,目前是不是所有的准备工作都已经完成?那么接下来就是关键的一步,调用sqlsession的某一个方法来得到我们所需要的结果。

如上图所示,调用的是selectOne方法,为什么会调用该方法?sqlsession中有很多方法,因为我们是根据id进行查询,返回的结果只能是一条,也就是只会对应一个User对象。第一个参数表明我们需要执行的是userMapper.xml文件中哪个标签的内容。第二个参数1,大家还记得吗?在userMapper.xml文件的select标签中有一个id=#{id}表示占位符,也就是具体查询哪个id由程序中指定,这里就表示查询id为"1"的记录。那返回值是什么呢?细心的各位应该还记得在select标签中有一个属性resultType,我们将其定义成了com.es9d.domain.User,也就是说返回值为User类型。

f.执行看结果
到这里,能否查询成功,大家实际上会有一个半信半疑的态度,信的原因是JDBC的6个步骤在MyBatis中都有对应,感觉应该是可以成功的。不信的原因是好像有点颠覆之前JDBC代码的概念,感觉整个过程中也没写什么太多代码,就是配置了一下。
最好的方式就是看看是否能够取到值,并且封装到了User对象中,我先把整个代码截图一下

运行结果


5.小结
对比一下原来的JDBC查询和用MyBatis查询,可以发现,的确用MyBatis方便了很多,这里我们还是把步骤写一下
a.导入mybatis的jar包
b.编写SqlMapConfig.xml文件
c.编写xxxMapper.xml文件
d.将xxxMapper.xml文件交给SqlMapConfig.xml文件管理
e.得到SqlSessionFactory对象
f.得到SqlSession对象
g.根据sql标识符调用SqlSession对象的方法完成查询操作

当然,步骤不一定是这样,只是刚开始我给大家一个入门的流程。等大家用熟了之后,想先写什么就先写什么,就是这么任性。从直观的感受上来讲,我们更多的是关心xxxMapper.xml文件中sql语句的编写,像从原来的ResultSet结果集遍历数据封装到实体类对象中这种繁琐的操作再也不需要写了。当然,优点还有很多。

大家可能会想,根据id查询我们了解了,那比如要写增加,修改和删除该怎么做呢?如果数据表字段名和实体类属性名不一致会有问题吗?如果不用配置文件而使用注解的方式该怎么写?等等一系列疑惑,没关系,咱们先通过了一个简单的查询操作来感受了一下MyBatis框架的使用,先明白它和JDBC的一些差别,以及它的使用流程,其他问题咱们在接下来慢慢讨论,我先把这份文章命名为《一起来看MyBatis(一)》。
欲知后事如何,且听下回分解!

大家也可以关注下我们的微信公众号“忆说就懂”,扫一扫或者长按图片进行识别,平时有什么问题可以一起探讨与学习,谢谢!QQ交流群:574393683