Mybatis (三) Mybatis映射文件

Mybatis映射文件

基本CRUD

增长

<select id="saveRole" resultType="role">
  insert into tb_role
  (
  <trim suffixOverrides=",">
    <if test="roleName!=null">
      role_name,
    </if>
    <if test="description != null">
      description,
    </if>
    <if test="status != null">
      status,
    </if>
    <if test="createTime != null">
      create_time,
    </if>
    <if test="createUser != null">
      create_user,
    </if>
    <if test="modifyTime != null">
      modify_time,
    </if>
    <if test="modifyUser != null">
      modify_user
    </if>
  </trim>
  ) VALUES
  (
  <trim suffixOverrides=",">
    <if test="roleName!=null">
      #{roleName},
    </if>
    <if test="description != null">
      #{description},
    </if>
    <if test="status != null">
      #{status},
    </if>
    <if test="createTime != null">
      #{createTime},
    </if>
    <if test="createUser != null">
      #{createUser},
    </if>
    <if test="modifyTime != null">
      #{modifyTime},
    </if>
    <if test="modifyUser != null">
      #{modifyUser}
    </if>
  </trim>
  )
</select>

这个增长方法使用if 进行判断,因此只是将不为空的字段添加。java

增长并返回ID

<!--设置保存的时候须要返回插入时的id-->
<insert id="saveUser" useGeneratedKeys="true" keyProperty="id" parameterType="User" >
    insert into tb_user (user_id,
        username,password,email,phone,gender,birthday,create_time,
        create_user,modify_time,modify_user)
    values (
        #{user.userId},#{user.username},#{user.password},#{user.email},#{user.phone},#{user.gender},
        #{user.birthday},#{user.createTime},#{user.createUser},#{user.modifyTime},#{user.modifyUser})
</insert>

删除

<delete id="deleteRoleById">
  delete from tb_role where id = #{id}
</delete>

这是一个很是简单的删除语句,这里不赘述。git

更新

<update id="updateRole">
  update tb_role
  <set>
    <if test="roleName!=null">
      role_name = #{roleName},
    </if>
    <if test="description != null">
      description = #{description},
    </if>
    <if test="status != null">
      status = #{status},
    </if>
    <if test="createTime != null">
      create_time = #{createTime},
    </if>
    <if test="createUser != null">
      create_user = #{createUser},
    </if>
    <if test="modifyTime != null">
      modify_time = #{modifyTime},
    </if>
    <if test="modifyUser != null">
      modify_user = #{modifyUser}
    </if>
  </set>
  where id = #{id}
</update>

提示:这里采用了选择性更新,即只有字段不为空的时候,才会进行更新操做。sql

查询

<select id="selectRolesByStatus" resultType="role">
  select * from tb_role where status = #{status}
</select>

提示:这里仅仅介绍一下最简单的查询,后面重点介绍与查询相关的。数据库

增删改查标签相关属性请参考:编程

https://mybatis.org/mybatis-3/zh/sqlmap-xml.html#insert_update_and_deletejson

增删改查标签属性

Select 元素的属性

属性 描述
id 在命名空间中惟一的标识符,能够被用来引用这条语句。
parameterType 将会传入这条语句的参数类的彻底限定名或别名。这个属性是可选的,由于 MyBatis 能够经过类型处理器(TypeHandler) 推断出具体传入语句的参数,默认值为未设置(unset)。
resultType 从这条语句中返回的指望类型的类的彻底限定名或别名。 注意若是返回的是集合,那应该设置为集合包含的类型,而不是集合自己。可使用 resultType 或 resultMap,但不能同时使用。
resultMap 外部 resultMap 的命名引用。结果集的映射是 MyBatis 最强大的特性,若是你对其理解透彻,许多复杂映射的情形都能迎刃而解。可使用 resultMap 或 resultType,但不能同时使用。
flushCache 将其设置为 true 后,只要语句被调用,都会致使本地缓存和二级缓存被清空,默认值:false。
useCache 将其设置为 true 后,将会致使本条语句的结果被二级缓存缓存起来,默认值:对 select 元素为 true。
timeout 这个设置是在抛出异常以前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖驱动)。
fetchSize 这是一个给驱动的提示,尝试让驱动程序每次批量返回的结果行数和这个设置值相等。 默认值为未设置(unset)(依赖驱动)。
statementType STATEMENT,PREPARED 或 CALLABLE 中的一个。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。
resultSetType FORWARD_ONLY,SCROLL_SENSITIVE, SCROLL_INSENSITIVE 或 DEFAULT(等价于 unset) 中的一个,默认值为 unset (依赖驱动)。
databaseId 若是配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载全部的不带 databaseId 或匹配当前 databaseId 的语句;若是带或者不带的语句都有,则不带的会被忽略。
resultOrdered 这个设置仅针对嵌套结果 select 语句适用:若是为 true,就是假设包含了嵌套结果集或是分组,这样的话当返回一个主结果行的时候,就不会发生有对前面结果集的引用的状况。 这就使得在获取嵌套的结果集的时候不至于致使内存不够用。默认值:false。
resultSets 这个设置仅对多结果集的状况适用。它将列出语句执行后返回的结果集并给每一个结果集一个名称,名称是逗号分隔的。

