mybatis中最强大得元素 resultMap

resultMap 元素是 MyBatis 中最重要最强大的元素…ResultMap
的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了”
—— MyBatis 官方文档

一、 resultmap是mybatis中最复杂的元素之一它描述如何从结果集中加载对象,主要作用是定义映射规则、级联更新、定制类型转化器。

元素子元素作用
constructoridArg、arg用于配置构造器方法
id将结果集标记为id,以方便全局调用
result配置pojo到数据库列名映射关系
association级联使用代表一对一关系
collection级联使用代表一对多关系
discriminator级联使用鉴别器,根据实际选择实例,可以通过特定条件确定结果集

1、其中id、result是最简单的映射,id为主键映射;result为其他基本数据库表字段到实体类属性的映射,语句属性配置细节:

属性描述
property需要映射到javabean的属性名称。
id数据表的列名或者标签别名。
javaType一个完整的类名,或者是要给类型别名。如果你匹配的是一个JavaBean,那么MyBatis通常会自行检测到。然后,如果你是要映射到一个HashMap,那么需要指定javaType要达到的目的。
jdbcType数据表支持的类型列表。这个属性只在insert、update、或delete的时候针对允许为空的列有用。jdbc需要这项,但mybaits不需要。如果是针对jdbc编码,且允许有空的列,需要指定这项。
typeHandler使用这个属性可以覆写类型处理器。这项值可以是一个完整的类名,也可以是一个类型别名。

此时resultmap的xml如下:

<resultMap type="User" id="userMap">
    <id property="UserId" column="user_id" javaType="int" jdbcType="int"/>
    <result property="name" column="name" javaType="String" jdbcType="VARCHAR"/>
</resultMap>

2、一个 resultMap 中常用的写法

<resultMap id="唯一标识" type="映射的entity对象的绝对路径">
    <id column="表主键字段" jdbcType="字段类型" property="映射entity对象的主键属性" />
 
    <result column="表某个字段(要注意这个column的值,对应的其实是指实际查询出来的字段,所以如果取了别名要写别名)" jdbcType="字段类型" property="映射entity对象的某个属性"/>
 
    <!-- 指的是entity对象中的对象属性(一般一对一关联查询时使用) -->
    <association property="entity中某个对象属性" javaType="这个对象的绝对路径">
        <id column="这个对象属性对应的表的主键字段" jdbcType="字段类型" property="这个对象属性内的主键属性"/>
        <result column="表某个字段(要注意这个column的值,对应的其实是指实际查询出来的字段,所以如果取了别名要写别名)" jdbcType="字段类型" property="这个对象属性内的某个属性"/>
    </association>
    
    <!-- 指的是entity对象中的对象属性(通过单独sql查询时使用,一对一级联) -->
    <association property="entity中某个对象属性" column="将这边查询到的字段作为参数传递到新的sql,如id、name等(这里直接填字段名)" select="新的查询sql方法路径,取到方法名"/>
 
    <!-- 指的是entity对象中的集合属性(一般一对多关联查询时使用) -->
    <collection property="entity中的某个集合属性" ofType="这个集合泛型所存实体类的绝对路径">
        <id column="这个集合属性中泛型所存实体类对象对应表的主键字段" jdbcType="字段类型" property="这个集合属性中泛型所存实体类对象的主键属性"/>
        <result column="表某个字段(要注意这个column的值,对应的其实是指实际查询出来的字段,所以如果取了别名要写别名)" jdbcType="字段类型" property="这个集合属性泛型所存实体类对象的属性" />  
    </collection>
    
    <!-- 这里也是指的是entity对象中的集合属性(通过单独sql查询时使用,一对多级联) -->
    <collection property="entity中的某个集合属性" column="将这边查询到的字段作为参数传递到新的sql,如id、name等(这里直接填字段名)" select="新的查询sql方法路径,取到方法名"/>

    <!-- 引用另一个resultMap (套娃) -->
    <collection property="entity中的某个集合属性" resultMap="这个引用的resultMap的type,就是这个集合属性泛型所存实体类的绝对路径" />
    
    <!-- discriminator鉴别器级联,相当于java中的switch语句,可以看作是通过某字段不同的值返回不同的pojo,就像继承关系一样,resultMap元素也可以继承,加入自己的属性,是对当前resultMap的一个拓展,前提是resultMap1、resultMap2对应的实体都继承了resultMap对应的实体 -->
    <discriminator javaType="筛选的字段类型(int、long等)" column="筛选的字段(这里直接填字段名)">
        <case value="筛选的字段的值(1、2、3等)" resultMap="引入resultMap1(resultMap1对应的实体继承了resultMap对应的实体)"></case>
        <case value="筛选的字段的值(1、2、3等)" resultMap="引入resultMap1(resultMap2对应的实体继承了resultMap对应的实体)"></case>
    </discriminator>
    
