MyBatis系列四 映射器(上)

  映射器是MyBatis最强大的工具,也是我们使用MyBatis时用得最多的工具,因此熟 练掌握它十分必要。MyBatis是针对映射器构造的SQL构建的轻量级框架,并且通过配置 生成对应的JavaBean返回给调用者,而这些配置主要便是映射器,在MyBatis中你可以根 据情况定义动态SQL来满足不同场景的需要,它比其他框架灵活得多。MyBatis还支持自 动绑定JavaBean,我们只要让SQL返回的字段名和JavaBean的属性名保持一致(或者釆 用驼峰式命名),便可以省掉这些繁琐的映射配置。

一、映射器的主要元素

  首先让我们明确在映射器中我们可以定义哪些元素,它们的作用分别是什么,如表4.1 所示。

表4・1映射器的配置

元素名称

描 述

备 注

select

査询语句,最常用、最复杂的元素之一

可以自定义参数,返回结果集等

insert

插入语句

执行后返回一个整数,代表插入的条数

update

更新语句

执行后返回一个整数,代表更新的条数

delete

删除语句

执行后返回一个整数,代表删除的条数

parameterMap

定义参数映射关系

即将被删除的兀素,不建议大家使用

sql

允许定义一部分的SQL,然后在各个地方引用

例如,一张表列名,我们可以一次定义,在 多个SQL语句中使用

元素名称

描 述

备 注

resultMap

用来描述从数据库结果集中来加载对象,它是 最复杂、最强大的元素

它将提供映射规则

cache

给定命名空间的缓存配置

cache-ref

其他命名空间缓存配置的引用

接下来我们将详细讨论映射器中主要元素的用法。

二、select 元素

1、概述

  毫无疑问,select元素是我们最常用也是功能最强大的SQL语言。select元素帮助我们 从数据库中读出数据,组装数据给业务人员。执行select语句前,我们需要定义参数,它可以是一个简单的参数类型,例如int、float. String,也可以是一个复杂的参数类型,例如JavaBean、Map等,这些都是MyBatis接受的参数类型。执行SQL后,MyBatis也提供了强大的映射规则,甚至是自动映射来帮助我们把返回的结果集绑定到JavaBean中。select元素的配置如表4.2所示。

表4-2 select元素的配置

元 素

说 明

备 注

id

它和Mapper的命名空间组合起来是唯一的,提供给MyBatis调 用

如过命名空间和id组合起 来不唯一,MyBatis将抛出

异常

parameterType

你可以给出类的全命名,也可以给出类的别名,但使用别名必 须是MyBatis内部定义或者自定义的

我们可以选择JavaBean >

Map等复杂的参数类型传递 给SQL

parameterMap

即将废弃的元素,我们不再讨论它

.

resultType

定义类的全路径,在允许自动匹配的情况下,结果集将通过 JavaBean的规范映射;

或定义为int、double> float等参数;

也可以使用别名,但是要符合别名规范,不能和resultMap同时 使用

它是我们常用的参数之 一,比如我们统计总条数就 可以把它的值设置为int

元 素

说 明

备 注

resultMap

它是映射集的引用,将执行强大的映射功能,我们可以使用 resultType或者resultMap其中的一个,resultMap可以给予我们自 定义映射规则的机会

它是MyBatis最复杂的元 素,可以配置映射规则、级 联、typeHandler 等

flushCache

它的作用是在调用SQL后,是否要求MyBatis清空之前査询的 本地缓存和二级缓存

取4

默认勺

莹为布尔值,true/falseo

莹为false

useCache

启动二级缓存的开关,是否要求MyBatis将此次结果缓存

取值为布尔值,true/falseo

默认值为true

timeout

设置超时参数,等超时的时候将抛出异常,单位为秒

默认值是数据库厂商提供 的JDBC驱动所设置的秒数

fetchSize

获取记录的总条数设定

默认值是数据库厂商提供 的JDBC驱动所设置的条数

statementType

告诉MyBatis使用哪个JDBC的Statement工作,取值为