Insert, Update, Delete 元素的属性

属性 描述
id 命名空间中的惟一标识符,可被用来表明这条语句。
parameterType 将要传入语句的参数的彻底限定类名或别名。这个属性是可选的,由于 MyBatis 能够经过类型处理器推断出具体传入语句的参数,默认值为未设置(unset)。
parameterMap 这是引用外部 parameterMap 的已经被废弃的方法。请使用内联参数映射和 parameterType 属性。
flushCache 将其设置为 true 后,只要语句被调用,都会致使本地缓存和二级缓存被清空,默认值:true(对于 insert、update 和 delete 语句)。
timeout 这个设置是在抛出异常以前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖驱动)。
statementType STATEMENT,PREPARED 或 CALLABLE 的一个。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。
useGeneratedKeys (仅对 insert 和 update 有用)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(好比:像 MySQL 和 SQL Server 这样的关系数据库管理系统的自动递增字段),默认值:false。
keyProperty (仅对 insert 和 update 有用)惟一标记一个属性,MyBatis 会经过 getGeneratedKeys 的返回值或者经过 insert 语句的 selectKey 子元素设置它的键值,默认值:未设置(unset)。若是但愿获得多个生成的列,也能够是逗号分隔的属性名称列表。
keyColumn (仅对 insert 和 update 有用)经过生成的键值设置表中的列名,这个设置仅在某些数据库(像 PostgreSQL)是必须的,当主键列不是表中的第一列的时候须要设置。若是但愿使用多个生成的列,也能够设置为逗号分隔的属性名称列表。
databaseId 若是配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载全部的不带 databaseId 或匹配当前 databaseId 的语句;若是带或者不带的语句都有,则不带的会被忽略。

结果映射

结果映射(resultMap)

  • constructor - 用于在实例化类时,注入结果到构造方法中idArg - ID 参数;标记出做为 ID 的结果能够帮助提升总体性能arg - 将被注入到构造方法的一个普通结果
  • id – 一个 ID 结果;标记出做为 ID 的结果能够帮助提升总体性能
  • result – 注入到字段或 JavaBean 属性的普通结果
  • association – 一个复杂类型的关联;许多结果将包装成这种类型嵌套结果映射 – 关联自己能够是一个 resultMap 元素,或者从别处引用一个
  • collection – 一个复杂类型的集合嵌套结果映射 – 集合自己能够是一个 resultMap 元素,或者从别处引用一个
  • discriminator – 使用结果值来决定使用哪一个 resultMapcase – 基于某些值的结果映射嵌套结果映射 – case 自己能够是一个 resultMap 元素,所以能够具备相同的结构和元素,或者从别处引用一个

Id 和 Result 的属性

