1. 程式人生 > 實用技巧 >Mybatis 複雜查詢-association和collection 對比說明

Mybatis 複雜查詢-association和collection 對比說明

本篇記錄一下Mybatis association和collection 查詢說明

1.首先上一個實際專案中是mapper 藉此註釋說明

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.thirtydays.reading.dao.ReadingIeltsSectionPODao">
    
    <
resultMap type="SectionDetailAppDTO" id="sectionDetail"> <id property="sectionId" column="sectionId" /> <result property="questionPageUrl" column="questionPageUrl" /> <result property="passagePageUrl" column="passagePageUrl" /> <association
property="longSentenceInfo"
      javaType
="LSBaseAppDTO"
      column
="{sectionId=sectionId,accountId=accountId,lsInstructions=lsInstructions}"
     select="getSectionLongSentenceInfo"/> <collection property="paragraphs"
      ofType
="SectionParagraphAppDTO"
      column
="{sectionId=sectionId}"

      select
="listSectionParagraphs"/> <collection property="questions" ofType="SectionQuestionAppDTO" column="{sectionId=sectionId}" select="listSectionQuestions"/> <collection property="collocations" ofType="SectionCollocationAppDTO" column="{sectionId=sectionId,accountId=accountId}" select="listSectionCollocations" /> <collection property="vocabularies" ofType="SectionVocabulariesAppDTO" column="{sectionId=sectionId,accountId=accountId}" select="listSectionVocabularies" /> <collection property="answers" ofType="SectionAnswerAppDTO" column="{sectionId=sectionId,accountId=accountId}" select="listSectionAnswers" /> </resultMap> <!-- 獲取劍雅閱讀詳情 --> <select id="getReadingSectionDetail" resultMap="sectionDetail"> SELECT t1.`sectionId`, t1.`questionPageUrl`, t1.`passagePageUrl`, t1.`lsInstructions`, #{accountId} AS `accountId` FROM `reading_ielts_section` t1 WHERE t1.`sectionId` = #{sectionId} </select> <resultMap type="LSBaseAppDTO" id="lsBaseAppDTO"> <result property="instructions" column="lsInstructions" /> <collection property="sentences" ofType="LSDetailAppDTO" > <id property="sentenceId" column="sentenceId"/> <result property="longSentence" column="longSentence" /> <result property="longSentenceType" column="longSentenceType" /> <result property="translation" column="translation" /> <result property="optionsStr" column="options" /> <collection property="questions" ofType="LSQuestionAppDTO"> <id property="questionNo" column="questionNo"/> <result property="question" column="question"/> <result property="questionAnswer" column="answer"/> <result property="answerAnalysis" column="analysis"/> <result property="userAnswer" column="userAnswer"/> </collection> </collection> </resultMap> <!-- 獲取章節原文列表 --> <select id="listSectionParagraphs" resultType="SectionParagraphAppDTO"> SELECT `paragraphNo`, `enSentence`, `cnSentence` FROM `reading_ielts_section_paragraph` WHERE `sectionId` = #{sectionId} ORDER BY `paragraphNo` ASC </select> <!-- 獲取劍雅閱讀長難句句子列表 --> <select id="getSectionLongSentenceInfo" resultMap="lsBaseAppDTO"> SELECT t1.`sentenceId`, t1.`longSentence`, t1.`longSentenceType`, t1.`translation`, t1.`options`, t2.`questionNo`, t2.`question`, t2.`answer`, t2.`analysis`, t3.`userAnswer`, #{lsInstructions} AS `lsInstructions` <!-- t4.`lsInstructions` --> FROM `reading_ielts_section_sentence` t1 INNER JOIN `reading_ielts_section_sentence_question` t2 ON t1.`sentenceId` = t2.`sentenceId` LEFT JOIN `reading_ielts_section_sentence_answer` t3 ON t2.`questionNo` = t3.`questionNo` AND t3.`accountId` = #{accountId} <!-- INNER JOIN `reading_ielts_section` t4 ON t1.`sectionId` = t4.`sectionId` --> WHERE t1.`sectionId` = #{sectionId} ORDER BY t1.`sentenceId` </select> <!-- 獲取劍雅閱讀章節詞夥列表 --> <select id="listSectionCollocations" resultType="SectionCollocationAppDTO"> SELECT t2.`collocationId`, t2.`cnCollocation`, t2.`enCollocation`, IFNULL(t3.`collectStatus`, 0) AS `collectStatus` FROM `reading_ielts_section_collocation` t1 INNER JOIN `collocation` t2 ON t1.`collocationId` = t2.`collocationId` LEFT JOIN `collocation_collect` t3 ON t2.`collocationId` = t3.`collocationId` AND t3.`accountId` = #{accountId} WHERE t1.`sectionId` = #{sectionId} ORDER BY t1.`serialNo` </select> <!-- 獲取劍雅章節下詞彙列表 --> <select id="listSectionVocabularies" resultType="SectionVocabulariesAppDTO"> SELECT t2.`wordId`, t2.`word`, t2.`pronounce`, t2.`pronounceAudio`, t2.`bref`, IFNULL(t3.`collectStatus`, 0) AS `collectStatus` FROM `reading_ielts_section_vocabulary` t1 INNER JOIN `word` t2 ON t1.`wordId` = t2.`wordId` LEFT JOIN `word_collect` t3 ON t2.`wordId` = t3.`wordId` AND t3.`accountId` = #{accountId} WHERE t1.`sectionId` = #{sectionId} ORDER BY t1.`serialNo` </select> <!-- 獲取劍雅閱讀答題記錄列表 --> <select id="listSectionAnswers" resultType="SectionAnswerAppDTO"> SELECT `answerId`, `answerTime`, `questionNum`, `correctNum`, `answerDuration`, `correctRate` FROM `reading_ielts_section_answer` WHERE `sectionId` = #{sectionId} AND `accountId` = #{accountId} ORDER BY `answerTime` DESC </select> <!-- 獲取章節題目列表 --> <select id="listSectionQuestions" resultType="SectionQuestionAppDTO"> SELECT `questionNo`, `answer` AS `questionAnswer`, `analysis` AS `answerAnalysis` FROM `reading_ielts_section_part_question` WHERE `sectionId` = #{sectionId} ORDER BY `questionNo` </select> <!-- 獲取劍雅閱讀答題記錄列表 --> <select id="listSectionAnswerRecordsByAnswerId" resultType="SectionAnswerListAppVO"> SELECT t1.`userAnswer`, t1.`correctStatus`, t3.`questionNo`, t3.`answer` AS `questionAnswer`, t3.`analysis` AS `answerAnalysis` FROM `reading_ielts_section_answer_detail` t1 INNER JOIN `reading_ielts_section_answer` t2 ON t1.`answerId` = t2.`answerId` INNER JOIN `reading_ielts_section_part_question` t3 ON t1.`questionNo` = t3.`questionNo` AND t2.`sectionId` = t3.`sectionId` WHERE t1.`answerId` = #{answerId} </select> <!-- 更新劍雅閱讀練習統計資料 --> <update id="updateSectionPracticeNum"> UPDATE `reading_ielts_section` SET `practiceNum` = `practiceNum` + #{practiceNum}, `answerNum` = `answerNum` + #{answerNum}, `correctNum` = `correctNum` + #{correctNum}, `correctRate` = `correctNum` * 100 / `answerNum` WHERE `sectionId` = #{sectionId} </update> <!-- 劍雅列表 --> <select id="listSection" resultType="com.thirtydays.reading.model.vo.IeltsSectionsVO"> SELECT ris.sectionName, ris.sectionId, rit.testName, ic.categoryName, COUNT(distinct riss.sentenceId) sentenceCount, COUNT(distinct risc.collocationId) collocationCount, COUNT(distinct risv.wordId) vocabularyCount FROM reading_ielts_section ris LEFT JOIN reading_ielts_test rit ON ris.testId = rit.testId LEFT JOIN ielts_category ic ON rit.ieltsCategoryId = ic.ieltsCategoryId LEFT JOIN reading_ielts_section_collocation risc ON ris.sectionId = risc.sectionId LEFT JOIN reading_ielts_section_vocabulary risv ON ris.sectionId = risv.sectionId LEFT JOIN reading_ielts_section_sentence riss ON riss.sectionId = ris.sectionId <where> <if test="ieltsCategoryId != null"> rit.ieltsCategoryId = #{ieltsCategoryId} </if> <if test="testId != null"> AND ris.testId = #{testId} </if> </where> GROUP BY ris.sectionId </select> </mapper>

