1.1 SQL映射
SQL映射是MyBatis框架最具特色的部分,功能强大且使用简单。在第1章中提到,MyBatis框架的主要思想是将SQL语句从程序代码中分离出来,对JDBC访问数据库的代码进行封装,从程序中消除了所有SQL参数设置及处理结果集的JDBC代码,从而大幅减少数据访问层的编码量。并且,SQL语句与代码解耦,可以最大限度地实现对SQL语句的灵活管理,方便SQL调优以保证性能。
SQL映射文件中的几个顶级元素介绍如下。
1、mapper:SQL映射文件的根元素。只有一个属性namespace,用于区分不同的mapper,必须全局唯一。
2、cache:为给定命名空间配置缓存。
3、cache-ref:引用其他命名空间中的缓存配置。
4、resultMap:用来描述查询结果集中的字段和Java实体类属性的对应关系。
5、sql:定义可重用的SQL语句块,可以在其他语句映射中引用,提高编写和维护SQL语句的效率。
6、insert:映射insert语句。
7、update:映射update语句。
8、delete:映射delete语句。
9、select:映射select语句。
1.2 MyBatis框架的条件查询
1.2.1 实现单一条件查询
如果仅传入一个简单数据类型的查询条件,如一个基本数据类型或其包装类型,或一个String类型等,MyBatis框架的处理方式也非常简单。以实现根据用户的真实姓名模糊匹配来查询用户信息为例,关键代码如示例1所示。
示例1
根据用户的真实姓名模糊匹配查询用户信息。
关键代码:
(1)在SysUserMapper接口中添加查询方法
/**
* 根据用户的真实姓名模糊匹配查询用户,参数realName为需要传递给SQL语句的查询条件
*/
public List<SysUser> getUsersByRealName(String realName);
(2)在SysUserMapper.xml中添加SQL语句映射:
<select id="getUsersByRealName" resultType="sysuser" parameterType="string">
select * from t_sys_user where realName like CONCAT('%', #{param}, '%')
</select>
(3)在测试类中添加测试方法:
······ //省略创建SqlSession的代码
List<SysUser> userList =sqlSession.getMapper(SysUserMapper.class)
.getUsersByRealName("李");
······ //省略输出查询结果的代码
运行测试方法,结果如图2.1所示。
1.2.2 实现多条件查询
在实际应用中,数据查询经常会综合多种条件,如724系统用户管理模块中的查询用户功能,查询条件包括用户名(模糊匹配)和用户角色,如图2.2所示。对于多条件查询,MyBatis框架提供了多种方法实现条件赋值。
1. 将查询条件封装成Java对象作为入参
2. 将查询条件封装成Map对象作为入参
3 使用@Param注解实现多参数入参
1.3 MyBatis框架的结果映射
前面的示例多次在SQL映射文件中使用resultType属性指定查询结果为SysUser类型,MyBatis框架也能正确地将查询结果封装在SysUser实例的属性中。这实际上是MyBatis框架自动映射的结果,MyBatis框架会获取结果集中的列名称并查找具有相同名称的属性进行赋值。但实际开发中的情况会更加复杂,如数据库与应用程序的命名规则不统一、列名和属性名不同,或使用连接查询时需要封装来自多张表的数据,这时域对象要如何设计?针对这些问题可以有不同的解决方案,如在SQL语句中使用select子句别名、修改域模型设计以包含关联字段等。但是,这些方法都有明显的弊端,使用select子句别名会大大增加SQL语句的开发工作量,烦琐且易错,改变域模型设计规则会破坏面向对象的设计原则,导致混乱。为此,MyBatis框架提供了Result Map机制来自定义结果映射,简单灵活而又功能强大。
1.3.1 使用resultMap元素自定义结果映射
MyBatis框架使用resultMap元素来自定义结果映射。下面通过示例模拟实体类属性名和数据表列名不一致的情况,了解resultMap元素的基本用法。现在要查询用户信息列表,需要展示的字段包括账号、真实姓名、性别、电话、用户角色,注意用户角色要显示角色名称而不是角色ID。在SysUser类中加入角色名称属性,且与数据库角色表中角色名称字段不同名,如示例11所示。
示例11
在SysUser类中加入角色名称属性及getter/setter访问器,且该属性名与数据库角色表中的角色名称字段不同名。
关键代码:
public class SysUserimplements java.io.Serializable {
······ //省略其他属性
private String userRoleName; //角色名称
······ //省略getter/setter方法
1.3.2 嵌套结构映射
使用连接查询时,结果集中往往会包含与多个实体类相关的信息,此时即可使用嵌套结果映射解决数据封装问题。
1、accociation元素
accociation元素用来处理"has-one"类型的关系,如用户类内部“有一个”用户角色类型的属性、入库记录类中“有一个”供货商类型的属性。
2、collection元素
collection元素和accociation元素作用非常类似,只不过表达的是“一对多”关系,即实体类内部嵌套的是一个集合类型的属性。
1.3.3 resultType与resultMap小结
使用select元素映射查询语句时,对于返回结果的定义可以使用resultType属性,也可以使用resultMap属性。那么,二者有何区别呢?
从使用场景来看,resultType属性直接指定结果类型,依靠自动映射实现对实体类等复杂数据类型的封装,适用于比较简单、直接的数据封装场景;而resultMap属性是对外部resultMap定义的引用,可以自由控制结果映射规则和封装范围,能够处理结果集字符名与实体类属性名不一致,或需要对连接查询结果使用嵌套映射等较为复杂的问题。
从底层实现来看,MyBatis框架将查询出来的结果集首先存储在Map结构中,以字符名作为key。当select元素使用resultType属性指定结果类型时,MyBatis框架会自动将Map中的键值对对应赋值给实体类中与key同名的属性(通过调用setter访问器实现);使用resultMap属性时,则根据所引用的resultMap元素中定义的映射规则把Map中的键值对赋值给指定的实体类属性。
1.3.4 resultMap的自动映射行为
可以在MyBatis框架的核心配置文件中进行设置,修改自动映射的行为。修改mybatis-config.xml,在<settings>元素中添加如下设置。
<settings>
<!-- 省略其他设置 -->
<!-- 设置自动映射行为 -->
<setting name="autoMappingBehavior" value="FULL" />
</settings>
以上配置将自动映射行为设置为FULL,即全部使用自动映射,即使有嵌套映射的resultMap,也会使用自动映射。
1.4 MyBatis框架的增、删、改操作
了解了如何在MyBatis框架中执行查询和封装结果后,下面学习如何在MyBatis框架中执行增、删、改操作。
1.4.1 执行insert语句
1.4.2 执行update语句
1.4.3 执行delete语句
1.5 MyBatis框架的缓存
1.5.1 MyBatis框架的缓存分类
MyBatis框架的缓存分为两个级别。
1.一级缓存
MyBatis框架的一级缓存是基于PerpetualCache的HashMap本地缓存,默认是SqlSession级别的缓存,在SqlSession的一个生命周期内有效。当SqlSession关闭后,该SqlSession中所有的一级缓存会被清空。MyBatis框架的一级缓存默认是开启的。
2.二级缓存
二级缓存是SqlSessionFactory级别的,其作用域超出了一个SqlSession的范围,缓存中的数据可以被所有SqlSession共享。MyBatis框架的二级缓存默认是关闭的,使用时需要在MyBatis框架的核心配置文件中设置开启。
1.5.2 二级缓存的使用方法
在MyBatis框架中使用二级缓存需要以下几个环节。
(1)在MyBatis框架的核心配置文件中设置全局开启二级缓存,代码如下。
<settings>
<settingname="cacheEnabled"value="true"/>
</settings>
(2)即使全局开启了二级缓存,默认情况下也是不使用二级缓存的。可以根据需要在SQL映射文件(如SysUserMapper.xml)中配置缓存,为当前namespace启用二级缓存,代码如下。
<mapper namespace="cn.cvs.dao.sysUser.SysUserMapper">
<!-- 缓存配置 -->
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
......
</mapper>
本章总结
◎ MyBatis框架的SQL映射文件提供select、insert、update、delete等元素来实现SQL语句的映射。
◎ SQL映射文件的根节点是mapper元素,其namespace属性的值需要保证全局唯一,用于区分不同的mapper。
◎ 基于面向接口编程的理念,mapper元素的namespace属性值应指定为Mapper接口的完全限定类名。
◎ SQL映射文件的select元素可以使用resultMap或resultType指定返回结果的类型,但二者不能同时使用。
◎ 为Mapper接口方法传入多个简单类型的参数时,建议使用@Param注解为参数命名。
◎ 在resultMap元素中可以使用association元素和collection元素实现嵌套结果映射。