属性 描述
property 映射到列结果的字段或属性。若是用来匹配的 JavaBean 存在给定名字的属性,那么它将会被使用。不然 MyBatis 将会寻找给定名称的字段。 不管是哪种情形,你均可以使用一般的点式分隔形式进行复杂属性导航。 好比,你能够这样映射一些简单的东西:“username”,或者映射到一些复杂的东西上:“address.street.number”。
column 数据库中的列名,或者是列的别名。通常状况下,这和传递给 resultSet.getString(columnName) 方法的参数同样。
javaType 一个 Java 类的彻底限定名,或一个类型别名(关于内置的类型别名,能够参考上面的表格)。 若是你映射到一个 JavaBean,MyBatis 一般能够推断类型。然而,若是你映射到的是 HashMap,那么你应该明确地指定 javaType 来保证行为与指望的相一致。
jdbcType JDBC 类型,所支持的 JDBC 类型参见这个表格以后的“支持的 JDBC 类型”。 只须要在可能执行插入、更新和删除的且容许空值的列上指定 JDBC 类型。这是 JDBC 的要求而非 MyBatis 的要求。若是你直接面向 JDBC 编程,你须要对可能存在空值的列指定这个类型。
typeHandler 咱们在前面讨论过默认的类型处理器。使用这个属性,你能够覆盖默认的类型处理器。 这个属性值是一个类型处理器实现类的彻底限定名,或者是类型别名。

支持的 JDBC 类型

为了之后可能的使用场景,MyBatis 经过内置的 jdbcType 枚举类型支持下面的 JDBC 类型。缓存

BIT FLOAT CHAR TIMESTAMP OTHER UNDEFINED
TINYINT REAL VARCHAR BINARY BLOB NVARCHAR
SMALLINT DOUBLE LONGVARCHAR VARBINARY CLOB NCHAR
INTEGER NUMERIC DATE LONGVARBINARY BOOLEAN NCLOB
BIGINT DECIMAL TIME NULL CURSOR ARRAY

单表基本结果映射

属性设值

<resultMap id="base_map" type="role">
  <id column="id" jdbcType="INTEGER" property="id" />
  <result column="role_name" jdbcType="VARCHAR" property="roleName"/>
  <result column="description" jdbcType="VARCHAR" property="description"/>
  <result column="status" jdbcType="INTEGER" property="status"/>
  <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
  <result column="create_user" jdbcType="VARCHAR" property="createUser"/>
  <result column="modify_time" jdbcType="TIMESTAMP" property="modifyTime"/>
  <result column="modify_user" jdbcType="VARCHAR" property="modifyUser"/>
</resultMap>

<select id="selectAllRoles" resultMap="base_map">
  select * from tb_role
</select>

java实体:mybatis

//空参数,全参数,get,set,toString
public class Role implements Serializable {

    private Integer id;
    private String roleName;
    private String description;
    private Integer status;
    private Date createTime;
    private String createUser;
    private Date modifyTime;
    private String modifyUser;
}

提示:能够看出,这里咱们再也不直接使用了user做为返回类型(resultType),而是使用告终果映射(resultMap)来映射实体。以上方式使用的实体映射是使用的setter进行设置参数的。咱们在setId方法上加一段输入语句以后,再次运行,结果以下:app

public void setId(Integer id) {
  System.out.println("setId of role is running");
  this.id = id;
}

那么咱们如何使用构造函数来进行属性设置赋值呢?

<resultMap id="base_map" type="role">
  <constructor>
    <idArg column="id" javaType="Integer"/>
    <arg column="role_name" javaType="String"/>
    <arg column="description" javaType="String"/>
    <arg column="status" javaType="Integer"/>
    <arg column="create_time" javaType="Date"/>
    <arg column="create_user" javaType="String"/>
    <arg column="modify_time" javaType="Date" />
    <arg column="modify_user" javaType="String" />
  </constructor>
</resultMap>

构造方法设值

public Role(Integer id, String roleName, String description, Integer status, Date createTime, String createUser, Date modifyTime, String modifyUser) {
  System.out.println("all args' constructor of role is running ");
  this.id = id;
  this.roleName = roleName;
  this.description = description;
  this.status = status;
  this.createTime = createTime;
  this.createUser = createUser;
  this.modifyTime = modifyTime;
  this.modifyUser = modifyUser;
}

测试结果:

关联关系一对一

​ 前面咱们看到了单表操做,咱们经过直接返回对象或是使用resultMap的方式来映射实体。这里咱们看一下实体一对一的关系如何映射。