</resultMap>

(1)用法部分示例
association和collection都有有两种配置方式:(1)、嵌套数据 (2)、嵌套查询

a、association一对一级联嵌套查询示例如下:

<select id="getUser" resultMap="userMap" parameterType="long">
    SELECT id,username,password,email FROM USER WHERE id=#{id}
</select>
<resultMap id="userMap" type="user">
    <id property="id" column="id"/>
    <result property="password" column="password"/>
    <result property="email" column="email"/>
    <association property="card" column="id" select="com.changzhen.mybatis.mapper.CardMapper.findCardByUserId"/>
</resultMap>

b、association一对一嵌套数据示例如下:

<resultMap id="ordermap" type="Order">
        <id property="id" column="id" />
        <result property="user_id" column="user_id" />
        <result property="price" column="price" />
        <association property="user" javaType="User">
            <id property="id" column="uid" />
            <result property="username" column="user_name" />
            <result property="age" column="age" />
            <result property="bir" column="bir" />
         </association>
    </resultMap>

c、collection一对多嵌套查询示例如下:

 <mapper namespace="com.changzhen.mybatis.mapper.CardMapper">
    <resultMap id="cardMap" type="card">
        <id property="id" column="id"></id>
        <result property="userId" column="user_id"/>
        <result property="name" column="name"/>
        <result property="address" column="address"/>
        <collection property="creditCards" column="id" select="com.changzhen.mybatis.mapper.BankCardMapper.findBankCardsByUserId"/>
    </resultMap>
 
    <select id="findCardByUserId" parameterType="long" resultMap="cardMap">
        SELECT id, user_id, name, address FROM card WHERE user_id = #{userId}
    </select>
</mapper>

d、collection一对多嵌套数据示例如下:

    <resultMap id="UserRolesMap" type="com.example.server.bean.User">
        <id column="u_id" property="userId" jdbcType="INTEGER"/>
        <result column="u_name" property="userName" jdbcType="VARCHAR"/>
        <result column="password" property="password" jdbcType="VARCHAR"/>
        <collection property="roleList"  javaType="java.util.List" ofType="com.example.server.bean.Role" >
            <id column="r_id" property="roleId" jdbcType="INTEGER"/>
            <id column="r_name" property="roleName" jdbcType="VARCHAR"/>
        </collection>
    </resultMap>

e、discriminator鉴别器级联示例如下:

<mapper namespace="com.changzhen.mybatis.mapper.BankCardMapper">
 
<resultMap id="bankCardMapper" type="bankCard">
    <id property="id" column="id"/>
    <result property="userId" column="user_id"/>
    <result property="bankName" column="bank_name"/>
    <result property="types" column="types"/>
    <discriminator javaType="int" column="types">
        <case value="1" resultMap="debitCardMapper"></case>
        <case value="2" resultMap="creditCardMapper"></case>
    </discriminator>
</resultMap>
 
<select id="findBankCardsByUserId" parameterType="long" resultMap="bankCardMapper">
    SELECT id, user_id, bank_name, types FROM bank_card WHERE user_id = #{userId}
</select>
 
<resultMap id="debitCardMapper" type="debitCard" extends="bankCardMapper"/>
 
<resultMap id="creditCardMapper" type="creditCard" extends="bankCardMapper"/>
 
</mapper>

3、那么对于实体类中的各个属性使用建议

    主键id则建议使用 <id column="" ../>

    一般的字段建议使用 <result column="" ../>

    引用了另外某个实体类对象 <association ... />

    引用了由某个实体类组成的集合 <collection ... />

二、使用过程中需要注意的地方

