查看: 966|回复: 0

[Java学习] 阿里P7工程师带你一起来看MyBatis(二)

发表于 2018-1-19 14:49:53
好了,经过第(一)篇的学习,我们已经知道如何用MyBatis来进行查询操作,之前的案例是根据id进行查询数据表的一条记录,并把相应的值自动映射到实体类对象的属性中。
那接下来我们就该看看增加,修改和删除的操作用MyBatis如何做咯。
1.JDBC中的增删改
我们不妨来回忆下原始的JDBC代码是如何进行增删改的操作的,同样,我拿一张《聊聊JDBC》中的截图过来。
上图中使用的是Statement对象,而没有使用PreparedStatement对象,流程大体是一样的,我们只是为了了解步骤。那咱们按照原先的查询操作,把增加的步骤来写一写。
(1)加载数据库驱动类
(2)根据url,user,pass得到一个数据库连接对象
(3)构建一条sql语句
(4)将构建的sql语句交给Statement对象的executeUpdate方法执行并返回受影响的行数
当然,一般情况下,在构建sql语句的时候,我们使用的是PreparedStatement对象,并用占位符"?",然后对参数进行赋值,这些是小的细节。但是要说明的一点是,通常参数的值是从实体类对象中取出来然后进行赋值的,也就是体现了面向对象开发的思想。不明白什么意思?也就是说,假如上面这段代码是一个add方法,通常add方法会这样声明"add(User user)",然后sql语句就这样写"insert into ... values (user.getUsername,user.getPassword)...",我写的是伪代码,主要是让大家明白,参数的值通常是从一个对象中取出来的,而不是传一些零散的参数过来赋值。好了,这里就不多扯咯,大家平时开发中使用多了,也就习惯这种面向对象的开发流程了。
从上面的代码可以看出,步骤似乎简单的一些,那这几步哪些在MyBatis中又是如何管理和优化的呢?咱们知道MyBatis实际上就是对JDBC代码的封装。很明显,(1)(2)两步还是在核心配置文件SqlMapConfig.xml中使用数据源的方式进行管理,那第(3)步呢?同样是在xxxMapper.xml文件中进行配置,只不过使用的不是select标签,而是insert标签。那第(4)步呢?先不着急,我们还是通过一个demo来感受一下。
要朝这java程序员发展或者真心有兴趣的。可以找我要一些java的学习视频java学习交流群:450936584,这个是免费的,希望同学找我要的时候不要有理所应当的态度,毕竟都是我的心血,希望你是真的有一颗想要学好java的心,我也会尽所能的去帮助你成为一名优秀的程序员
2.使用MyBatis进行增加操作
为了加深大家对MyBatis使用的印象,我们来重新新建一个项目名称为"ES9D_MyBatis2",巩固一下MyBatis使用的流程,不过和(一)中重复的过程就不写的那么细咯。
(1)新建一个Java或者Java Web项目,名称为"ES9D_MyBatis2"
(2)导入mybatis和mysql的jar包
(3)还用原来的数据库db_es9d_mybatis和数据表t_users
(4)把t_users表对应的实体类User先写好
(5)在src目录下新建一个核心配置文件"SqlMapConfig.xml"
SqlMapConfig.xml文件目前的内容为,主要是配置关于事务和数据源的信息。
(6)新建一个包"com.es9d.mapper"用于存放xxxMapper.xm文件,并在该包下新建一个"userMapper.xml"文件,因为目前是要对"t_users"表进行操作,一个表对应对应一个实体类,对应一个mapper文件
(7)接下来就是编写"userMapper.xml"文件的内容,为了对比,我们把select标签保留
注意观察上面图片中的内容,之前我们学过了用select标签进行查询操作,现在我们要进行的是增加操作需要使用的就是insert标签,这个很容易理解,并且给这个标签起一个名字,用id来表示。名称为"addUser",可读性很好。
在insert标签中的内容是一条insert语句,有了之前的select标签的经验,我们很容易知道#(username)就相当于原来JDBC代码中的"?",表示占位符。
到这里为止,应该都比较容易理解,然后就是parameterType,表示参数类型,在进行select查询的时候,因为id是整型,所以上面写成了"int"。而这里却写成了"com.es9d.domain.User",是一个实体类类型,这时候你可能会有疑惑,占位符的参数类型命名是String,怎么能写成实体类类型呢?回想一下之前我们的JDBC代码,在进行增加操作时,方法中是不是说最好传入一个User对象,这样体现了面向对象的开发思想,并且在进行参数赋值的时候也方便。那这里咱们就大胆地猜测一下,之所以参数类型写成User,是不是和之前的JDBC代码有异曲同工之处。到时候代码中肯定就是从User对象中获取到相应的参数赋值给对应的#{username}之类的。
到此为止,userMapper.xml文件中insert标签配置完成,接下来做什么呢?
(8)将xxxMapper.xml文件交给核心配置文件SqlMapConfig管理
注意这步不能忘了,再想想是不是?最终咱们代码中是根据核心配置文件得到一个SqlSession对象进行相应的操作,如果xxxMapper.xml文件配置好了,不交给核心配置文件管理,那一切工作就无xxxMapper.xml文件无关,在其中做的一系列配置就徒劳咯,切记,要交给SqlMapConfig管理
(9)编写增加的代码
准备工作完成,接下来就是写代码进行测试。于是咱们新建一个包名称为"com.es9d.test",在该包下新建一个类"Test.java"。
然后就巴拉巴拉地写固定格式的代码,开动咯。
上面这段代码没啥好说的,都明白是什么意思吧?在MyBatis(一)中给大家详细说明咯,不过大家可能有疑问的是,这里仅仅是获取到了SqlSession对象,并没有进行增加的操作,代码不全啊,没错,还没继续往下写。这里我们来一起想一想,这几行代码是为了先读取到核心配置文件SqlMapConfig的输入流,然后根据数据流得到SqlSessionFactory工厂,再根据工厂得到SqlSession对象。一共3步,有没有发现无论是查询还是增加都需要写重复的代码,无论是从性能上还是代码的冗余上,显然不合理,于是我们决定将这段获取SqlSession的代码放到一个工具类中,为了不影响增加的整体流程,我将这个工具类的描述放到第"5"小点中,大家需要了解的可以往下拖动一下到第"5"小点,这里我默认为大家已经看过咯。用工具类获取到SqlSession代码如下图所示。
是不是变得非常简洁,ok,到这里相当于模板代码写完了,接下来就是写增加的代码咯,不能忘了咱们的主要目的。还是先回想一下之前写select查询的时候,接下来的步骤是不是要准备一个"sql标识符",比如"com.es9d.mapper.userMapper.getUser",因为需要定位到userMapper.xml文件中的select标签,然后才可以使用,那增加呢?增加也是一样,也需要准备一个这样的"sql标识符"
这个"sql标识符"的含义咱们就不重复解释咯,之前说明过,主要就是为了定位到userMapper.xml文件中的具体的标签,比如这个定位到的是insert标签。然后呢?找到了insert标签,咱们需要干嘛?insert标签中是不是有3个参数值待定,需要我们传值,这样才是一条完整的增加sql语句,而且我们知道怎么传值的,是通过User对象进行传值的吧?所以我们需要先准备一个User对象,并且把需要增加的值赋值给相应的属性,具体做法如下图所示。
好了,到这里,User对象也准备完事,接下来呢?是不是同样的要将"sql标识符"交给SqlSession对象的某个方法去执行,并且把参数需要的User对象一起传入,那我们来找找这样的方法。发现一个insert方法,找到有两个参数的,第一个参数是需要执行的"sql标识符",第二个参数是需要用于赋值的User对象。到这里咱们再好好想想,是不是非常合情合理?咱们的userMapper.xml文件中的insert标签,有一条insert语句,但是该sql语句不完整,参数还没赋值,怎样赋值?需要使用一个User对象来赋值,于是咱们传入一个User对象,那这样就会自动把sql语句补全,交给一个insert方法执行,当然,这里的自动,要建立在数据表的字段和实体类的属性名称一致的情况下,不然会失败,咱们先不提这个,后面再说。返回值是int类型,表示受影响的行数,这点很容易理解,在原先的JDBC代码中也有这样的返回值。
(10)测试增加代码
好了,到了这里,感觉一切都已经完成,那咱们来测试试试看,看是否有问题。
执行完之后,刷新数据表,发现并没有增加一条记录,奇怪,怎么回事?哪边写错了?在使用MyBatis框架进行增加,修改和删除操作的时候,一定要提交事务,不然无效。原来如此,那就提交呗,不过这里需要把有个概念说明一下,SqlSession对象可以是自动提交事务型的,也可以是手动提交事务型的,在第"5"小点有说明,这里咱们获取到的是手动提交事务型的,所以需要咱们手动提交事务,怎么做呢?如下图所示。
于是,咱们再来执行一遍,然后观察数据表的变化。
从上图可以看到,的确增加成功,就是没有提交事务的原因,而且可以发现,此时自动增长的id为6,为什么呢?因为没有手动提交事务之前,我执行了两次增加的代码,所以4和5两个id值被占用了,这里就变成6咯。
另外,还要说明的一点是,用完SqlSession对象之后,要记得关闭资源,就像之前JDBC代码中关闭Connection对象一样。
到这时候,大家会想,刚才是手动提交事务,如果是自动提交事务呢?使用的是openSession(true)的方法,还需要"session.commit()"吗?显然是不需要的,咱们不妨也来做一个测试。
可以发现,getSqlSession使用的是自动提交事务的SqlSession,而在session.insert之后也没有进行事务的提交,此时我们执行一下代码,看是否会增加成功。
没有问题,增加成功。
3.使用MyBatis进行修改操作
好了,说完了增加,就轮到修改咯,其实原理是一样的,这里我就不从一开始的步骤去一一写咯,正好大家可以感受下,如果需要新增一个功能,我们需要变化的是什么,不变的是什么。前面几步是不变的,主要是修改userMapper.xml文件,增加一个标签,如下图所示。
有了前面的基础,很容易看懂这段配置是干什么的,update表明是修改,id唯一标识符,parameterType表示参数类型,为了指定将哪条记录进行修改,并且修改成什么内容,和insert那边是一样的,如果一个个参数来传值也行,但是我们是面向对象的开发思想,所以传来的是对象。然后update标签中的语句#{username}是占位符。
接下来是什么,代码测试对吧?这时候咱们选用JUnit进行测试,新建一个类Test2
这个过程很容易看懂吧?首先获取SqlSession对象,然后定义需要执行的"sql标识符",然后准备需要修改的User对象,交给SqlSession的update方法执行,我们直接来看结果,修改成功。
4.使用MyBatis进行删除操作
有了前面增加和修改的案例,删除变得非常容易,直接来看流程,先是修改userMapper.xml文件
这里是根据id进行删除,和select根据id查询一样,所以parameterType为int,不再是User类型。然后就是代码。
这里传入的就是一个id值,类型为int型。然后我们执行看下结果,成功删除。
5.将获取SqlSession对象封装到工具类中
既然是工具类,最好先新建一个工具类的包,名称为"com.es9d.utils",然后在其中新建一个类名称为"MyBatisUtils"。
然后就是怎样获取到SqlSession对象,一共是3步,我们可以把前2步获取到SqlSessionFactory放到一个方法中,获取SqlSession放到一个方法中,为什么这样做?大家想一想,使用工厂SqlSessionFactory获取SqlSession的时候使用openSession方法,但是该方法是重载的,可以根据实际需要选择不同的参数,而一般我们使用的是boolean这个参数,之前也提到过。如果没有参数值,事务是需要手动提交的,如果参数值为true,事务是自动提交的。至于什么是手动提交事务,什么是自动提交事务,在demo中咱们会有体现,大家先有这样一个概念,代码如下图所示,很容易理解对不对?如果我们在代码中需要用到SqlSession对象,是不是只需要使用"MyBatisUtils.getSqlSession"即可,因为咱们把方法设置成了static,可以通过类名直接调用。
6.使用MyBatis查询全部记录
之前咱们用过select标签根据id查询单条记录,然后封装到User对象中,那如果是查询多条记录呢?咱们不妨来试试。
(1)修改userMapper.xml文件
同样,还是从userMapper.xml文件入手,既然是查询,肯定还是用select标签。
目前好像我们能够写出这样的标签形式,一个select标签,一个对应的id,标签中是要查询的sql语句,没有参数值需要传入,所以不需要parameterType属性,那还缺少什么?显然,查询出来是有结果返回的,如果需要returnType属性,那值是什么呢?你可能会想,多条记录肯定对应多个User对象,那干脆写Users加个"s",注意这里是需要一个类型。以前我们在JDBC代码中是怎么做的?如果查询到多条记录,当时是每次把每次查询到的结果保存到一个User对象中,然后再将这些对象保存到一个List集合中,ok,我们同样如此。那此时你可能会想,那类型写成java.util.List,这个思路是对的,但是要注意每条我们查询出来的结果是一个User对象,所以这里咱们还是写User类型,将保存这些User对象的工作交给代码中去做,所以该配置还是如下图所示。
(2)编写代码
第一点,因为是查询操作,无需事务的提价,所以这里我们调用的是无参的openSession方法;第二点构建的"sql标识符",定位到userMapper.xml文件中的对应的标签;第三点最重要的,调用session的selectList方法,把"sql标识符"传入,为啥调用selectList方法,很容易相同,因为每次查询出来的记录对应一个User对象,需要将每个User对象保存到List集合中,就像之前JDBC代码中循环遍历一样,只不过这里MyBatis把这些过程封装起来了,不用我们手动去写代码了,很方便吧?;第四点,将lists打印出来,看是否拿到了数据表中的全部记录,并且是以"User对象"的形式展现的。
(3)运行看结果
从下图中可以看得出来,List集合中有数据,而且存储的是一个个User对象。
7.小结
今天我们讨论了如何使用MyBatis进行全部查询,增加,修改和删除的操作,内容还是相对比较简单的,把上一篇的内容也一起复习了一下。这样一来,大家对MyBatis框架至少有了一个大概的认识,接下来会向大家介绍字段名和属性名不一样怎么办,一级缓存、二级缓存,一对一,一对多表怎么操作,如何进行一些优化等等。当然,大家如果有兴趣,咱们也可以一起看看MyBatis的源码,看内部结构是如何实现的,它怎么就能够自动完成以前我们手动的一些操作的。
欲知后事如何,且听下回分解!



回复

使用道具 举报