一对一关系的映射:association标签的属性元素

property CDATA              属性,必须
column CDATA                数据库表的字段名
javaType CDATA              属性的java类型
jdbcType CDATA              数据库表的字段的类型
select CDATA                嵌套查询时使用。
resultMap CDATA             关联外部的手动映射关系时使用
typeHandler CDATA           类型处理器
notNullColumn CDATA     
columnPrefix CDATA          字段前缀,一对一中有涉及到
resultSet CDATA         
foreignColumn CDATA     
autoMapping (true|false)    是否自定映射
fetchType (lazy|eager)      是否懒加载

业务:用户与身份证是一对一的关系。

User类:

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
public class User implements Serializable {

    private Integer id;
    private String userId;
    private String username;
    private String password;
    private String email;
    private String phone;
    private Integer gender;
    private Date birthday;
    private Integer status;
    private Date createTime;
    private String createUser;
    private Date modifyTime;
    private String modifyUser;
    private Card card;
}

提示:这里使用了lombok 简化实例开发,依赖以下:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.8</version>
</dependency>

Card类:

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
public class Card implements Serializable {

    private Integer id;
    private Integer uid;
    private String cardId;
    private String address;
    private Date createTime;
    private Date modifyTime;
}

一对一自动映射

​ 经过上面的实例类关系咱们能够发现,card是User类中的一个属性,可是如何经过Mybatis的自动映射机制将card表中的数据之间填充到User属性中。咱们能够在查询字段上使用别名来映射,以下,uid字段是user的card属性的属性,则能够经过card.uid 来映射到User类的card属性的uid字段。

<select id="findUserWithCardByUserId" resultType="user">
    SELECT
      a.id,a.user_id,a.username,a.password,a.email,a.phone,
      a.gender,a.birthday,a.status,a.create_time,a.create_user,
      a.modify_time,a.modify_user,
      b.id as "card.id" ,
      b.uid as "card.uid",
      b.card_id as "card.cardId",
      b.address as "card.address",
      b.create_time as "card.createTime" ,
      b.modify_time as "card.modifyTime"
    FROM
        tb_user a
    INNER JOIN tb_card b on a.id = b.uid where a.id = #{id};
</select>

一对一手动映射

手动映射就是经过结果集的方式列进行映射,以下:

<resultMap id="BaseResultMapWithCard" type="user">
    <id column="id" jdbcType="INTEGER" property="id"/>
    <result column="user_id" jdbcType="VARCHAR" property="userId"/>
    <result column="username" jdbcType="VARCHAR" property="username"/>
    <result column="password" jdbcType="VARCHAR" property="password"/>
    <result column="email" jdbcType="VARCHAR" property="email"/>
    <result column="phone" jdbcType="VARCHAR" property="phone"/>
    <result column="gender" jdbcType="INTEGER" property="gender"/>
    <result column="birthday" jdbcType="DATE" property="birthday"/>
    <result column="status" jdbcType="INTEGER" property="status"/>
    <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
    <result column="create_user" jdbcType="VARCHAR" property="createUser"/>
    <result column="modify_time" jdbcType="TIMESTAMP" property="modifyTime"/>
    <result column="modify_user" jdbcType="VARCHAR" property="modifyUser"/>
    <association property="card" javaType="card">
        <id column="bid" jdbcType="INTEGER" property="id"/>
        <result column="uid" jdbcType="INTEGER" property="uid"/>
        <result column="card_id" jdbcType="VARCHAR" property="cardId"/>
        <result column="address" jdbcType="VARCHAR" property="address"/>
        <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
        <result column="modify_time" jdbcType="TIMESTAMP" property="modifyTime"/>
    </association>
</resultMap>


<select id="findUserWithCardByUserId" resultMap="BaseResultMapWithCard">
        select
            a.id,a.user_id,a.username,a.password,a.email,a.phone,a.gender,
            a.birthday,a.status,a.create_time,a.create_user,a.modify_time,a.modify_user,
            b.id bid,
            b.uid,
            b.card_id,
            b.address,
            b.create_time,
            b.modify_time
        FROM
            tb_user a
        INNER JOIN tb_card b on a.id = b.uid where a.id = #{id}
</select>