1、如果是单表映射column默认是对应数据库字段pojo属性与数据库字段对应一致时,中可以不用写映射,如果有个别的字段不一致,可以只写不一致的字段

例如:

    <resultMap id="usermap" type="User">
         <result property="username" column="user_name" />
    </resultMap>
    <select id="selectUserById" parameterType="integer"      resultMap="usermap">
          select * from `user` where id = #{value}
    </select>

结果:User{id=1, username=‘zhangsan’, age=18, bir=Tue Oct 08 00:00:00 CST 2019}

如果查询的字段起了别名,那么column就是别名

例如:

    <resultMap id="usermap" type="User">
          <result property="username" column="u"></result>
    </resultMap>
    <select id="findUserById" parameterType="integer" resultMap="usermap">
          select id,user_name u,age,bir from `user` where id = #{value}
    </select>

结果:User{id=1, username=‘zhangsan’, age=18, bir=Tue Oct 08 00:00:00 CST 2019}

反例:

<resultMap id="usermap" type="User">
         <result property="username" column="user_name"></result>
    </resultMap>
    <select id="findUserById" parameterType="integer" resultMap="usermap">
         select id,user_name u,age,bir from `user` where id = #{value}
    </select>

结果:User{id=1, username=‘null’, age=18, bir=Tue Oct 08 00:00:00 CST 2019}

总结:column值实际上是指查询出的字段!默认情况下是数据库字段。

2、如果是多表关联查询(特征就是resultMap中使用association或collection标签),可能会出现两个表某字段一致的情况!需要对column值进行修改

a. 首先多表关联查询时,主表查询出的字段必须要写全(与单表查询不同,多表查询不能省略,即便数据库列名与pojo属性名一致也要写!否则该字段查询出的数据为null!)

(1)也就是说,凡是查询出来的字段都要写,没有查询的字段不需要写,因为都没有查询这个字段,写了也没用。但是一般都写全,因为一个xml文件一般只配置一个(可以配多个),那么不同的查询语句可能查询出来的字段不一致,尽量补全。

(2)单表查询时可以省略一致的字段。

(3)property的值是属性名,属性名不是类里面定义的变量名,而是set/get方法的方法名去掉set/get,然后首字母小写。
例如:

  <resultMap id="ordermap" type="Order">
        <!-- 字段一定要写全 -->
        <id property="id" column="id" />
        <result property="user_id" column="user_id" />
        <result property="price" column="price" />
        <result property="name" column="name" />
        <!-- property是指order类中关联的另一个pojo属性(User),user是它的变量名 -->

       <!-- javaType一定要写,同理<collection>内的ofType也要写,否则会报空指针异常! -->
        <association property="user" javaType="User">
        </association>
    </resultMap>

反例:

    <resultMap id="ordermap" type="Order">
        <!-- 少写了name -->
        <id property="id" column="id" />
        <result property="user_id" column="user_id" />
        <result property="price" column="price" />
        <!-- property是指order类中关联的另一个pojo属性(User),user是它的变量名 -->
        <association property="user" javaType="User">
        </association>
    </resultMap>

    <select id="findOrderAndUser" resultMap="ordermap">
        select o.* from `order` o,`user` u where u.id = o.user_id
    </select>

    List<Order> list = sqlSession.selectList("findOrderAndUser");
      for (Order or : list ) {
          System.out.println(or);
       }

输出结果为:
Order{id=1, user_id=1, name=‘null’, price=2}
Order{id=2, user_id=1, name=‘null’, price=3}
Order{id=3, user_id=2, name=‘null’, price=3}
Order{id=4, user_id=2, name=‘null’, price=4}

b. 同样需要把字段补全,少写一个字段,则该字段就为null!
例如:

       <association property="user" javaType="User">
            <!-- 这是的property是指User实体内的属性,column是指查询出来的字段,如果有别名就是别名 -->
            <id property="id" column="uid" />
            <result property="username" column="user_name" />
            <result property="age" column="age" />
            <result property="bir" column="bir" />
        </association>

       <select id="findOrderAndUser" resultMap="ordermap">
          select  ??? from `order` o,`user` u where u.id = o.user_id
       </select>

注意:此时两个表关联查询出的所有字段,其中order的id与user表的id字段名一致,输出时需要对其中一个字段取别名,否则值会被覆盖!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值