目录

1、概述

2、select元素

2.1 简单的select元素的应用

2.2 自动映射和驼峰映射

2.3 传递多个参数

2.3.1 使用map接口传递参数

2.3.2 使用注解传递参数

2.3.3 使用Java Bean传递参数

2.3.4 使用混合方式传递参数

2.4 使用resultMap映射结果集

2.5 分页参数RowBounds

3、insert元素

3.1 简单的insert语句的应用

3.2 主键回填

3.3 自定义主键

4、update元素和delete元素

5、sql元素


映射器是MyBatis最为复杂且最重要的组件。它由一个接口和XML文件(或注解)组成。在映射器中可以配置参数、SQL语句、存储过程、缓存、级联等,并能够通过简易的映射规则映射到指定的POJO或其他对象上,映射器能够有效消除JDBC底层的代码。

整个MyBatis应用程序开发中,映射器的开发量占全部工作量的80%。MyBatis的映射器可以使用注解完成,但是应用范围并不广,主要原因:【1】面对复杂性,SQL会显得无力,尤其是面对较长的SQL;【2】注解的可读性较差;【3】在功能上,注解丢失了XML上下文相互引用的功能。基于实际情况,我们主要讨论XML的实现方式。

1、概述

映射器的配置元素:

     元素                                                   描述                              备注
select 查询语句 自定义参数,返回结果等
insert 插入语句 执行后返回一个整数,代表插入的条数
update 更新语句 执行后返回一个整数,代表更新的条数
delete 删除语句 执行后返回一个整数,代表删除的条数
sql 允许定义一部分SQL,然后再各个地方引用它 一次定义,可以在多个SQL语句中使用
resultMap 描述从数据库结果集中来加载对象,它是最复杂、最强大的元素 提供映射规则
cache 给定命名空间的缓存配置 ——
cache-ref 其他命名空间缓存配置的引用 ——

2、select元素

select元素代表SQL的select语句,用于查询。看一下select元素的配置。

         元素                                               描述                            备注
id id和Mapper的命名空间组合起来是唯一的,供MyBatis使用 如果命名空间和id结合起来不唯一,MyBatis将抛出异常
parameterType 给出类的全命名,也可以给出别名,但是别名必须是MyBatis内部定义或者自定义的 可以选择Java Bean、Map等简单的参数类型传递给SQL
resultType

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

或定义为int、double、float、map等参数

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

常用的参数之一,比如统计总条数时可以把它的值设置为int
resultMap 它是映射集的引用,将执行强大的映射功能。resultType和resultMap不能同时使用 最复杂的元素,可以配置映射规则、级联、typeHandler等
flushCache 在调用SQL后,是否要求MyBatis情况之前查询本地缓存和二级缓存 取值为布尔类型,默认为false
useCache 启动二级缓存的开关,是够要求MyBatis将此次结果缓存 布尔类型,默认为true
timeout 设置超时参数,超时时将抛出异常,单位为秒 默认为数据库厂商提供的JDBC驱动所设置的秒数
fetchSize 获取记录的总条数设定 默认为数据库厂商提供的JDBC驱动所设置的条数
statementType 使用哪个JDBC的Statement工作,取值为STATEMENT、PREPARED、CALLABLE 默认为PREPARED
resultSetType —— 默认为数据库厂商提供的JDBC驱动所设置
databaseId 数据库厂商标识设置 多数据库支持
resultOrdered 用于嵌套结果select语句 布尔类型,默认为false
resultSets 用于多结果集的情况,将列出执行SQL后每个结果集的名称,每个名称之间用逗号分隔 较少使用

2.1 简单的select元素的应用

一个栗子,统计用户表中同一个姓氏的数量:

<select id="" parameterType="String" resultType="sysRole">select count(*) from sys_rolewhere user_name like concat('%',#{firstName},'%')
<select/>
  • id:它配合Mapper的全限定名,联合成一个唯一的标识,用于标识这条SQL
  • parameterType:表示这条SQL接受的参数类型【即传入的参数的类型】,可以是MyBatis系统定义或者自定义的别名;
  • resultType:表示这条SQL语句返回的结果集的类型,与parameterType一样,可以是系统或者自定义的别名,也可以是类的全限定名;
  • #{firstName}:如果传入的是pojo实体类型,占位符中的变量名称必须是pojo实体类中对应的属性.属性.属性...。起到占位作用,如果传入的是基本类型(string,long,double,int,boolean,float等),那么#{}中的变量名称可以随意写。

仅仅只有这一条SQL语句,还不够,我们还需要一个接口程序才能运行起来:

public intserface SysRoleMapper{public Integer getRoleFirstName(String firstName);
}

这个栗子仅仅是让我们认识select元素的基础属性和用法,在实际的开发情况中,我们所遇到的问题比这条SQL更加复杂。

 2.2 自动映射和驼峰映射

MyBatis提供了自动映射的功能,在默认情况下自动映射是开启的,使用它能够有效地减少大量的映射配置,进而减少体力劳动。

关于它们的配置主要在MyBatis的基础文件mybatisConfig.xml中进行配置。在<settings><settings/>元素标签内有两个可以配置的选项autoMappingBehavior和mapUnderscoreToCamelCase,它们是控制自动映射和驼峰映射的开关。

配置自动映射的autoMappingBehavior选项的取值范围是:

  • NONE,不进行自动映射。
  • PARTIAL,默认值,只对没有嵌套结果集进行自动映射。
  • FULL,对所有的结果集进行自动映射,包括嵌套结果集。

默认情况下,使用默认的PARTIAL级别就可以了。为了实现自动映射,首先给出一个POJO类:

public class SysRole{private int id;private String roleName;private String note;/* setter and getter */
}

如上SysRole类,如果编写的SQL列名和属性名保持一致,那么它就会形成自动映射,比如通过角色编号获取角色信息:

<select id="getRole" parameterType="java.lang.Integer" resultType="com.learn.ssmr.chapter5.pojo.SysRole">select id, role_name as roleName ,notefrom sys_rolewhere id = #{id}
<select/>

原来的列名role_name被别名roleName代替了,这样就和POJO上的属性名称保持一致了。此时MyBatis就会将这个结果集映射到POJO的属性roleName上,自动完成映射,而无须再进行任何配置,明显减少了工作量。

如果系统按照驼峰命名法,那么只需在配置项把mapUnderscoreToCamelCase设置为true即可。这样上述SQL语句可以修改成:

<select id="getRole" parameterType="java.lang.Integer" resultType="com.learn.ssmr.chapter5.pojo.SysRole">select id, role_name, notefrom sys_rolewhere id = #{id}
<select/>

MyBatis会严格按照驼峰命名的方式做自动映射,只是这样会要求字段和POJO的属性名严格对应,降低了灵活性。

自动映射和驼峰映射都建立在SQL列名和POJO属性名的映射关系上,而现实开发情况更复杂,可能有些字段有主表和从表关联的级联,或者typeHandler的复杂转换规则,此时resultType元素是无法满足这些要求的。如果需要更强大的映射规则,可考虑使用resultMap。

 2.3 传递多个参数

自己写的demo中多是传递一个参数,在实际开发中我们可能会遇到传递多个参数的情况,如订单可以通过编号查询,也可以通过订单名称、日期或者价格等参数进行查询。假定场景:通过角色名role_name和备注note对角色进行模糊查询,这样就有两个参数了。

2.3.1 使用map接口传递参数

  • 在MyBatis中运行map接口通过键值对传递多个参数,接口方法定义如下:
public interface SysRoleMapper{public List<SysRole> getRoleByMap(Map<String, Object> paramterMap);
}
  • 此时,传递给映射器的是一个map对象,使用它在SQL中设置对应的参数,如下:
<select id="getRoleByMap" paramterType="map" resultType="sysRole">select id, role_name as roleName, notefrom sys_rolewhere role_name like concat('%',#{roleName},'%')and note like concat('%',#{note},'%')
<select/>
  • 设置map参数:
SysRoleMapper roleMapper = sqlSession.getMapper(SysRoleMapper.class);
Map<String, Object> paramterMap = new HashMap<String, Object>();
paramterMap.put("roleName", "1");
paramterMap.put("note", "1");
List<SysRole> roles = roleMapper.getRoleMap(paramterMap);
  • 严格来说,map适用几乎所有场景,但是实际情况使用不多。原因:

【1】map是一个键值对应的集合,使用者需要通过阅读它的键,才能明白其作用;

【2】使用map不能限定其传递的数据类型,因此业务性不强,可读性差。

2.3.2 使用注解传递参数

  • 使用map传递多个参数----可读性差。而MyBatis也提供了一个注解@Param,可以通过它去定义映射器的参数名称,使用它可以得到更好的可读性,接口定义方法如下:
public interface SysRoleMapper{public List<SysRole> getRoleByAnnotation(@Param("roleName") String roleName, @Param("note") String note);
}
  • 可读性提高了,我们能够明确知道参数,一目了然。这个时候需要修改一下映射文件:
<select id="getRoleByAnnotation" resultType="sysRole">select id, role_name as roleName, notefrom sys_rolewhere role_name like concat('%',#{roleName},'%')and note like concat('%',#{note},'%')
<select/>
  • 此时,不需要再给出传入的参数类型,即不用设置patamterType属性,让MyBatis自动搜索即可。通过注解配置提高了可读性,但是如果SQL语句很复杂,传递的参数很多的时候,那么接口方法要传递的参数也就很多了,使用起来很不方便。此时,我们还可以使用Java Bean的方式传递参数。

2.3.3 使用Java Bean传递参数

  • 定义一个POJO类---RoleParams:
public class RoleParams{private String roleName;private String note;/*setter and getter*/
}
  • 此时,接口方法定义如下:
public interface SysRoleMapper{public List<SysRole> getRoleByJavaBean(RoleParams roleParam);
}
  • 修改映射文件如下:
<select id="getRoleByJavaBean" paramterType="com.learn.ssm.chapter.param.Roleparams"resultType="sysRole">select id, role_name as roleName, notefrom sys_rolewhere role_name like concat('%',#{roleName},'%')and note like concat('%',#{note},'%')
<select/>
  • 修改JavaBean定义的属性作为参数:
SysRoleMapper roleMapper = sqlSession.getMapper(SysRoleMapper.class);
RoleParams roleParams = new RoleParams();
roleParams.setRoleName("1");
roleParams.setNote("1");
List<SysRole> roles = roleMapper.getRoleByJavaBean(roleParams);

2.3.4 使用混合方式传递参数

  • 在某些情况下,可能还需要混合使用几种方法来传递参数,比如查询角色名和备注的同时,还需要支持分页,而分页的POJO实现如下:
public class PageParams{private int start;private int limit;/*setter and getter*/
}
  • 此时,接口设计如下:
public interface SysRoleMapper{public List<SysRole> getRoleByMix(@Param("params") RoleParams roleParams,@Param("page") PageParams pageParams);
}
  • 关于映射文件,则如下修改:
<select id="getRoleByMix" resultType="sysRole">select id, role_name as roleName, notefrom sys_rolewhere role_name like concat('%',#{roleName},'%')and note like concat('%',#{note},'%')limit #{page.start},#{page.limit}
<select/>
  • 这样就能使用混合参数,MyBatis对params和page这类Java Bean参数提供EL(中间语言)支持。

小结:

  • 使用map传递参数导致了业务可读性的丢失,致使后期维护困难,应废弃这种方式;
  • 使用@Param注解传递多个参数,收到参数个数(n)的影响。当n<= 5时,最佳传递方式,比使用Java Bean更好;当n>= 5时,多个参数将给调用带来困难,不推荐;
  • 当参数多于5个时,建议使用JavaBean方式。

 2.4 使用resultMap映射结果集

在复杂的映射配置时,select元素提供了resultMap属性。先定义resultMap属性:

<mapper namespace="com.learn.ssm.chapter.param.Roleparams"><resultMap id="roleMap" type="sysRole"><id property="id" column="id"/><result property="roleName" column="role_name"/><result property="note" column="note"/><resultMap/><select id="getRoleMap" paramterType="long" resultMap="roleMap">select id, role_name, note from sys_rolewhere id=#{id}</select>
</mapper>

分析一下上边的SQL配置:

  • resultMap:定义了一个roleMap,它的属性id代表它的标识,type代表使用哪个类作为其映射类,可以是别名或全限定类名
  • 子元素id:表示resultMap的主键,而result表示其属性,id和result元素的属性property表示POJO类的属性名,而column表示SQL的字段名。把POJO的属性和SQL的列名做对应,就建立起了映射关系
  • select元素中:resultMap指定了采用哪个resultMap作为其映射规则

 2.5 分页参数RowBounds

MyBatis支持分页,内置了一个专门处理分页的类——RowBounds。

RowBounds源码:

poublic class RowBounds{private static final int NO_ROW_OFFSET = 0;private static final int NO_ROW_LIMIT = Integer.MAX_VALUE;private static final RowBounds DEFAULT = new RowBounds();private int offset;private int limit;public RowBounds(){this.offset = NO_ROW_OFFSET;this.limit = NO_ROW_LIMIT;}public RowBounds(int offset, int limit){this.offset = offset;this.limit = limit;}/*setter and getter*/
}
  • offset:偏移量,即从第几行开始读取记录
  • limit:限制条数,默认值0~2147483647

此时,我们需要给接口增加一个rowBounds参数

public interface SysRoleMapper{public List<SysRole> getRoleByRowBounds(@Param("roleName") String roleName,@Param("note") String note, RowBounds rowBounds);
}

配置一下映射文件:

<select id="getRoleByRowBounds" resultType="sysRole">select id, role_name as roleName, notefrom sys_rolewhere role_name like concat('%',#{roleName},'%')and note like concat('%',#{note},'%')
<select/>

看一下配置文件,并没有关于RowBounds参数的任何信息,它是一个附加参数,MyBatis会自动识别,然后进行分页。测试一下接口:

SqlSession sqlsession = null;
try{sqlSession = SqlSessionFactoryUtils.openSqlSession();SysRoleMapper roleMapper = sqlSession.getMapper(SysRoleMapper.class);RowBounds rowBounds = new RowBounds(0, 20);List<SysRole> roleList = roleMapper.getRoleByRowBounds("roleName", "note", "rowBounds");
} catch(Exception e){e.printStackTrace();
} finally{if(sqlSession != null){sqlSession.close();}
}

运行分页就可以限定地查询返回至多20条记录的结果。而这个RowBounds分页只能应用于一些小数据量的查询,原理是执行SQL查询后,按照偏移量和限制条数返回查询结果,所以对于大量的数据查询,性能不佳,可通过分页插件进行处理。

3、insert元素

执行select的基础就是先插入数据,而插入数据依赖于insert语句。相对于select而言,insert语句简单很多。insert语句可以配置以下属性:

            属性                                                               描述 备注
id SQL编号,标识这条SQL 命名空间+id+databaseId唯一,否则抛异常
parameterType 传入参数类型,同select元素 和select一样,可以是单个或多个参数
flushCache 是否刷新缓存,布尔类型;true时,插入数据会刷新一级和二级缓存;false时,不刷新缓存 默认true
statementType 使用哪个JDBC的Statement工作,取值为STATEMENT、PREPARED、CALLABLE 默认PREPARED
useGeneratedKeys 是否启用JDBC的getGeneratedKeys方法来取出由数据库内部生成的主键(如MySQ和SQLServer这样的数据库表的自增主键) 默认false
keyProperty (仅对insert和update有用)唯一标记一个属性,通过generatedKeys的返回值,或通过insert语句的selectKey子元素设置它的键值。如果是复合主键,要把每一个名称用逗号隔开 默认unset,不能和keyColumn一起使用
keyColumen (仅对insert和update有用)通过生成的键值设置表中的列名,这个设置仅在某些数据库中是必须的,当主键列不是表中的第一列时需要设置。如果是复合主键,需要把每一个名称用逗号隔开 不能和keyProperty一起使用

MyBatis在执行一条insert语句后,会返回一个整数表示其影响记录数。

 3.1 简单的insert语句的应用

插入一条角色记录:

<insert id="insertRole" paramterType="sysRole">insert into sys_role(roleName, note)values(#{roleName}, #{note})
<insert/>

分析:

  • id:表示这条SQL,结合命名空间让MyBatis找到它
  • paramterType:表示传入的参数类型
  • 没有配置的属性将采用默认值,这样就完成一个角色记录的插入。

 3.2 主键回填

JDBC的statement对象在执行插入的SQL后,可以通过getGeneratedKeys方法获得数据库生成的主键,这样便能达到获取主键的功能。在insert语句中有个开关属性useGeneratedKeys,用来控制是否打开这个功能,默认值为false。当打开这个开关,还要配置其属性keyPropertykeyColumn,告诉系统把生成的主键放入哪个属性中,如果存在多个主键,就用逗号隔开。

返回主键:

<insert id="insertRole" paramterType="sysRole" useGeneratedKeys="true" keyProperty=id>insert into sys_role(roleName, note)values(#{roleName}, #{note})
<insert/>
  • useGeneratedKeys:表示采用JDBC的Statement对象的getGeneratedKeys方法返回主键
  • keyProperty:表示使用哪个POJO的属性去匹配这个主键,这里是id,说明它会用数据库生成主键去赋值给这个POJO。

 3.3 自定义主键

有时候主键可能依赖于某些规则,比如取消角色表的id递增规则,而将其规则修改为:

  • 角色表记录为空时,id设置为1
  • 角色表记录不为空时,id设置为当前id加3

它依赖于selectKey元素进行支持,允许自定义键值得生成规则:

<insert id="insertRole" paramterType="sysRole"><selectKey keyProperty="id" resultType="java.lang.Integer" order="VEFORE">select if (max(id) = null, 1, max(id) + 3)from sys_role</selectKey>insert into sys_role(id,roleName,note)values(#{id},#{roleName},#{note})
</insert>
  • selectey元素的keyProperty指定了采用哪个属性作为POJO的主键。
  • resultType:指定返回结果集类型
  • order = “BEFORE”:说明它相当于当前定义的SQL前执行【在执行插入之前执行生成主键的SQL,然后插入数据。】。

4、update元素和delete元素

updatedelete的属性差不多,执行完会返回一个整数。所以表示该SQL语句影响了数据库的记录行数

<update id="updateRole" parameterType="sysRole">update sys_role set roleName = #{roleName},note = #{note}where id = #{id}
</update>
<delete id="deleteRole" parameterType="java.lang.Integer">delete from sys_role where id = #{id}
</delete>

5、sql元素

sql元素的作用:定义一条SQL的一部分,便于后面SQL引用。

<mapper namespace="com.learn.ssm.chapter.param.Roleparams"><resultMap id="roleMap" type="sysRole"><id property="id" column="id"/><result property="roleName" column="role_name"/><result property="note" column="note"/><resultMap/><!-- sql元素 --><sql id="roleCols">id, roleName, note</sql><select id="getRoleMap" paramterType="long" resultMap="roleMap">select <include refid="roleCols"/> from sys_rolewhere id=#{id}</select><insert id="insertRole" paramterType="sysRole"><selectKey keyProperty="id" resultType="java.lang.Integer" order="VEFORE">select if (max(id) = null, 1, max(id) + 3)from sys_role</selectKey>insert into sys_role(<include refid="roleCols"/>)values(#{id},#{roleName},#{note})
</insert>
</mapper>

通过sql元素进行定义,就可以通过include元素引入到各条SQL中,减少对其列名的重复编写。

sql元素还支持变量递增:

<sql id="roleCols">${alias}.id,${alias}.roleName,${alias}.note,
</sql>
<select id="getRole" parameterType="java.lang.Integer" resultMap="sysRole">
<include refid="roleCols"><property name="alias" value="r">
</include>from sys_role where id = #{id}
</select>

在include元素中定义了一个命名为alias的变量,其值是SQL中表sys_role的别名,然后sql元素就能够使用这个变量名了。

MyBatis(六)------MyBatis映射器(select元素、insert元素、update元素、select元素、sql元素)相关推荐

  1. MyBatis学习之映射器Mapper(接口映射器+xml映射文件)

    Table of Contents 01 MyBatis映射器: 1.1 接口映射器+xml映射器 1.2 接口映射器+注解 02 接口映射器+xml映射器  方式 2.1 mybatis配置文件 引 ...

  2. 5、mybatis中的映射器

    目录 1.映射器是什么? 2.自定义sql和使用的分类 2.1 根据定义sql的两种方式分类 2.2 根据使用方式分类 mybatis在实际使用时,最主要的还是映射器.这一篇大体介绍一下映射器,但是有 ...

  3. mybatis的select、insert、update、delete语句

    一.select <!-- 查询学生,根据id --> <select id="getStudent" parameterType="String&qu ...

  4. 深入浅出MyBatis:「映射器」全了解

    本篇文章是「深入浅出MyBatis:技术原理与实践」书籍的总结笔记. 上一篇总结了MyBatis的配置,详细说明了各个配置项,其中提到了映射器,它是MyBatis最强大的工具,也是使用最多的工具. 通 ...

  5. 深入浅出Mybatis系列(七)---mapper映射文件配置之insert、update、delete

    2019独角兽企业重金招聘Python工程师标准>>> 上篇文章<深入浅出Mybatis系列(六)---objectFactory.plugins.mappers简介与配置&g ...

  6. mybatis的mapper.xml文件中含有中文注释时运行出错,mybatis配置优化和别名优化 mybatis配置之映射器说明

    记录一个发现的小问题,刚刚在UserMapper.xml文件中有一段中文注释掉的内容: <!-- <resultMap id="Usermap" type=" ...

  7. Maven使用注解配置SQL映射器(@Select,@Insert,@Update,@Delete)

    工程目录: Client.java package client;import java.io.*; import java.util.List; import org.apache.ibatis.i ...

  8. Oracle中5个核心Sql语句的基本构造:Select、Insert、Update、Delete和Merge

    Sql语言提供了很多不同的选择来得到同样的结果集,关键是需要搞清楚在不同的使用场景下哪种构造是最高效的. 1.Select语句 Select语句用来从一个表中,或者其他数据库对象中提取数据. sele ...

  9. 【Java EE】映射器

    映射器 映射器是MyBatis最复杂且最重要得组件,它由一个接口加上XML文件(或者注解)组成.在映射器中可以配置参数.各类的SQL语句.存储过程.缓存.级联等复杂的内容,并且通过简易的映射规则映射到 ...

  10. 深入理解MyBatis的原理(四):映射器的用法

    前言:继续深入学习 mybatis 的用法及原理,还是先会用再学习原理. 映射器的主要元素有:select.insert.update.delete.parameterMap(即将被删除,不建议使用) ...

最新文章

  1. 将web项目deploy到tomcat的方法
  2. GDCM:gdcm::Base64的测试程序
  3. 【OpenCV 例程200篇】70. 一维连续函数的傅里叶变换
  4. 陕师大计算机科学学院研究生,陕师大研究生
  5. Altium AD20修改原理图右下角标题栏,自定义标题栏,添加图片、标题、页码、时间、作者
  6. 15种排序算法可视化展示
  7. matlab求均值、方差
  8. Modern UI for WPF 初接触
  9. 字符处理——大写转小写、小写转大写
  10. esp32-Arduino开发学习
  11. 仙剑奇侠传编年史(转自网络)
  12. Latex改变页边距
  13. Raft 共识算法1-Raft基础
  14. 数字孪生三维铁路管理系统方案
  15. python爱情动画_人生苦短,我用Python-从Houdini里导出RBD解算的Skin动画
  16. 美国推进隐私保护立法 加剧全球网络空间治理复杂性
  17. Airship起航,1.0发布
  18. 基于visual的单机游戏外挂
  19. 使用nudge4j从浏览器进入JVM
  20. 碎片化时间如何利用才最高效?

热门文章

  1. 分页加载总页数计算公式
  2. List集合之ArrayList
  3. Spring源码之BeanDefinitionRegistryPostProcessor内部执行流程
  4. 一个出色的UI设计师需要具备哪些能力?
  5. 从开发到发布一款基于Vue2x的图片预览插件
  6. 控制Arduino的利器-Windows Remote Arduino
  7. 在linux本地下载ftp中的文件
  8. Java线程并发与安全性问题详解
  9. android HandlerThread源码解析
  10. Luogu5889 跳树