SSM框架学习-MyBatis篇 SQL映射文件——实现高级结果映射和多表查询

SSM框架学习-MyBatis篇 SQL映射文件——实现高级结果映射(多表查询)

问题情境:比如有张表,用户和用户详情,这两张表里面没长表都有一个id字段,这两个表的id字段都是对应的。

实体类里面分别对应两个实体类,user和userdetail,还有一个很重要的实体类,叫做“用户+用户详情”(userwithdetail),这个实体类首先继承了user,里面的元素是前面的userdetail这个对象。

比如我想要查询一个用户,我还想知道他的详情,我就要在数据库里面select它一下,要返回userwithdetail 这个对象,因为这这个对象既继承了父类User,还包括了对应的对象userDetail。那么这么复杂的结构,肯定会使用到多表查询。

mybatis对于处理简单的单表查询,用resultType就可以解决 但是对于多表查询,都要使用resultMap进行详细的描述 告诉mybatis怎么封装。

自顶向下的先实践一下多表查询:

1、数据库定义user和userdetail的两张表。这个就不多赘述。

对应的实体类,前面已经说过。其中user和userdetail都实现serializable,UserWithDetail 继承了User

2、mybatis的配置文件先声明一下两个要用到的Mapper文件,这个也不多赘述

3、首先先写一个方法,就按照id查询一个用户吧。这个写法应该没毛病。给User和UserDetail两张表

起一个别名。然后两表联合查询。

    <select id="queryById" resultMap="userWithDetailMap">
        select t1.id as uid ,t1.phone,t1.password,t1.create_date,t1.status,
        t2.id  as udid,t2.address,t2.cid
        from user t1,user_detail t2
        <where>
            t1.id=u_id
            and t1.id =#{id}
        </where>
    </select>

 4、由于从user t1,user_detail t2这两张表里面查询数据,单纯的语句已经不知道返回的数据的封装规则是什么了。resultType就不能解决问题了,那我们就定义一个resultMap

    <resultMap id="userBaseMap" type="com.sdbit.ylh.entity.UserWithDetail">
        <!--user的基本信息-->
        <id property="id" column="uid"/>
        <result property="phone" column="phone"/>
        <result property="password" column="password"/>
        <result property="createDate" column="create_date"/>
        <result property="status" column="status"/>
    </resultMap>

这里先定义一个基本的user信息而不是userdetail,原因是这个resultmap竟然还可以继承,为了以后写方便,就先给它写一个basemap,对表中的数据进行映射,先说说里面的属性

  • property:映射数据库列(column)的实体与对象(JavaBean)的对应元素的属性。这里是User类的元素。
  • column:数据库列名
  • id:id算是一个比较特殊的property,用来映射数据库主键列与对象对应的元素,这里是User的uid元素

那user的对应属性如此,可是最后结果还有一个userdetail对象需要我们去封装,这个应该怎么解决呢?

那么就需要用到上面说的resultMap的继承。

5、这里在写一个resultMap,id的值为userWithDetailMap

    <resultMap id="userWithDetailMap" extends="userBaseMap"   type="com.sdbit.ylh.entity.UserWithDetail">
        <association property="userDetail" javaType="com.sdbit.ylh.entity.UserDetail">
        <id property="id" column="udid"/>
        <result property="address" column="address"></result>
        <result property="cid" column="cid"></result>
        </association>
    </resultMap>

这里就用到了association这个属性,这个属性就专门用来处理一对一的情况。这里持有的是userDetail这一个对象,然后我们需要告诉mybatis它类型是对应实体类中的 com.sdbit.ylh.entity.UserWithDetail这个类,

这个类对应的表的属性,和他们对应的类里面的元素。我们在里面继续声明即可,和上面一样id和property

完事之后在看看上面指定的resultmap,就一目了然了。

程序成功运行,查询出一条数据user+userdetail

还有一种封装resultMap更简单的方式,但是不是官方推荐的那种,也可以使用(这里没有使用继承!):

实践一下分步查询:

分步查询(如果查询太复杂,可以使用分步查询)

意思就是,当查询很复杂的时候,我们可以先写一个sql语句进行单表查询,然后再在resultMap里面再次执行一次别的sql语句

这个sql语句可以是别的mapper里面的语句。

具体怎么实现呢?下面就是实践演示。

1、首先定义一个“别的”mapper,这里叫做UserDetailMapper,顾名思义,就是专门对UserDetail的这个表进行查询。

因为最后我们想要得到的结果是User+UserDetail=UserWithDetail。

2、在sql的xml文件里写一个简单的select,把UserDetail表里面对应id的记录查找出来。

3、回到UserMapper.xml,我们首先封装一个resultMap,

    <resultMap id="userWithDetailMap3" extends="userBaseMap" type="com.sdbit.ylh.entity.UserWithDetail">
        <association property="userDetail"
                     select="com.sdbit.ylh.mapper.UserDetailMapper.queryByUserId"
                     column="uid">
        </association>
    </resultMap>

在这个语句中可以看到,association里面的property指向的就是userwithDetail里面的userDetail,那么这个userDetail对象从哪里来呢?就从select引用com.sdbit.ylh.mapper.UserDetailMapper下面的queryByUserId方法里来,但是上面这个uid是从哪里来呢??

那么我们在sql语句书写的时候,就要包含resultMap需要的列,我们现在就来写分步查询的最后一个sql

<select id="queryByIdByStep" resultMap="userWithDetailMap3">
        select t1.id as uid ,t1.phone,t1.password,t1.create_date,t1.status
        from user t1
        <where>
            and t1.id =#{id}
        </where>
    </select>

那么这里的uid就封装好了给resultMap。resultmap就可以执行第二步查询。完成了两次查询后UserWithDetail这个对象才完美的被数据填满。

如上就完成了使用association处理一对一的关联关系。

1对1的关联关系总结:

  •     学会了使用association来实现多表查询,对实体类和数据库这两方的映射
  •     处理多表查询中出现bean包含bean的两种处理方式,官方的和简单的
  •     resultMap的继承的写法。
  •     使用定义resultMap来实现分步查询,使用association,甚至可以跨mapper调用方法查询

  

   

猜你喜欢

转载自blog.csdn.net/Xenoverse/article/details/83050681
今日推荐