首先我們先看最開始的查詢部分

1.通常我們的級聯查詢需求要麼就是基於一條資料查詢相關的,按照日常我們的寫法,我們估計會先將下表的t1內容全部查詢出來 然後再單條遍歷去查相關的級聯物件,在mybatis中通過一對一和一對多的關聯關係可以極大的優化我們的程式碼

這裡我的需求是根據t1中的每條物件 查詢其相關的內容 一次方法獲取所有相關的級聯集合

包括一對一的association 和一對多的 collection

在這當中需要注意的點包括:
1.
association 通常為一對一關係 查詢的實體一般用javaType

2.級聯關係中的column欄位為select可用的引數,引數必須來子於主查詢語句

3.主語句不需要的子段或者其他一些引數可直接作為查詢條件進行查詢 用來作為子查詢的引數
4.級聯子查詢也可以是級聯查詢  級聯查詢可以巢狀 
    
    <resultMap type="SectionDetailAppDTO" id="sectionDetail">
        <id property="sectionId" column="sectionId" />
        <result property="questionPageUrl" column="questionPageUrl" />
        <result property="passagePageUrl" column="passagePageUrl" />
        <association property="longSentenceInfo" javaType="LSBaseAppDTO" column="{sectionId=sectionId,accountId=accountId,lsInstructions=lsInstructions}" select="getSectionLongSentenceInfo"/>
        <collection property="paragraphs"  ofType="SectionParagraphAppDTO" column="{sectionId=sectionId}" select="listSectionParagraphs"/>    
        <collection property="questions"  ofType="SectionQuestionAppDTO" column="{sectionId=sectionId}" select="listSectionQuestions"/>     
        <collection property="collocations" ofType="SectionCollocationAppDTO" column="{sectionId=sectionId,accountId=accountId}" select="listSectionCollocations" />
        <collection property="vocabularies" ofType="SectionVocabulariesAppDTO" column="{sectionId=sectionId,accountId=accountId}" select="listSectionVocabularies" />
        <collection property="answers" ofType="SectionAnswerAppDTO" column="{sectionId=sectionId,accountId=accountId}" select="listSectionAnswers" />
    </resultMap>
    
    <!-- 獲取劍雅閱讀詳情 -->
    <select id="getReadingSectionDetail" resultMap="sectionDetail">
        SELECT t1.`sectionId`,
               t1.`questionPageUrl`,
               t1.`passagePageUrl`,
               t1.`lsInstructions`,
               #{accountId} AS `accountId`
        FROM `reading_ielts_section` t1 
        WHERE t1.`sectionId` = #{sectionId}
    </select>