经过上述的SQL查询和结果集的手动映射关系,这样就能够实现字段和实体的查询了。

固然,Mybatis还提供下面这种方式来实现:

<resultMap id="BaseResultMapWithCard" type="user">
    <id column="id" jdbcType="INTEGER" property="id"/>
    <result column="user_id" jdbcType="VARCHAR" property="userId"/>
    <result column="username" jdbcType="VARCHAR" property="username"/>
    <result column="password" jdbcType="VARCHAR" property="password"/>
    <result column="email" jdbcType="VARCHAR" property="email"/>
    <result column="phone" jdbcType="VARCHAR" property="phone"/>
    <result column="gender" jdbcType="INTEGER" property="gender"/>
    <result column="birthday" jdbcType="DATE" property="birthday"/>
    <result column="status" jdbcType="INTEGER" property="status"/>
    <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
    <result column="create_user" jdbcType="VARCHAR" property="createUser"/>
    <result column="modify_time" jdbcType="TIMESTAMP" property="modifyTime"/>
    <result column="modify_user" jdbcType="VARCHAR" property="modifyUser"/>
    <association property="card" javaType="card" column="id" select="selectCard"></association>
</resultMap>

<select id="findUserWithCardByUserId" resultMap="BaseResultMapWithCard">
    select
      a.id,a.user_id,a.username,a.password,a.email,a.phone,a.gender,
      a.birthday,a.status,a.create_time,a.create_user,a.modify_time,a.modify_user
    FROM
        tb_user a
    where a.id = #{id}
</select>

<select id="selectCard" resultType="card">
    select * from tb_card where uid = #{id}
</select>

这样的操做其实就是先查询出User的信息,而后在取user表的id字段来查询card表的数据,这样就至关于向MySQL发送了两条SQL,咱们经过日志能够观察到现象:

​ 两种方式均可以实现一样地结果,若是须要控制SQL发送条数的话,可使用关联方式,若是须要在必定程度上下降SQL的查询时间,则能够将其拆分为多个查询SQL。

拓展:

下面咱们看一下下面这个SQL如何进行映射,咱们假设,一个User有一个主身份证和一个副身份证,那么咱们须要如何查询映射:

User:

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
public class User implements Serializable {

    private Integer id;
    private String userId;
    private String username;
    private String password;
    private String email;
    private String phone;
    private Integer gender;
    private Date birthday;
    private Integer status;
    private Date createTime;
    private String createUser;
    private Date modifyTime;
    private String modifyUser;

    private Card card;//主
    private Card card1;//副
}

对应的SQL映射以下:

<resultMap id="BaseResultMapWithCard" type="user">
    <id column="id" jdbcType="INTEGER" property="id"/>
    <result column="user_id" jdbcType="VARCHAR" property="userId"/>
    <result column="username" jdbcType="VARCHAR" property="username"/>
    <result column="password" jdbcType="VARCHAR" property="password"/>
    <result column="email" jdbcType="VARCHAR" property="email"/>
    <result column="phone" jdbcType="VARCHAR" property="phone"/>
    <result column="gender" jdbcType="INTEGER" property="gender"/>
    <result column="birthday" jdbcType="DATE" property="birthday"/>
    <result column="status" jdbcType="INTEGER" property="status"/>
    <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
    <result column="create_user" jdbcType="VARCHAR" property="createUser"/>
    <result column="modify_time" jdbcType="TIMESTAMP" property="modifyTime"/>
    <result column="modify_user" jdbcType="VARCHAR" property="modifyUser"/>
    <association property="card" javaType="card" resultMap="cardResultMap" columnPrefix="b1_" />
    <association property="card1" javaType="card" resultMap="cardResultMap" columnPrefix="b2_" />
</resultMap>

<resultMap id="cardResultMap" type="card">
    <id column="id" jdbcType="INTEGER" property="id"/>
    <result column="uid" jdbcType="INTEGER" property="uid"/>
    <result column="card_id" jdbcType="VARCHAR" property="cardId"/>
    <result column="address" jdbcType="VARCHAR" property="address"/>
    <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
    <result column="modify_time" jdbcType="TIMESTAMP" property="modifyTime"/>
