2.3 MyBatis框架的映射文件
MyBatis框架真正强大之处在于SQL映射语句,这也是其魅力所在。相对于它强大的功能,SQL映射文件的配置却非常简单。在第1章中将SQL映射配置和JDBC代码对比发现,使用SQL映射文件配置可减少50%以上的代码量,并且MyBatis框架专注于SQL,对于开发人员来说,也可极大限度地进行SQL调优以保证其性能。下面是关于SQL映射文件的顶级元素配置。
(1)mapper:映射文件的根元素节点,只有一个属性namespace(命名空间),其作用如下:
①用于区分不同的mapper,全局唯一;
②绑定DAO接口,即面向接口编程。当namespace绑定某个接口后,就可以不用写该接口的实现类,MyBatis框架会通过接口的完整限定名查找到对应的mapper配置来执行SQL语句。因此namespace的命名必须要跟接口同名。
(2)cache:配置给定命名空间的缓存。
(3)cache-ref:从其他命名空间引用的缓存配置。
(4)resultMap:用来描述数据库结果集和对象的对应关系。
(5)sql:重用的SQL块,也可被其他语句引用。
(6)insert:映射插入语句。
(7)update:映射更新语句。
(8)delete:映射删除语句。
(9)select:映射查询语句。
关于MyBatis框架的SQL映射文件中mapper元素的namespace属性有如下要求。
(1)namespace的命名必须跟某个DAO接口同名,同属于DAO层,故代码结构上,映射文件与该DAO接口应放置在同一package下(如cn.dsscm.dao.user),并且都是以Mapper 结尾(UserMapper.java、UserMapper.xml)。
(2)在不同的mapper文件中,子元素的id可以相同,MyBatis通过namespace和子元素的id联合区分。接口中的方法与映射文件中SQL语句id应相互对应。
映射文件是MyBatis框架中十分重要的文件,可以说,MyBatis框架强大之处就体现在映射文件的编写上。下面将对MyBatis框架映射文件中的元素进行详细讲解。
2.3.1 主要元素
在映射文件中,<mapper>元素是映射文件的根元素,其他元素都是其子元素。这些子元素及其作用如图2.9所示。
图2.9 映射文件中的主要元素
2.3.2 <select>元素
<select>元素用于映射查询语句,可以帮助从数据库中读取数据,并组装数据给业务开发人员。使用<select>元素执行查询操作的方法,见示例10。
【示例10】 使用<select>元素
上述语句中的唯一标识为findUserById,它接收一个Integer类型的参数,并返回一个User类型的对象。<select>元素中,除了上述示例代码中的属性,还有其他一些可以配置的属性,如表2-9所示。
表2-9 <select>元素的常用属性
2.3.3 <insert>元素
<insert>元素用于映射插入语句,在执行完元素中定义的SQL语句后,会返回一个表示插入记录数的整数。<insert>元素的配置见示例11。
【示例11】 使用<insert>元素
从上述示例代码中可以看出,<insert>元素的属性与<select>元素的属性大部分相同,但还包含了3个特有属性,如表2-10所示。
表2-10 <insert>元素的特有属性
执行插入操作后,需要返回插入成功的数据生成的主键值时,就可以通过上面所讲解的3个属性来实现。如果使用的数据库支持主键自动增长(如MySQL),那么可以通过keyProperty属性指定POJO类的某个属性接收主键返回值(通常会设置到id属性上),然后将useGeneratedKeys的属性值设置为true,其使用见示例12。
【示例12】 使用<insert>元素属性
使用上述配置执行插入后,就会返回插入成功的行数,以及插入行的主键值。为了验证此配置,可以通过前面的代码测试。
如果使用的数据库不支持主键自动增长(如Oracle),或者支持增长的数据库取消了主键自增的规则时,也可以使用MyBatis提供的另一种方式来自定义生成主键,具体配置见示例13。
【示例13】 使用主键自增
在执行上述示例代码时,<selectKey>元素会首先运行,它会通过自定义的语句来设置数据表中的主键(如果tb_user表中没有记录,则将id设置为1,否则就将id的最大值加1来作为新的主键),然后再调用插入语句。
<selectKey>元素在使用时可以设置以下几种属性:
在上述<selectKey>元素的属性中,keyProperty、resultType和statementType的作用与前面讲解的相同,这里不重复介绍。order属性可以被设置为BEFORE或AFTER。如果设置为BEFORE,那么它会首先执行<selectKey>元素中的配置来设置主键,然后执行插入语句;如果设置为AFTER,那么它会先执行插入语句,然后执行<selectKey>元素中的配置内容。
2.3.4 <update>元素和<delete>元素
<update>元素和<delete>元素的使用比较简单,它们的属性配置也基本相同(<delete>元素中不包含表2-10中的3个属性),其常用属性见示例14。
【示例14】 使用<update>元素和<delete>元素
从上述配置代码中可以看出,<update>元素和<delete>元素的属性与<select>元素中的属性基本一致。与<insert>元素一样,<update>和<delete>元素在执行完之后,也会返回一个表示影响记录条数的整数,其使用见示例15。
【示例15】 使用<update>元素和<delete>元素
2.3.5 <sql>元素
在一个映射文件中,通常需要定义多条SQL语句,这些SQL语句的组成可能有一部分是相同的(如多条select语句中都查询相同的id、username、jobs字段),如果每一个SQL语句都重写一遍相同的部分,势必会增加代码量导致映射文件过于臃肿。那么有什么办法将这些SQL语句中相同的组成部分抽取出来,然后在需要的地方引用呢?答案是肯定的,可以在映射文件中使用MyBatis所提供的<sql>元素来解决上述问题。
<sql>元素的作用就是定义可重用的SQL代码片段,然后在其他语句中引用这个代码片段。例如,定义一个包含id、userCode、userName和userPassword等字段的代码片段如下:
这个代码片段可以包含在其他语句中使用,见示例16。
【示例16】 使用<sql>元素
在上述代码中,使用<include>元素的refid属性引用了自定义的代码片段,refid的属性值为自定义代码片段的id。
上面只是一个简单的引用查询。在实际开发中,可以更加灵活地定义SQL片段,见示例17。
【示例17】 使用SQL片段
上述代码中,定义了3个代码片段,分别为表的前缀名、要查询的表和需要查询的列。前两个代码片段中,分别获取了<include>子元素<property>中的值,其中第1个代码片段中的“${prefix}”会获取name为prefix的值“tb_”,获取后所组成的表名为“tb_user”;而第2个代码片段中的“${indude_target}”会获取name为include_target的值“tablename”,由于tablename为第1个SQL片段的id值,所以最后要查询的表为“tb_user”。所有的SQL片段在程序运行时,都会由MyBatis组合成SQL语句来执行需要的操作。
2.3.6 <resultMap>元素
<resultMap>元素表示结果映射集,是MyBatis中最重要、最强大的元素。它的主要作用是定义映射规则、级联的更新及定义类型转化器等。
<resultMap>元素中包含了一些子元素,它的元素结构见示例18。
【示例18】 <resultMap>元素
<resultMap>元素的type属性表示需要映射的POJO类,id属性是这个resultMap的唯一标识。它的子元素<constmctor>用于配置构造方法(当一个POJO类中未定义无参的构造方法时,就可以使用子元素<constructor>进行配置)。子元素<id>用于表示哪个列是主键,而<result>元素用于表示POJO类和数据表中普通列的映射关系。<association>元素和<collection>元素用于处理多表时的关联关系,而<discriminator>元素主要用于处理一个单独的数据库查询返回很多不同数据类型结果集的情况。
在默认情况下,MyBatis程序在运行时会自动将查询到的数据与需要返回对象的属性进行匹配赋值(需要表中的列名与对象的属性名称完全一致)。然而实际开发时,数据表中的列和需要返回的对象属性可能不会完全一致,这种情况下MyBatis框架是不会自动赋值的。此时就可以使用<resultMap>元素进行处理。
2.3.7 技能训练
上机练习3 实现供应商表的查询
需求说明
(1)在上机练习2的基础上,实现订单表的查询操作。
(2)实现订单表的增加操作。
(3)实现根据供应商id修改订单信息的操作。
(4)实现根据供应商id删除订单信息的操作。
(1)增加和修改订单。
①使用insert元素和update元素。
②parameterType:Java实体类Bill。
③DAO层接口方法的返回类型:int。
createBy、creationDate、modifyDate、modifyBy这4个字段应根据方法选择增加或者修改进行灵活操作。
(2)删除订单:使用delete元素。