級聯巢狀查詢

在上邊我們已經通過

association  和  collection  做了一個物件相關的級聯查詢
其中我們也可以在級聯查詢中巢狀級聯查詢 比如這裡的assocaition又嵌套了一層查詢對映
<resultMap type="LSBaseAppDTO" id="lsBaseAppDTO">
    
        <result property="instructions" column="lsInstructions" />
        
        <collection property="sentences" ofType="LSDetailAppDTO" >
            <id property="sentenceId" column="sentenceId"/>
            <result property="longSentence" column="longSentence" />
            <result property="longSentenceType" column="longSentenceType" />
            <result property="translation" column="translation" />
            <result property="optionsStr" column="options" />
            
            <collection property="questions" ofType="LSQuestionAppDTO">
                <id property="questionNo" column="questionNo"/>
                <result property="question" column="question"/>
                <result property="questionAnswer" column="answer"/>
                <result property="answerAnalysis" column="analysis"/>
                <result property="userAnswer" column="userAnswer"/>
            </collection>
        </collection>
    </resultMap>
    <!-- 獲取劍雅閱讀長難句句子列表 -->
    <select id="getSectionLongSentenceInfo" resultMap="lsBaseAppDTO">
        SELECT
            t1.`sentenceId`,
            t1.`longSentence`,
            t1.`longSentenceType`,
            t1.`translation`,
            t1.`options`,
            t2.`questionNo`,
            t2.`question`,
            t2.`answer`,
            t2.`analysis`,
            t3.`userAnswer`,
            #{lsInstructions} AS `lsInstructions`
            <!-- t4.`lsInstructions` -->
        FROM
            `reading_ielts_section_sentence` t1
            INNER JOIN `reading_ielts_section_sentence_question` t2 ON t1.`sentenceId` = t2.`sentenceId`
            LEFT JOIN `reading_ielts_section_sentence_answer` t3 ON t2.`questionNo` = t3.`questionNo` AND t3.`accountId` = #{accountId}
            <!-- INNER JOIN `reading_ielts_section` t4 ON t1.`sectionId` = t4.`sectionId` -->
        WHERE
            t1.`sectionId` = #{sectionId}
        ORDER BY t1.`sentenceId`
    </select>

在mybatis中

collection 可以根據查詢的列進行合併歸組,例如此處我們的關係就是一對多對多
lsInstructions 對應多個  sentences,  每個sentences 又對應多個  questions