STATEMENT(Statement)、PREPARED ( PreparedStatement )、

CallableStatement

默认值为PREPARED

resultSetType

这是对JDBC的resultSet接口而言,它的值包括FORWARD, ONLY (游标允许向前访问)、SCROLL_SENSITIVE (双向滚动, 但不及时更新,就是如果数据库里的数据修改过,并不在resultSet 中反应出来)、SCROLL_INSENSITIVE (双向滚动,并及时跟踪 数据库的更新,以便更改resultSet中的数据)

默认值是数据库厂商提供

的JDBC驱动所设置的

databaseld

它的使用请参考第3章的databaseldProvider数据库厂商标识这 部分内容

提供多种数据库的支持

resultOrdered

这个设置仅适用于嵌套结果集select语句。如果为true,就是假 设包含了嵌套结果集或者是分组了。当返回一个主结果行的时候, 就不能对前面结果集的引用。这就确保了在获取嵌套的结果集的 时候不至于导致内存不够用

取6

默认6

专为布尔值,true/falseo

皇为false

resultSets

适合于多个结果集的情况,它将列出执行SQL后每个结果集的 名称,每个名称之间用逗号分隔

很少使用

2、简易数据类型的例子

  例如,我们需要统计一个姓氏的用户数量。我们应该把姓氏作为参数传递,而将结果设置为整形返回给调用者,如代码清单4.1所示。

代码清单4・1 select的简单例子