</resultMap>


<select id="findUserWithCardByUserId" resultMap="BaseResultMapWithCard" >
    select
      a.id,a.user_id,a.username,a.password,a.email,a.phone,a.gender,
      a.birthday,a.status,a.create_time,a.create_user,a.modify_time,a.modify_user,
      b1.id b1_id,
      b1.uid b1_uid,
      b1.card_id b1_card_id,
      b1.address b1_address,
      b1.create_time b1_create_time,
      b1.modify_time b1_modify_time,
      b2.id b2_id,
      b2.uid b2_uid,
      b2.card_id b2_card_id,
      b2.address b2_address,
      b2.create_time b2_create_time,
      b2.modify_time b2_modify_time
    from tb_user a
    inner join tb_card b1 on a.id = b1.uid
    inner join tb_card b2 on a.id = b2.uid
    where a.id = 1
</select>

​ 当链接多个表时,咱们可能会不得不使用列别名来避免在 ResultSet 中产生重复的列名。指定 association标签的columnPrefix 列名前缀容许你将带有这些前缀的列映射到一个外部的结果映射中。

关联关系一对多

// 下面是collection标签的各个属性元素

property CDATA #REQUIRED    必须,指定的是java实体类的属性名
column CDATA                指定的是表的字段名(查询出来的,有多是字段别名)
javaType CDATA              集合通常不使用这个
ofType CDATA                属性的java类型,例如:string,integer
jdbcType CDATA              数据库的字段类型
select CDATA                当咱们须要进行嵌套查询的时候,执行另一个查询语句
resultMap CDATA             返回值的映射关
typeHandler CDATA           类型处理
notNullColumn CDATA         
columnPrefix CDATA          当咱们须要进行区分的时候,能够指定前缀,后面有案例
resultSet CDATA             
foreignColumn CDATA         外键
autoMapping (true|false)    是否须要自动映射
fetchType (lazy|eager)      是否进行懒加载

​ 在实际开发中,权限每每是无关业务,可是又是相当重要的一环。在设计权限的时候,咱们每每不会讲权限之间与用户以前关联,为了更加好的管理,咱们会在用户与权限之间引入一个角色,用角色来统一管理具备相同权限的用户,通常一个用户存在于多个角色,好比即便CEO又是系统开发人员(哈哈),这里就是一个一对多的关系,下面咱们看看,在Mybatis中一对多的关系如何映射:

User:

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
public class User implements Serializable {

    private Integer id;
    private String userId;
    private String username;
    private String password;
    private String email;
    private String phone;
    private Integer gender;
    private Date birthday;
    private Integer status;
    private Date createTime;
    private String createUser;
    private Date modifyTime;
    private String modifyUser;
    private List<Role> roles;
}

Role:

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
public class Role implements Serializable {

    private Integer id;
    private String roleName;
    private String description;
    private Integer status;
    private Date createTime;
    private String createUser;
    private Date modifyTime;
    private String modifyUser;
}

根据id查询的SQLxml文件:

这里与前面的一对多的关联关系有所不一样 ,一对多关联关系使用的是association,java类型使用的是javaType。而多对多关联关系使用的标签是collection,java类型属性使用的是ofType。

<resultMap id="BaseResultWithRole" type="com.ooyhao.mybatis.bean.User">
    <id column="id" jdbcType="INTEGER" property="id"/>
    <result column="user_id" jdbcType="VARCHAR" property="userId"/>
    <result column="username" jdbcType="VARCHAR" property="username"/>
    <result column="password" jdbcType="VARCHAR" property="password"/>
    <result column="email" jdbcType="VARCHAR" property="email"/>
    <result column="phone" jdbcType="VARCHAR" property="phone"/>
    <result column="gender" jdbcType="INTEGER" property="gender"/>
    <result column="birthday" jdbcType="DATE" property="birthday"/>
    <result column="status" jdbcType="INTEGER" property="status"/>
    <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
    <result column="create_user" jdbcType="VARCHAR" property="createUser"/>
    <result column="modify_time" jdbcType="TIMESTAMP" property="modifyTime"/>
    <result column="modify_user" jdbcType="VARCHAR" property="modifyUser"/>
    <collection property="roles" ofType="role">
        <id column="cid" jdbcType="INTEGER" property="id"/>
        <result column="role_name" jdbcType="VARCHAR" property="roleName"/>
        <result column="description" jdbcType="VARCHAR" property="description"/>
        <result column="status" jdbcType="INTEGER" property="status"/>
        <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
        <result column="create_user" jdbcType="VARCHAR" property="createUser"/>
        <result column="modify_time" jdbcType="TIMESTAMP" property="modifyTime"/>
        <result column="modify_user" jdbcType="VARCHAR" property="modifyUser"/>
    </collection>
