mybatis第二章朱磊孔.docx
《mybatis第二章朱磊孔.docx》由会员分享,可在线阅读,更多相关《mybatis第二章朱磊孔.docx(46页珍藏版)》请在冰豆网上搜索。
mybatis第二章朱磊孔
Touteng安博A+精英软件人才培养工程系列教材
基于mybatis开发持久层应用
(第三阶段)
版本历史
版本
完成日期
修改人
说明
目录
第2章MyBatis进阶2
核心技能部分5
2.1MyBatis级联查询5
2.1.1什么是关联关系5
2.1.2关联6
2.1.3动态SQL13
本章总结18
任务实训部分18
1:
继续完善学生管理系统,对学生进行条件查询18
2:
对表Classes进行删除操作20
3:
对表Classes进行更新操作21
巩固练习22
2.2Mybatis缓存23
2.3Mybatis映射器注解26
MyBatis进阶
学习内容
ØMyBatis高级级联查询
ØMyBatis集合映射、关联优化
ØMyBatis动态SQL语句、存储过程
能力目标
Ø掌握MyBatis高级级联查询
Ø掌握MyBatis集合映射
Ø掌握MyBatis动态SQL语句
Ø了解Mybatis存储过程
本章简介
第1章主要讲解了Mybatis总体架构、运行原理,并且使用mybatis实现了对数据库的CRUD操作。
在面向对象设计中,数据库表之间的关系一般被设计为实体对象之间的关系,实体对象之间关系一般包括:
多对一,一对多,一对一,多对多。
Mybatis在3.X之后引进了以注解形式实现简单的映射语句。
本章主要针对对象的关联关系、关联映射配置实现映射进行讲解。
核心技能部分
2.1MyBatis级联查询
2.1.1什么是关联关系
关联体现的是两个类之间语义级别的一种强依赖关系。
比如我和我的朋友,这种关系比依赖更强、不存在依赖关系的偶然性、关系也不是临时性的,一般是长期性的,而且双方的关系一般是平等的。
关联可以是单向、双向的。
表现在代码层面,为被关联类B以类的属性形式出现在关联类A中,也可能是关联类A引用了一个类型为被关联类B的全局变量。
在UML类图设计中,关联关系用由关联类A指向被关联类B的带箭头实线表示,在关联的两端可以标注关联双方的角色和多重性标记
在mybatis中,实体类中的关联关系直接映射sql语句。
例如我们使用部门、员工表做下面映射关系。
2.1.2关联
2.1.2.1多对一关联查询
在mybatisConfig.xml中添加对DeptMapper.xml的引用,看代码斜体加粗部分:
xmlversion="1.0"encoding="UTF-8"?
>
DOCTYPEconfigurationPUBLIC"-//mybatis.org//DTDConfig3.0//EN"
"http:
//mybatis.org/dtd/mybatis-3-config.dtd">
增加映射文件(EmpMapper.xml)与映射接口(EmpMapper.java),以及实体类(Emp.java)
EmpMapper.xml的映射文件
xmlversion="1.0"encoding="UTF-8"?
>
DOCTYPEmapperPUBLIC"-//mybatis.org//DTDMapper3.0//EN"
"http:
//mybatis.org/dtd/mybatis-3-mapper.dtd">
javaType="org.mybatis.example.Dept">
select
e.empno,e.ename,e.job,e.mgr,e.hiredate,e.sal,m,
e.deptno,d.dname,d.loc
fromempeleftjoindeptdone.deptno=d.deptno
EmpMapper.java接口
publicinterfaceEmpMapper{
publicListselectManytoOne();
}
Emp.java实体类
publicclassEmp{
privateIntegerempno;
privateStringename;
privateStringjob;
privateIntegermgr;
privateDatehiredate;
privateIntegersal;
privateIntegercomm;
privateDeptdept;
//省略getter和setter
大家注意看映射文件中的这部门代码
javaType="org.mybatis.example.Dept">
关联元素处理“有一个"类型的关系。
比如,示例中,一个员工(Emp)有一个部门(Dept)。
关联映射就工作于这种结果之上。
指定了目标属性,来获取值的列,属性的java类型(很多情况下MyBatis可以自己算出来),如果需要的话还有jdbc类型,如果想覆盖或获取的结果值还需要类型控制器。
关联中不同的是需要告诉MyBatis如何加载关联。
MyBatis在这方面会有两种不同的方式:
1.嵌套查询:
通过执行另外一个SQL映射语句来返回预期的复杂类型。
2.嵌套结果:
使用嵌套结果映射来处理重复的联合结果的子集。
首先,来查看这个元素的属性。
所有的都会看到,它和普通的只由select和resultMap属性的结果映射不同。
属性
描述
property
映射到列结果的字段或属性。
如果匹配的是存在的,和给定名称相同的JavaBeans的属性,那么就会使用。
否则MyBatis将会寻找给定名称的字段。
这两种情形"可以使用通常点式的复杂属性导航。
比如,可以这样映射一些东西:
“username",或者映射到一些复杂的东西:
“address.street.number"。
column
来自数据库的类列名,或重命名的列标签。
这和通常传递给resultSet.getString(columnName)方法的字符串是相同的。
注意:
要处理复合主键,可以指定多个列名通过column="{prop1=col1,prop2=col2}"这种语法来传递给嵌套查询语句。
这会引起prop1和prop2以参数对象形式来设置给目标嵌套查询语句。
javaType
一个Java类的完全限定名,或一个类型别名(参加上面内建类型别名的列表)。
如果映射到一个JavaBean,MyBatis通常可以断定类型。
然而,如"映射到的是HashMap,那么"应该明确地指定javaType来保证所需的行为。
jdbcType
在这个表格之前的所支持的JDBC类型列表中的类型。
JDBC类型是仅仅需要对插入,更新和删除操作可能为空的列进行处理。
这是JDBC的需要,而不是MyBatis的。
如果直接使用JDBC编程,需要指定这个类型-但仅仅对可能为空的值。
typeHandler
类型处理器。
使用这个属性,可以覆盖默认的类型处理器。
这个属性值是类的完全限定名或者是一个类型处理器的实现,或者是类型别名。
以上代码执行结果:
publicstaticvoidmain(String[]args)throwsIOException{
SqlSessionsession=SqlSessionFactoryUtil.getSqlSession();
EmpMapperempmapper=session.getMapper(EmpMapper.class);
ListempList=empmapper.selectManytoOne();
for(Empemp:
empList){
System.out.println(emp.getEname()+"的部门:
"+emp.getDept().getDname());
}
session.close();
}
这种的查询在mybatis中成为:
嵌套结果查询。
还有另一种查询方式:
嵌套查询
示例2.1:
javaType="org.mybatis.example.Dept"select="selectDept"/>
SELECT*FROMempWHEREempno=#{id}
parameterType="int"resultType="org.mybatis.example.Dept">
SELECT*FROMdeptWHEREdeptno=#{id}
有两个查询语句:
一个来加载员工,另外一个来加载部门,而且员工的结果映射描述了“selectDept"语句应该被用来加载它的dept属性。
其他所有的属性将会被自动加载,假设它们的列和属性名相匹配。
这种方式很简单,但是对于大型数据集合和列表将不会表现很好。
问题就是我们熟知的“N+1查询问题"。
概括地讲,N+1查询问题可以是这样引起的:
?
1.执行了一个单独的SQL语句来获取结果列表(就是“+1")。
?
2.对返回的每条记录,执行了一个查询语句来为每个加载细节(就是“N")。
这个问题会导致成百上千的SQL语句被执行。
这通常不是期望的。
MyBatis能延迟加载这样的查询就是一个好处,因此可以分散这些语句同时运行的消耗。
然而,如果加载一个列表,之后迅速迭代来访问嵌套的数据,会调用所有的延迟加载,这样的行为可能是很糟糕的。
非常重要:
在嵌套查询映射中id元素扮演了非常重要的角色。
应该通常指定一个或多个属性,它们可以用来唯一标识结果。
实际上就是如果离开她了,有一个严重的性能问题是MyBatis仍然可以工作。
选择的属性越少越好,它们可以唯一地标识结果。
主键就是一个显而易见的选择(尽管是联合主键)。
现在,上面的示例用了嵌套的形式把dept结果嵌套到emp映射,但是这种情况不利于对dept结果映射的重用。
如果想重用这样的结果映射,这里给出使用这种方式的相同示例:
javaType="org.mybatis.example.Dept"resultMap="deptresultmap">
上面已经看到了如何处理“有一个"类型关联。
但是“有很多个"是怎样的?
下面这个部分就是来讨论这个主题。
1.1.2.2一对多关联查询(集合)
Emp对Dept是多对一,反过来从Dept来看则是一对多,实体类Dept映射一对多的示例代码:
publicclassDept{
privateIntegerdeptno;
privateStringdname;
privateStringloc;
privateListemps;
省略getter与setter
集合嵌套结果查询:
需要在Dept添加多的一方的集合属性。
另外如果达到一对多映射,必须修改映射文件:
DeptMapper.xml,如下所示:
集合元素的作用几乎和关联是相同的。
实际上,它们也很相似,文档的异同是多余的。
所以更多关注于它们的不同。
来继续上面的示例,一个员工只有一个部门。
但是部门有很多员工。
在部门类中,这可以由下面这样的写法来表示:
privateListemps;
要映射嵌套结果集合到List中,我们使用集合元素。
就像关联元素一样,我们可以从连接中使用嵌套查询,或者嵌套结果。
集合的嵌套查询
来看看使用嵌套查询来为部门加载员工。
resultMap="empresultmap">
这里应该注意很多东西,但大部分代码和上面的关联元素是非常相似的。
首先,应该注意使用的是集合元素。
然后要注意那个新的“ofType"属性。
这个属性用来区分JavaBean(或字段)属性类型和集合包含的类型来说是很重要的。
所以可以读出下面这个映射:
select="empresultmap">
“在org.mybatis.example.Emp类型的ArrayList中的emps的集合。
"
javaType属性是不需要的,因为MyBatis在很多情况下会为"算出来。
所以可以缩短成以上写法。
至此,可以猜测集合的嵌套结果是如何来工作的,因为它和关联完全相同,除了它应用了一个“ofType"属性
select
e.empno,e.ename,e.job,e.mgr,e.hiredate,e.sal,m,
d.deptno,d.dname,d.loc
fromdeptdleftjoinempeone.deptno=d.deptno
又一次联合了部门表和员工表,而且关注于保证特性,结果列标签的简单映射。
使用以下代码测试数据:
示例2.2
publicstaticvoidmain(Stringargs){
SqlSessionsession=SqlSessionFactoryUtil.getSqlSession();
DeptMapperdeptmapper=session.getMapper(DeptMapper.class);
ListdeptList=deptmapper.selectOnetoMany();
for(Deptdept:
deptList){
System.out.println("部门名称:
"+dept.getDname());
System.out.println("所属员工的个数:
"+dept.getEmps().size());
}
session.close();
}
查询结果:
同样,要记得id元素的重要性,如果不记得了,请阅读上面的关联部分。
同样,如果引用更长的形式,允许的结果映射的更多重用,可以使用上面提到的集合的嵌套查询。
注意:
这个对所映射的内容没有深度,广度或关联和集合相联合的限制。
当映射它们时应该在大脑中保留它们的表现。
应用在找到最佳方法前要一直进行的单元测试和性能测试。
好在myBatis让后来可以改变想法,而不对代码