mybatis 查询优化主子表查询之association和collection

很多开发人员之所以编写出低效的应用,有一大原因是并不理解怎样编写高效的SQL。以订单查询为例,我们经常需要查询某个用户的订单以及订单明细,并且以树形方式展现如下:

 

对于这种性质的功能,很多开发人员的做法是先查询主表,然后根据主表去循环子表,如下所示: 

List<Department> depts = DepartmentMapper.queryDept();
for (Department dept: depts) {
    dept.setEmps(EmployeeMapper.queryEmp(dept.id));
}

这种做法就是典型的过程性编程思维,它不仅在更改查询条件或字段时维护性差、不支持两个表的查询条件,而且性能低下,主表有几条记录就会导致请求数据库几次,不仅应用响应时间长,服务器也耗费了更多的资源。更好的做法是一次性查询会所有符合条件的记录,然后再应用中进行拆分并组装,主流的ORM框架几乎都支持这些模式,以使用最广泛的Mybatis为例,其结果映射resultMap中的association(用于一对一和多对一)和collection(用于一对多)元素支持自动将二位结果映射为主子对象。如下所示: 

复制代码
<mapper namespace="chapter6.dao.DepartmentMapper">
    <!-- 嵌套结果集的方式,使用collection标签定义关联的集合类型的属性封装规则 -->
    <resultMap type="chapter6.Department" id="MyDept">
        <id column="did" property="id"/>
        <result column="dept_name" property="departmentName"/>
        <collection property="emps" ofType="chapter6.Employee">
            <id column="eid" property="id"/>
            <result column="last_name" property="lastName"/>
            <result column="email" property="email"/>
            <result column="gender" property="gender"/>
        </collection>
    </resultMap>
    
    <select id="queryDept" resultMap="MyDept" >
        SELECT
            d.id did,
            d.dept_name dept_name,
            e.id,
            e.last_name last_name,
            e.email email,
            e.gender gender
        FROM
            tbl_dept d
        LEFT JOIN tbl_employee e ON d.id = e.d_id
    </select>
</mapper>
复制代码

association同样可以实现相同功能,不过明细表是主表,如下所示:

复制代码
<mapper namespace="com.abc.mapper.StudentMapper">
    <select id="getById" parameterType="int"
        resultMap="studentResultMap">
        select s.id s_id,
        s.name s_name,
        s.gender s_gender,
        s.major s_major,
        s.grade s_grade,
        t.id t_id,
        t.name t_name,
        t.gender t_gender,
        t.title t_title,
        t.research_area t_research_area
        from student s left join teacher t
        on s.supervisor_id = t.id
        where s.id=#{id}
    </select>
    <resultMap id="studentResultMap" type="Student">
        <id property="id" column="s_id" />
        <result property="name" column="s_name" />
        <result property="gender" column="s_gender" />
        <result property="major" column="s_major" />
        <result property="grade" column="s_grade" />
        <!--使用resultMap属性引用下面的教师实体映射 -->
        <association property="supervisor" javaType="Teacher"
            resultMap="supervisorResultMap" />
    </resultMap>
    <!--教师实体映射 -->
    <resultMap id="supervisorResultMap" type="Teacher">
        <id property="id" column="t_id" />
        <result property="name" column="t_name" />
        <result property="gender" column="t_gender" />
        <result property="researchArea" column="t_research_area" />
        <result property="title" column="t_title" />
    </resultMap>
</mapper>
复制代码

 需要注意的是,默认情况下Mapper中使用association标签,select 有大量相同的数据,此时会出现问题, 有的数据可以联查出来, 而有的不可以。此时需要开启缓存开关,参考https://blog.csdn.net/qq_27848369/article/details/80534253

posted @   zhjh256  阅读(1890)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
历史上的今天:
2017-02-02 c++的友元类、方法及其益处
2017-02-02 c/c++的typedef/using类型别名
2017-02-02 c++的class声明及相比java的更合理之处
2017-02-02 c++ sleep(windows/linux)
2017-02-02 c++不自动生成相关函数比如赋值、拷贝函数
点击右上角即可分享
微信分享提示