</resultMap>


<select id="findUserWithRolesByUserId" resultMap="BaseResultWithRole">
    select
      a.id,a.user_id,a.username,a.password,a.email,a.phone,a.gender,
      a.birthday,a.status,a.create_time,a.create_user,a.modify_time,a.create_user,
      c.id cid,
      c.role_name,
      c.description,
      c.status,
      c.create_time,
      c.create_user,
      c.modify_time,
      c.create_user
    from tb_user a
    left join tb_user_role b on a.id = b.user_id
    left join tb_role c on c.id = b.role_id
    where a.id = #{id}
</select>

测试结果以下:

{
    "birthday": 1551369600000,
    "createTime": 1551433926000,
    "createUser": "admin",
    "email": "12345678@qq.com",
    "gender": 1,
    "id": 1,
    "modifyTime": 1551679675000,
    "password": "admin123456789",
    "phone": "12345678901",
    "roles": [{
        "createTime": 1551433926000,
        "createUser": "admin",
        "description": "超级管理员",
        "id": 1,
        "modifyTime": 1551679675000,
        "roleName": "admin",
        "status": 0
    }, {
        "createTime": 1551433926000,
        "createUser": "admin",
        "description": "开发人员",
        "id": 2,
        "modifyTime": 1551679675000,
        "roleName": "develop",
        "status": 0
    }],
    "status": 0,
    "userId": "oms20190001",
    "username": "admin"
}

除了上述方式进行关联查询,咱们还能够将SQL进行拆分:

关联嵌套查询:

<resultMap id="BaseResultWithRole" type="com.ooyhao.mybatis.bean.User">
    <id column="id" jdbcType="INTEGER" property="id"/>
    <result column="user_id" jdbcType="VARCHAR" property="userId"/>
    <result column="username" jdbcType="VARCHAR" property="username"/>
    <result column="password" jdbcType="VARCHAR" property="password"/>
    <result column="email" jdbcType="VARCHAR" property="email"/>
    <result column="phone" jdbcType="VARCHAR" property="phone"/>
    <result column="gender" jdbcType="INTEGER" property="gender"/>
    <result column="birthday" jdbcType="DATE" property="birthday"/>
    <result column="status" jdbcType="INTEGER" property="status"/>
    <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
    <result column="create_user" jdbcType="VARCHAR" property="createUser"/>
    <result column="modify_time" jdbcType="TIMESTAMP" property="modifyTime"/>
    <result column="modify_user" jdbcType="VARCHAR" property="modifyUser"/>
    <collection property="roles" ofType="role"  column="id"  select="selectRole" />
</resultMap>

<resultMap id="selectRole" type="role">
    <id column="cid" jdbcType="INTEGER" property="id"/>
    <result column="role_name" jdbcType="VARCHAR" property="roleName"/>
    <result column="description" jdbcType="VARCHAR" property="description"/>
    <result column="status" jdbcType="INTEGER" property="status"/>
    <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
    <result column="create_user" jdbcType="VARCHAR" property="createUser"/>
    <result column="modify_time" jdbcType="TIMESTAMP" property="modifyTime"/>
    <result column="modify_user" jdbcType="VARCHAR" property="modifyUser"/>
</resultMap>


<select id="findUserWithRolesByUserId" resultMap="BaseResultWithRole">
    select
      a.id,a.user_id,a.username,a.password,a.email,a.phone,a.gender,
      a.birthday,a.status,a.create_time,a.create_user,a.modify_time,a.create_user
    from tb_user a
    where a.id = #{id}
</select>


