MyBatis系列(四 )——MyBatis的多表操作

前言

在前面的系列文章学习中,我们已经可以实现对单表进行CRUD等操作了,但是对于多表操作来说,返回的结果往往是多表查询后的数据集,这个时候我们又应该如何去封装我们的结果集呢?本篇文章将针对MyBatis的多表操作的使用进行介绍,希望能够对各位读者一个参考。

想要了解更多MyBaits系列文章,可以从下面的传送门阅读:

MyBatis系列(一)——MyBatis的介绍和CRUD
MyBatis系列(二)——MyBatis的动态代理和映射文件动态配置
MyBatis系列(三)——MyBatis的类型处理器和PageHelper分页插件


一、表和表之间的关系

在讲MyBatis的多表操作之前,我们不妨先回顾一下,在关系型数据库中,表和表之间的关系都有哪些。

(一)一对一关系

比如存在订单表和用户表,订单表对于用户表而言就是一对一的关系,因为一个订单只能对应一个用户,订单表中使用userId作为外键关联用户user

(二)一对多关系

一对多的关系在生活中也很好找例子,一个班级可以有很多个学生,一个用户可以有很多订单,用户user通过userId可以关联到多张订单表。

(三)多对多关系

一个学生可以选多门课程,一门课程也可以被多个学生选择,这就是生活中的多对多关系。再比如一个用户可以有多个角色,一个角色也可以被分配给多个用户。在实际操作中,我们往往会使用一张中间表来保存二者之间的关联关系。


二、使用MyBatis进行多表操作

我们从之前的文章学习中知道,在单表操作中,MyBaits是给我们提供了resultType属性让我们选择封装的对象,但是使用多表查询操作中,结果集中势必会有多张表的字段交互的结果。这个时候,单纯的resultType已经是不能够满足我们承载结果集的数据了,这就引出了resultMap属性。

(一)一对一操作

我们以订单的例子来进行演示,一个订单对应一个用户。

步骤一:创建POJO类,用户和订单类简要代码如下:
public class Order {

    private Integer oid;

    private Date createtime;

    private Double total;

    // 一个订单对应一个用户,所以这里不写userId,而是用User这个完整对象
    private User user;
}
public class User {

    private Integer uid;

    private String username;

    private String password;

    private Date birth;
}
步骤二:创建OrderMapper.xml映射文件

这里需要注意,对于Order对象中的User属性,我们可以使用类似于user属性名.属性的方式来选择注入结果集的数据。

  <mapper namespace="com.qiqv.dao.OrderMapper">

    <resultMap id="orderMap" type="com.qiqv.pojo.Order">
        <!--手动指定字段与实体属性的映射关系 column: 数据表的字段名称 property:实体的属性名称 -->
        <id column="oid" property="oid"></id>
        <result column="createtime" property="createtime"></result>
        <result column="total" property="total"></result>
        <result column="uid" property="user.uid"></result>
        <result column="username" property="user.username"></result>
        <result column="password" property="user.password"></result>
        <result column="birth" property="user.birth"></result>
    </resultMap>

    <select id="getOrderById" parameterType="int" resultMap="orderMap">
        select * from orders o,user u where o.oid = u.uid and oid = #{id}
    </select>

</mapper>

除了上面这种方式外,我们还可以使用association标签来封装Order对象中的User属性

    <resultMap id="orderMap" type="com.qiqv.pojo.Order">
        <!--手动指定字段与实体属性的映射关系 column: 数据表的字段名称 property:实体的属性名称 -->
        <id column="oid" property="oid"></id>
        <result column="createtime" property="createtime"></result>
        <result column="total" property="total"></result>
        <association property="user" javaType="user">
            <id column="uid" property="uid"></id>
            <result column="username" property="username"></result>
            <result column="password" property="password"></result>
            <result column="birth" property="birth"></result>
        </association>
    </resultMap>
步骤三:在核心配置文件中引入映射文件和配置别名
  <!--  配置别名 -->
    <typeAliases >
        <typeAlias type="com.qiqv.pojo.User" alias="user"></typeAlias>
        <typeAlias type="com.qiqv.pojo.Order" alias="order"></typeAlias>
     </typeAliases>
    <mappers>
        <mapper resource="com/qiqv/mapper/UserMapper.xml"></mapper>
        <mapper resource="com/qiqv/mapper/OrderMapper.xml"></mapper>
    </mappers>
步骤四:在Mapper接口文件中加入方法
public interface OrderMapper {
    // 根据oid查询订单信息
    Order getOrderById(Integer oid);
}
步骤五:在代码中进行测试
    @Test
    public void getOrderByIdTest() throws  Exception{
        InputStream is = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
        System.out.println(mapper.getOrderById(1));
    }