<select id= "countFirstName ”  parameterType= " string ” resultType= " int ” > 
select count (*) as total from t_user where name like concat (# { firstName),'%;)
</select>

我们在接口 UserDao中定义方法。

public int countFirstNcme(String firstName);

这样就可以使用MyBatis调用SQL 了,十分简单。下面对操作步骤进行归纳概括。

  • id标出了这条SQL。
  • parameterType定义参数类型。
  • resultType定义返回值类型。

当然这个例子只是为了用来入门,我们将来遇到的问题远比这个复杂得多。

3、自动映射

  有这样的一个参数autoMappingBehavior,当它不设置为NONE的时候,MyBatis会提 供自动映射的功能,只要返回的SQL列名和JavaBean的属性一致,MyBatis就会帮助我们 回填这些字段而无需任何配置,它可以在很大程度上简化我们的配置工作。在实际的情况 中,大部分的数据库规范都是要求每个单词用下划线分隔,而Java则是用驼峰命名法来命 名,于是使用列的别名就可以使得MyBatis自动映射,或者直接在配置文件中开启驼峰命 名方式。

  让我们来看一个例子,体验一下自动映射的好处。我们需要通过角色编号查询一个角色,并将结果集映射到角色的JavaBean ±o我们先给出JavaBean,如代码清单4.2所示。

代码清单4・2: Role.java

package com.learn.chapter4.po;
public class Role (
  private Long id;
  private String roleName;
  private String note;
  public Long getld() {
    return id;
  public void setld(Long id) (
    this.id = id;
  }
  public String getRoleName() (
    return roleName;
  }
  public void setRoleName(String roleName) (
    this.roleName = roleName;
  )
  public String getNote () (
    return note;
  }
  public void setNote(String note) (
    this.note = note;
  }
}

而数据库表(T_ROLE)的字段如表4.3所示。

表4.3数据库表T ROLE描述

字 段

•类 型

说 明

ID

INT(20)

角色编号,主键,递增

ROLE NAME

VARCHAR(60)

角色名称

NOTE

VARCHAR(1024)

备注

让我们编写Mapper的映射语句,如代码清单4-3所示。

代码清单4・3:自动映射

<select parameterType="id" id="getRole" resultType="com.learn• chapter4. pojo.Role" >
Select id, role_name as roleNamef note from t_role
where id =#{id}
</select>

对于RoleDao接口,我们提供一个方法。

public Role getRole(Long id);

  这样就可以使用它,角色名称(m2_name)使用SQL提供的别名功能使得查询结果 JavaBean的属性一一对应起来,然后MyBatis提供的自动映射的功能使得我们无需过多 的提供配置信息,大大减少了我们的工作量。

  自动映射可以在settings元素中配置autoMappingBehavior属性值来设置其策略。它包 3个值。

    • NONE,取消自动映射。
    • PARTIAL,只会自动映射,没有定义嵌套结果集映射的结果集。
    • FULL,会自动映射任意复杂的结果集(无论是否嵌套)。

  默认值为PARTIAL0所以在默认的情况下,它可以做到当前对象的映射,使用FULL 是嵌套映射,在性能上会下降。

  如果你的数据库是规范命名的,即每一个单词都用下划线分隔,POJO釆用驼峰式命名 方法,那么你也可以设置mapUnderscoreToCamelCase true,这样就可以实现从数据库到 POJO的自动映射了。

4、传递多个参数

(1)使用Map传递参数

对于RoleDao接口,我们提供一个方法。

public List<Role> findRoleByMap(Map<String, String〉params);

输入上面的代码就可以使用这个方法了,如代码清单4.5所示。

 

  这个方法虽然简单易用,但是有一个弊端:这样设置的参数使用了 Map,而Map需要 键值对应,由于业务关联性不强,你需要深入到程序中看代码,造成可读性下降。MyBatis 为我们提供了更好的实现方法,它就是注解参数的形式,让我们看看如何实现。

(2)使用注解方式传递参数

  我们需要使用 MyBatis 的参数注解@Param(org.apache.ibatis.annotations.Param)来实现 想要的功能。操作方法是,把RoleDao接口修改为下面的形式。

  我们把映射器的XML修改为无需定义参数类型,如代码清单4-6所示。

 

  当我们把参数传递给后台的时候,通过@Param提供的名称MyBatis就会知道 #{roleName}代表rolename参数,参数的可读性大大提高了。但是这会引起另一个麻烦,一 SQL拥有10个参数的查询,如果我们都使用@Param方式,那么参数将十分复杂,可读 性依旧不高,不过MyBatis为我们提供了 JavaBean定义参数的方式来解决这个问题。

(3)使用JavaBean传递参数

  在参数过多的情况下,MyBatis允许组织一个JavaBean,通过简单的setter和getter方法设置参数,这样就可以提高我们的可读性。首先,定义一个RoleParams的JavaBean,如代码清单4.7所示。

代码清单4・7:定义简易的参数JavaBean

package com.learn.chapter4.params;
public class RoleParam (
  private String roleName; private String note;
  public String getRoleName() (
    return roleName;
  }
  public void setRoleName(String roleName) ( 
    this.roleName = roleName;   }   public String getNote() (     return note;   }   public void setNote(String note) (
    this.note = note;   }

  我们用JaveBean改写一下传递参数的例子,如代码清单4-8所示。

 

  同样我们在RoleDao接口提供一个方法。

public List<Role> findRoleByParams(RoleParam params);

  这就是通过JavaBean的方式传递多个参数的方式。

(4)总结

  • 使用Map传递参数。因为Map导致业务可读性的丧失,从而导致后续扩展和维护 的困难,我们应该在实际的应用中果断废弃这样的传递参数的方式。
  • 使用@Param注解传递多个参数,这种方式的使用受到参数个数(n)的影响。当n <=5时,它是最佳的传参方式,它比用JavaBean更好,因为它更加直观;当n>5 时,多个参数将给调用带来困难。
  • 当参数个数多于5个时,建议使用JavaBean方式。

5、使用resultMap映射结果集

  在某些时候,我们需要处理更为复杂的映射, resultMap为我们提供了这样的模式。我们需要在映射器中定义resultMap,这也是我们常见 的场景,如代码清单4-9所示。

解释一下resultMap的配置。

  • 定义了一个唯一标识(id)为roleResultMap的resultMap,用type属性去定义它对 应的是哪个JavaBean (也可以使用别名)。
  • 通过id元素定义resultResultMap,这个对象代表着使用哪个属性作为其主键。result 元素定义普通列的映射关系,例如,把SQL结果返回的列role no和type属性定义 JavaBean的属性roleNo等做一一对应。
  • 这样select语句就不再需要使用自动映射的规则,直接用resultMap属性指定 roleResultMap即可,这样MyBatis就会使用我们的自定义映射规则。

  resultMap可没有你所看见的那么简单,它是映射器中最为复杂的元素,它一般用于复杂、级联这些关联的配置。在简单的情况下,我们可以使用resultType通过自动映射来完 成,这样配置的工作量就会大大减少,未来随着进一步的学习深入,我们还会讨论resultMap 的高级应用。

三、insert 元素

1、概述

insert元素,相对于select元素而言要简单许多。MyBatis会在执行插入之后返回一个 整数,以表示你进行操作后插入的记录数。insert元素配置详解,如表4.4所示。

  虽然元素也不少,但是我们实际操作中常用的元素只有几个,并不是很难掌握,让我们 做一个插入角色的操作。首先需要在映射器中定义我们的插入语句,如代码清单4.10所示。

2、主键回填和自定义

  现实中有许多我们需要处理的问题,例如,主键自增字段;MySQL里面的主键需要根据一些特殊的规则去生成,在插入后我们往往需要获得这个主键,以便于未来的操作,而MyBatis提供了实现的方法。

  首先我们可以使用keyProperty属性指定哪个是主键字段,同时使用useGeneratedKeys 属性告诉MyBatis这个主键是否使用数据库内置策略生成。

  我们的例子中t role表就是指定了 id列为自增字段。因此我们建立POJO,它能提供setter和getter方法,这样便能够使用MyBatis的主键回填功能了。

  那么我们可以在XML中进行如代码清单4.11所示的配置。

 

  这样我们传入的role对象就无需设置id的值,MyBatis会用数据库的设置进行处理。 这样做的好处是在MyBatis插入的时候,它会回填JavaBean的id值。我们进行调试,在插 入后,它自动填充主键,方便以后使用。

  让我们测试一下这个功能,如代码清单4.12所示。

代码清单4-12:主键回填测试

sqlSession = SqlSessionFactoryUtil.openSqlSession ();
RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
Role role = new Role(); role.setRoleName("test4"); role.setRoleName("test4Note");
roleMapper.insertRole(role); System.err.printIn(role.getId());

让我们看看调试的结果,如图4.1所示。

  实际工作往往不是我们想象的那么简单,需要根据一些特殊的关系设置主键id的值。假设我们取消表t role的id自增的规则,我们的要求是:如果表t_role没有记录,则我们需要设置id=l,否则我们就取最大id加2,来设置新的主键,对于一些特殊要求,MyBatis 也提供了应对方法。

  这个时候我们可以使用selectKey元素进行处理,操作方法如代码清单4-13所示。

代码清单4-13:使用自定义主键生成规则

 

<insert id ="insertRole" parameterType="role" useGeneratedKeys= "true" keyProperty="id">
<selectKey keyProperty="id" resultType="int" order= "BEFORE" >
select if(max(id) is null, 1, max(id) + 2) as newld from t_role 
</selectKey> insert into t_role(id, role_namez note) values (#(id), #{roleName},#(note)) </insert>

这样我们就能定义自己的规则来生成主键了,MyBatis的灵活性也得以体现。

四、update元素和delete元素

  这两个元素比较简单,所以我们放在一起讨论。和insert元素一样,MyBatis执行完 update元素和delete元素后会返回一个整数,标出执行后影响的记录条数。

  让我们看看映射文件的配置方法,我们来配置更新和删除角色的XML文件,如代码 清单4-14所示。

  我们所面对的大部分场景都和这相似,需要通过一个JavaBean插入一张表的记录或者 根据主键删除记录,对于参数传递可以参考select元素传递参数的例子。插入和删除执行 完成MyBatis会返回一个整数显示更新或删除了几条记录。

 

 

 

posted @ 2020-09-03 22:22  跃小云  阅读(208)  评论(0编辑  收藏  举报