<select id="selectRole" resultType="role" >
    select b.* from tb_user_role a
    left join tb_role b on a.role_id = b.id
    where a.user_id = #{id}
</select>

注:多对多其实就是双向的一对多关系,再也不赘述。

鉴别器

摘自官网:

有时候,一个数据库查询可能会返回多个不一样的结果集(但整体上仍是有必定的联系的)。 鉴别器(discriminator)元素就是被设计来应对这种状况的,另外也能处理其它状况,例如类的继承层次结构。 鉴别器的概念很好理解——它很像 Java 语言中的 switch 语句。

一个鉴别器的定义须要指定 column 和 javaType 属性。column 指定了 MyBatis 查询被比较值的地方。 而 javaType 用来确保使用正确的相等测试(虽然不少状况下字符串的相等测试均可以工做)。例如:

<resultMap id="vehicleResult" type="Vehicle">
  <id property="id" column="id" />
  <result property="vin" column="vin"/>
  <result property="year" column="year"/>
  <result property="make" column="make"/>
  <result property="model" column="model"/>
  <result property="color" column="color"/>
  <discriminator javaType="int" column="vehicle_type">
    <case value="1" resultMap="carResult"/>
    <case value="2" resultMap="truckResult"/>
    <case value="3" resultMap="vanResult"/>
    <case value="4" resultMap="suvResult"/>
  </discriminator>
</resultMap>
---------------------------------------也能够这样-----------------------------------------

<resultMap id="vehicleResult" type="Vehicle">
  <id property="id" column="id" />
  <result property="vin" column="vin"/>
  <result property="year" column="year"/>
  <result property="make" column="make"/>
  <result property="model" column="model"/>
  <result property="color" column="color"/>
  <discriminator javaType="int" column="vehicle_type">
    <case value="1" resultType="carResult">
      <result property="doorCount" column="door_count" />
    </case>
    <case value="2" resultType="truckResult">
      <result property="boxSize" column="box_size" />
      <result property="extendedCab" column="extended_cab" />
    </case>
    <case value="3" resultType="vanResult">
      <result property="powerSlidingDoor" column="power_sliding_door" />
    </case>
    <case value="4" resultType="suvResult">
      <result property="allWheelDrive" column="all_wheel_drive" />
    </case>
  </discriminator>
</resultMap>

提示:请注意,这些都是结果映射,若是你彻底不设置任何的 result 元素,MyBatis 将为你自动匹配列和属性。因此上面的例子大多都要比实际的更复杂。 这也代表,大多数数据库的复杂度都比较高,咱们不太可能一直依赖于这种机制。

下面经过一个案例来使用一下鉴别器:

数据以下:

咱们经过接口的方式来使用鉴别器建立不一样的交通工具实体:

public interface Vehicle {}

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
public class Bus implements Vehicle {
    private Integer id;
    private String name;
}

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
public class Car implements Vehicle{

    private Integer id;
    private String name;
}

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
public class Subway implements Vehicle {
    
    private Integer id;
    private String name;
}

Sql.xml文件:

<resultMap id="BaseResultMap" type="com.ooyhao.mybatis.bean.Vehicle">
    <id column="id" jdbcType="INTEGER" property="id"/>
    <discriminator javaType="INTEGER" jdbcType="INTEGER" column="vehicle_type" >
        <case value="1" resultType="car">
             <result property="name" column="vehicle_name" jdbcType="VARCHAR" />
        </case>
        <case value="2" resultType="bus">
             <result property="name" column="vehicle_name" jdbcType="VARCHAR"/>
        </case>
        <case value="3" resultType="subway">
              <result property="name" column="vehicle_name" jdbcType="VARCHAR"/>
        </case>
    </discriminator>
</resultMap>

<select id="findVehicleById" resultMap="BaseResultMap">
    select * from tb_vehicle where id = #{id}
</select>

在case之外的,就至关于在每个case中都会存在,而在case中的则是根据条件来选择的。

id为1时:

id为3时:

源码地址:

https://gitee.com/ooyhao/JavaRepo_Public/tree/master/Mybatis

最后

若是以为不错的话,那就关注一下小编哦!一块儿交流,一块儿学习

相关文章
相关标签/搜索