(二)一对多操作

一对多的表关系,我们在第一节就已经介绍过了。比如一个用户有多个订单,可以联想到要想实现查询用户的时候顺带查询订单,就需要在原有的用户类基础上新增一个封装有订单的List集合。

步骤一:修改原有的User对象
public class User {

    private Integer uid;

    private String username;

    private String password;

    private Date birth;

    private List<Order> orders;
}
步骤二:在映射文件中新增对应的查询语句和resultMap配置
    <resultMap id="userOMap" type="com.qiqv.pojo.User">
        <id column="uid" property="uid"></id>
        <result column="username" property="username"></result>
        <result column="birth" property="password"></result>
        <!--
        使用collection标签来封装List集合对象
        property 表示属性名称 ofType 表示集合中封装的对象类型
        -->
        <collection property="orders" ofType="com.qiqv.pojo.Order">
            <id column="oid" property="oid"></id>
            <result column="createtime" property="createtime"></result>
            <result column="total" property="total"></result>
        </collection>
    </resultMap>

    <select id="getAllUserOrderByUid" parameterType="int" resultMap="userOMap">
        select * from user u ,orders o where u.uid = o.uid and u.uid = #{id}
    </select>
步骤三:在核心配置文件配置别名和映射文件(如果之前已经做了就可以忽略这一步)
<!--  配置别名 -->
    <typeAliases >
        <typeAlias type="com.qiqv.pojo.User" alias="user"></typeAlias>
        <typeAlias type="com.qiqv.pojo.Order" alias="order"></typeAlias>
     </typeAliases>
    <mappers>
        <mapper resource="com/qiqv/mapper/UserMapper.xml"></mapper>
        <mapper resource="com/qiqv/mapper/OrderMapper.xml"></mapper>
    </mappers>
步骤四:在Mapper接口文件中加入方法
public interface UserMapper {
    // 查询用户的订单方法
    User getAllUserOrderByUid(Integer uid) throws Exception;
}
步骤五:在测试中进行测试
    @Test
    public void getAllUserOrderByUidTest() throws  Exception{
        InputStream is = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        System.out.println(mapper.getAllUserOrderByUid(1));
    }
(三)多对多操作

多对多本质上其实就是两个一对多关系,只要理解了一对多的写法,多对多其实并没有什么不同。在本小节中,我们会举例用户和角色之间的多对多关系进行演示操作。

步骤一:创建实体类对象
public class User {

    private Integer uid;

    private String username;

    private String password;

    private Date birth;

    private List<Order> orders;

    private List<Role> roles;
}
public class Role {

    private int id;

    private String rolename;
}
步骤二:定义映射文件方法内容:
    <resultMap id="userRoleMap" type="user">
        <id column="uid" property="uid"></id>
        <result column="username" property="username"></result>
        <result column="password" property="password"></result>
        <result column="birth" property="password"></result>
        <collection property="roles" ofType="role">
            <id column="rid" property="id"></id>    
            <result column="rolename" property="rolename"></result>
        </collection>
    </resultMap>

    <select id="getAllUserRoleByUid" parameterType="int" resultMap="userRoleMap">
        select * from user u  left join  user_role_table ur  on u.uid=ur.uid left join roles r on ur.rid = r.id where u.uid = 1
    </select>
步骤三:在核心配置文件中配置别名和映射文件(如果已经加过了就忽略这一步)
  <!--  配置别名 -->
    <typeAliases >
        <typeAlias type="com.qiqv.pojo.User" alias="user"></typeAlias>
        <typeAlias type="com.qiqv.pojo.Role" alias="role"></typeAlias>
     </typeAliases>
    <mappers>
        <mapper resource="com/qiqv/mapper/UserMapper.xml"></mapper>
    </mappers>
步骤四:在mapper接口中添加方法
public interface UserMapper {
    // 根据uid查询用户和所属角色
    User getAllUserRoleByUid(Integer uid);
}
步骤五:在代码中进行测试
    @Test
    public void getAllUserRoleByUidTest() throws Exception {
        InputStream is = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.getAllUserRoleByUid(1);
        for(Role role : user.getRoles()){
            System.out.println(role);
        }
    }

说在最后

至此,有关MyBatis的多表操作就讲解结束了,其实MyBatis的多表操作实现并不复杂,关键在于知道resultMap的使用,我们通过resultMap封装好POJO类中的结果集后,其他的自然没有难度。另外需要注意的是多对多的表关系,本质上只是两个对象之间的一对多,用的时候需要注意不要写漏了即可。

posted @ 2021-04-02 15:11  moutory  阅读(173)  评论(0编辑  收藏  举报  来源