Day64 Mybatis的多表查詢、ResultMap、註解以及快取

神一樣的我發表於2018-05-02

mybatis的多表查詢

AutoMapping自動注入(預設):

概念:如果資料庫表的欄位和實體類的屬性名一致,則欄位的值自動賦值給實體類的屬性。
    資料庫表設計:
        學生表:
            學號
            姓名
            年齡
            教師編號
        教師表:
            教師編號
            姓名
    業務裝配方式:根據業務分開查詢其需要的資料,並將查詢的資料儲存到實體類中
        一對一查詢:
            示例  查詢學生及其教師資訊  
                先查詢所有的學生資訊
                根據學生資訊中的老師編號查詢其對應的教師資訊,並儲存到該學生實體類的教師屬性中
            注意:
                學生實體類的設計中應該包含教師屬性
        一對多查詢:
            示例  查詢教師及其學生資訊
                先查詢教師資訊
                根據教師編號查詢其學生資訊,並將學生資訊儲存到教師實體類的學生集合屬性中
            注意:
                教師實體類的設計中應該包含集合型別的學生屬性
        特點:
            效率低下。
            SQL語句執行了n+1條

ResultMap n+1方式:

resultMap屬性:
            如果實體類的屬性名和表的欄位不一致,這也就需要
            指明的將某個欄位的值賦值給實體類的指定的屬性。
            在mapper.xml中使用ResultMap屬性進行指明賦值即可。
            示例:
            <resultMap type="student2" id="stu">
                <id column="sid" property="sid2"/>
                <!-- <result column="sname" property="sname"/> -->
                <result column="sage" property="sage2"/>
                <result column="tid" property="tid2"/>
            </resultMap>
            <select id="selStuResultMap" resultMap="stu">
                select * from student
            </select>
            注意:ResultType和ResultMap選擇其中一個使用。
        一對一查詢:
            示例:查詢學生及其教師資訊
                在mapper.xml檔案中宣告標籤語句完成查詢
                select標籤中宣告sql語句查詢所有的學生資訊
                使用標籤屬性ResultMap指明Student實體類屬性的teacher屬性的值執行一次查詢
                程式碼:
                <resultMap type="student" id="rm">
                <!-- <id column="sid" property="sid"/>
                <result column="sname" property="sname"/>
                <result column="sage" property="sage"/> -->
                <result column="tid" property="tid"/>
                <association property="teacher" column="tid" select="com.bjsxt.mapper.TeacherMapper.selTeaById"></association>
            </resultMap>
            <select id="selStuRm" resultMap="rm">
                select * from student
            </select>
        一對多查詢:
            示例 查詢教師及其學生資訊
            在mapper.xml中宣告標籤語句完成教師查詢
            然後使用ReultMap屬性進行自定義賦值,同時指明學生集合屬性的查詢。
            程式碼:
            <resultMap type="teacher" id="rm">
            <id column="tid" property="tid"/>
            <result column="tnname" property="tname"/>
            <collection property="ls" column="tid" select="com.bjsxt.mapper.StudentMapper.selStuByTid"></collection>
        </resultMap>
        <select id="selTeaRm" resultMap="rm">
            select * from teacher
        </select>
    總結特點:
        效率低下的。SQL語句執行了n+1條。
        如果實體類的屬性是一個物件則在ResultMap中使用association 標籤即可
        如果實體類的屬性是一個集合物件,則使用collection 標籤即可

ResultMap 聯合查詢方式:

一對一查詢:
            示例  查詢學生及其教師資訊
            <resultMap type="student" id="rms">
            <id column="sid" property="sid"/>
            <result column="sname" property="sname"/>
            <result column="sage" property="sage"/>
            <result column="tid" property="tid"/>
            <association property="teacher" javaType="teacher">
                <result column="tid" property="tid"/>
                <result column="tname" property="tname"/>
            </association>
            </resultMap>
        <select id="selStuUn" resultMap="rms">
            select * from student s
            left join teacher t
            on s.tid=t.tid
        </select>
        一對多查詢:  
            示例:查詢教師及其學生資訊
        <resultMap type="teacher" id="rt">
            <id column="tid" property="tid"/>
            <result column="tname" property="tname"/>
            <collection property="ls" ofType="student">
                <id column="sid" property="sid"/>
                <result column="sname" property="sname"/>
                <result column="sage" property="sage"/>
                <result column="tid" property="tid"/>
            </collection>
        </resultMap>
        <select id="selTeaUn" resultMap="rt">
            select * from teacher t
            left join student s
            on t.tid=s.tid
        </select>

Automapping多表注入

    <!-- 一對一 查詢學生及其教師資訊 autoMapping注入  -->
        <select id="selStuUn2" resultType="Student">
            select s.*,t.tid `teacher.tid`,t.tname `teacher.tname` from student s
            left join teacher t
            on s.tid=t.tid
        </select>

mybatis的註解

註解學習:
    註解的作用(瞭解):
        替代XML檔案配置的。
    特點:
        註解可以節省我們的工作量,但是耦合性比較高。
    注意:
        mybatis的註解和mapper.xml配置文集可以同時使用
    示例:
    //查詢所有的學生資訊
    @Select("select * from student")
    List<Student> selStu();

    //根據ID查詢學生資訊
    @Select("select * from student where sid=#{0}")
    Student selStuById(int sid);

    //插入一條學生資訊
    @Insert("insert into student values(default,#{0},#{1},#{2})")
    int insStu(String sname,int sage,int tid);

    //刪除一條學生資訊
    @Delete("delete from student where sid=#{0}")
    int delStu(int sid);

快取

一級快取:(SqlSession)
    當SqlSession物件完成資料庫操作後,會將此次操作的資料庫命令物件(preparedStatement)放入快取中,
    以後執行相同的mapper.xml中配置的標籤時,直接從快取獲取即可。 
二級快取:(Factory快取)
    第一步:
        在mapper.xml檔案中使用標籤開啟:
            <cache readOnly="true"></cache>
    第二步:
        SqlSession物件在Close的時候會將其快取的資料重新整理到Factory快取中

其他知識點:

其他知識點:

資料庫設計:
  表關係設計:

 一對多   :主外來鍵關聯     有外來鍵的是子表
多對多    :通過中間表

查詢結果集的處理:  
相當於原生JDBC的while()迴圈對結果集的賦值。
實體類設計: 把一個實體類根據業務需求作為另一個實體類的屬性。

 業務裝配模式:  效率低下 ,SQL語句簡單,分開查詢
            使用JAVA程式碼進行邏輯判斷,在一條SQL語句查詢時候呼叫另一條查詢語句。
 ResultMap n+1方式: 效率低下,但完全解耦,有關聯的列必須寫,沒關聯的列可以省略。SQL語句簡單,分開查詢
    在XML檔案中用標籤進行邏輯判斷賦值

 ResultMap  多表聯合查詢: SQL語句複雜。但效率高。
           使用SQL多表聯合查詢語句替代邏輯判斷。
    在ResultMap 裡進行一對一,和一對多的標籤操作進行對欄位進行賦值。
ResultType 和ResultMap不能同時使用
 ResultMap   相關欄位解釋:
https://blog.csdn.net/wxwzy738/article/details/24742495
    Type:該條資料返回值型別   
        id:和select 的ResultMap的值同名。
    Id標籤  :一般為表的主鍵 
         column:資料庫欄位名
         property:實體類屬性
   Result標籤:一般為表欄位賦值
    column:資料庫欄位名
         property:實體類屬性
   Association標籤: 適用於一對一,也就是連線的表查詢條件是一個物件的資料,比如一個學生對應一個教師,如果是多表查詢,可以在該標籤裡面用ID和Result標籤給連線表賦值
       column:資料庫欄位名   (單表查詢)
         property:實體類屬性
        select:需要呼叫查詢語句的全限定路徑,包名到查詢語句名   (單表查詢使用這個繼續查另一個表)  
       JavaType:完整java類名或別名  (聯合查詢)
   Collection標籤:適用於一對多,也就是連線的表是一個集合。比如一個教師對應多個學生
可以在該標籤裡面用ID和Result標籤給連線表賦值

     column:資料庫欄位名   (單表查詢)
         property:實體類屬性
        select:需要呼叫查詢語句的全限定路徑,包名到查詢語句名   (單表查詢使用這個繼續查另一個表)  
       OfType: 連線表的完整java類名或別名  (聯合查詢)

JavaType和OfType的區別:
JavaType和ofType都是用來指定物件型別的,但是JavaType是用來指定pojo中屬性的型別,而ofType指定的是對映到list集合屬性中pojo的型別。都是指定物件的型別 不同的是當使用反向查詢select從另一個maper檔案中取出資料時必須用ofType


 使用註解進行單表查詢比使用XML方式簡單。但是對於多表查詢不建議用註解方式進行查詢,註解大大阻礙瞭解耦。

快取:







細節:

注意mybatis裡要掃描mapper包
select 要寫 resultType 代表的是每條語句的返回值型別   
 對應的介面裡的方法裡的寫的是整個結果集用什麼去存,介面方法要與xml裡的查詢方法ID同名。

小案例:

需求:
這裡寫圖片描述

資料庫設計:
學生表:
CREATE TABLE student (
sid int(10) NOT NULL AUTO_INCREMENT,
sname varchar(100) NOT NULL,
sage int(3) NOT NULL,
tid int(10) NOT NULL,
PRIMARY KEY (sid)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
教師表:
CREATE TABLE teacher (
tid int(10) NOT NULL,
tname varchar(100) NOT NULL,
PRIMARY KEY (tid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

匯入Mybatis相關jar包 Gson jar包 js1.9 log4j jar包
配置XML檔案

搭建環境,建包,寫程式碼

src:
mybatis.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
  <configuration>
    <typeAliases>
        <package name="com.bjsxt.pojo"/>
    </typeAliases>
    <environments default="mysql">
        <environment id="mysql">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="1234"/>
            </dataSource>
        </environment>
    </environments>
      <mappers>
        <package name="com.bjsxt.mapper"/>
      </mappers>
  </configuration>

log4j.properties:


log4j.rootCategory=info



log4j.logger.com.bjsxt.mapper=debug, CONSOLE
log4j.logger.com.bjsxt.serviceImpl=debug, CONSOLE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=- %c-%d-%m%n


log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=D:\axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=- %c-%d-%m%n

com.bjsxt.mapper:
ShowMapper.xml:

<?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.bjsxt.mapper.ShowMapper">
    <!--
        分頁查詢學生及其教師資訊
      -->
      <resultMap type="student" id="rs">
        <id column="sid" property="sid"/>
        <result column="sname" property="sname"/>
        <result column="sage" property="sage"/>
        <result column="tid" property="tid"/>
        <association property="teacher" javaType="teacher">
            <result column="tid" property="tid"/>
            <result column="tname" property="tname"/>
        </association>
      </resultMap>
      <select id="selStu" resultMap="rs">
        select * from student s
        left join teacher t
        on s.tid=t.tid
        <where>
            <if test="param1 !='' and param1 !=null">
                <bind name="sa" value="'%'+param1+'%'"/>
                and sname like #{sa}
            </if>
            <if test="param2 !='' and param2 !=null">
                <bind name="ta" value="'%'+param2+'%'"/>
                and tname like #{ta}
            </if>
        </where>
         limit #{param3},#{param4}
      </select>

 </mapper>

ShowMapper.java:

package com.bjsxt.mapper;

import java.util.List;

import com.bjsxt.pojo.Student;

public interface ShowMapper {
    /**
     * 分頁查詢學生及其教師資訊
     * @param tname 
     * @param sname 
     * @param pageStart
     * @param pageSize
     * @return
     */
    List<Student> selStu(String sname, String tname, int pageStart,int pageSize);


}

com.bjsxt.pojo:
Student.java:

package com.bjsxt.pojo;

public class Student {
    private int sid;
    private String sname;
    private int sage;
    private int tid;
    private Teacher teacher;
    public int getSid() {
        return sid;
    }
    public void setSid(int sid) {
        this.sid = sid;
    }
    public String getSname() {
        return sname;
    }
    public void setSname(String sname) {
        this.sname = sname;
    }
    public int getSage() {
        return sage;
    }
    public void setSage(int sage) {
        this.sage = sage;
    }
    public int getTid() {
        return tid;
    }
    public void setTid(int tid) {
        this.tid = tid;
    }
    public Teacher getTeacher() {
        return teacher;
    }
    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }
    @Override
    public String toString() {
        return "Student [sid=" + sid + ", sname=" + sname + ", sage=" + sage + ", tid=" + tid + ", teacher=" + teacher
                + "]";
    }
    public Student() {
        super();
        // TODO Auto-generated constructor stub
    }
    public Student(int sid, String sname, int sage, int tid, Teacher teacher) {
        super();
        this.sid = sid;
        this.sname = sname;
        this.sage = sage;
        this.tid = tid;
        this.teacher = teacher;
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + sage;
        result = prime * result + sid;
        result = prime * result + ((sname == null) ? 0 : sname.hashCode());
        result = prime * result + ((teacher == null) ? 0 : teacher.hashCode());
        result = prime * result + tid;
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Student other = (Student) obj;
        if (sage != other.sage)
            return false;
        if (sid != other.sid)
            return false;
        if (sname == null) {
            if (other.sname != null)
                return false;
        } else if (!sname.equals(other.sname))
            return false;
        if (teacher == null) {
            if (other.teacher != null)
                return false;
        } else if (!teacher.equals(other.teacher))
            return false;
        if (tid != other.tid)
            return false;
        return true;
    }



}

Teacher.java:

package com.bjsxt.pojo;

public class Teacher {
    private int tid;
    private String tname;
    public int getTid() {
        return tid;
    }
    public void setTid(int tid) {
        this.tid = tid;
    }
    public String getTname() {
        return tname;
    }
    public void setTname(String tname) {
        this.tname = tname;
    }
    @Override
    public String toString() {
        return "Teacher [tid=" + tid + ", tname=" + tname + "]";
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + tid;
        result = prime * result + ((tname == null) ? 0 : tname.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Teacher other = (Teacher) obj;
        if (tid != other.tid)
            return false;
        if (tname == null) {
            if (other.tname != null)
                return false;
        } else if (!tname.equals(other.tname))
            return false;
        return true;
    }
    public Teacher() {
        super();
        // TODO Auto-generated constructor stub
    }
    public Teacher(int tid, String tname) {
        super();
        this.tid = tid;
        this.tname = tname;
    }




}

PageInfo.java:

package com.bjsxt.pojo;

import java.util.List;

public class PageInfo {
    private int pageNum;
    private int pageSize;
    private List<Student> ls;
    public int getPageNum() {
        return pageNum;
    }
    public void setPageNum(int pageNum) {
        this.pageNum = pageNum;
    }
    public int getPageSize() {
        return pageSize;
    }
    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }
    public List<Student> getLs() {
        return ls;
    }
    public void setLs(List<Student> ls) {
        this.ls = ls;
    }
    @Override
    public String toString() {
        return "PageInfo [pageNum=" + pageNum + ", pageSize=" + pageSize + ", ls=" + ls + "]";
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((ls == null) ? 0 : ls.hashCode());
        result = prime * result + pageNum;
        result = prime * result + pageSize;
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        PageInfo other = (PageInfo) obj;
        if (ls == null) {
            if (other.ls != null)
                return false;
        } else if (!ls.equals(other.ls))
            return false;
        if (pageNum != other.pageNum)
            return false;
        if (pageSize != other.pageSize)
            return false;
        return true;
    }
    public PageInfo() {
        super();
        // TODO Auto-generated constructor stub
    }
    public PageInfo(int pageNum, int pageSize, List<Student> ls) {
        super();
        this.pageNum = pageNum;
        this.pageSize = pageSize;
        this.ls = ls;
    }




}

com.bjsxt.service:
ShowService.java:

package com.bjsxt.service;

import java.io.IOException;

import com.bjsxt.pojo.PageInfo;

public interface ShowService {

    /**
     * 根據pageNum和pageSize獲取學生分頁資料
     * @param pageNum
     * @param pageSize
     * @param tname 
     * @param sname 
     * @return
     */
    PageInfo getStuInfoService(int pageNum,int pageSize, String sname, String tname)throws IOException ;

}   

com.bjsxt.serviceImpl:
ShowServiceImpl.java:

package com.bjsxt.serviceImpl;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import com.bjsxt.mapper.ShowMapper;
import com.bjsxt.pojo.PageInfo;
import com.bjsxt.pojo.Student;
import com.bjsxt.service.ShowService;

public class ShowServiceImpl implements ShowService{

    @Override
    public PageInfo getStuInfoService(int pageNum,int pageSize, String sname, String tname) throws IOException {
        //獲取SqlSession物件
                InputStream is = Resources.getResourceAsStream("mybatis.xml");
                SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(is);
                SqlSession ss=factory.openSession();
        //獲取mapper介面物件
                ShowMapper sm=ss.getMapper(ShowMapper.class);
        //換算分頁查詢起始點
                int pageStart=pageNum*pageSize-pageSize;
        //查詢資料
                List<Student> ls=sm.selStu(sname,tname,pageStart, pageSize);
        //將資料儲存到pageInfo物件中
                PageInfo p=new PageInfo();
                p.setPageNum(pageNum);
                p.setPageSize(pageSize);
                p.setLs(ls);
        return p;
    }

}

com.bjsxt.servlet:
ShowServlet.java:

package com.bjsxt.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.bjsxt.pojo.PageInfo;
import com.bjsxt.service.ShowService;
import com.bjsxt.serviceImpl.ShowServiceImpl;
import com.google.gson.Gson;

/**
 * Servlet implementation class ShowServlet
 */
@WebServlet("/show")
public class ShowServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //設定請求編碼格式
        req.setCharacterEncoding("utf-8");
        //設定響應編碼格式
        resp.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");
        //獲取請求資訊
        int pageNum=Integer.parseInt(req.getParameter("pageNum"));
        int pageSize=Integer.parseInt(req.getParameter("pageSize"));
        String sname=req.getParameter("sname");
        String tname=req.getParameter("tname");
        //處理請求資訊
            //建立業務層物件
            ShowService ss=new ShowServiceImpl();
            PageInfo p=ss.getStuInfoService(pageNum, pageSize,sname,tname);
        //響應處理結果
            resp.getWriter().write(new Gson().toJson(p));
    }
}

WebContext:
show.jsp:

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
<!--引入jQuery檔案  -->
<script type="text/javascript" src="js/j.js"></script>
<!--宣告js程式碼域  -->
<script type="text/javascript">
    $(function(){
        //宣告變數記錄當前頁碼數
        var pn;
        //頁面載入呼叫getData獲取第一個資料
        getData(1,2);
        //給查詢按鈕新增事件
        $("#btn").click(function(){
            $("input[type=radio]").each(function(){
                if(this.value==2){
                    this.checked=true
                }else{
                    this.checked=false;
                }
            })
            getData(1,2);

        })
        //給上一頁新增事件
        $("#up").click(function(){
            getData(pn-1,2);
        })
        //給下一頁新增事件
        $("#down").click(function(){
            getData(pn+1,2);
        })
        //給radio單選按鈕新增事件
        $("input[type=radio]").click(function(){
            getData(1,$(this).val());
        })
        //封裝ajax請求
        function getData(pageNum,pageSize){
            //傳送ajax請求 請求第一頁的資料
            $.get("show",{pageNum:pageNum,pageSize:pageSize,sname:$("#sname").val(),tname:$("#tname").val()},function(data){
                //使用eval方法將資料轉換為js物件
                eval("var p="+data);
                pn=p.pageNum;
                //獲取表格物件
                var ta=$("#ta");
                ta.empty();
                ta.append("<tr height='35px'>"+
                        "<td width='100px'>編號</td>"+
                        "<td width='100px'>學生姓名</td>"+
                        "<td width='100px'>年齡</td>"+
                        "<td width='100px'>教師姓名</td>"+
                    "</tr>");
                //遍歷,將資料填充到表格中
                for(var i=0;i<p.ls.length;i++){
                    ta.append("<tr height='35px'>"+
                            "<td width='100px'>"+p.ls[i].sid+"</td>"+
                            "<td width='100px'>"+p.ls[i].sname+"</td>"+
                            "<td width='100px'>"+p.ls[i].sage+"</td>"+
                            "<td width='100px'>"+p.ls[i].teacher.tname+"</td>"+
                        "</tr>");
                }
            })
        }
    })

</script>
</head>
<body>
    <input type="radio" id="" name="page" value="2" checked="checked"/>2&nbsp;&nbsp;&nbsp;
    <input type="radio" id="" name="page" value="3"/>3&nbsp;&nbsp;&nbsp;
    <input type="radio" id="" name="page" value="4"/>4&nbsp;&nbsp;&nbsp;
    <br />
    學生姓名:<input type="text" id="sname"/>&nbsp;&nbsp;&nbsp;
    教師姓名: <input type="text" id="tname"/>&nbsp;&nbsp;&nbsp;
        <input type="button" id="btn"  value="查詢"/>&nbsp;&nbsp;&nbsp;
    <hr />
    <table border="1px" cellpadding="0" cellspacing="0" id="ta"></table>
    <a href="javascript:void(0)" id="up">上一頁</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    <a href="javascript:void(0)" id="down">下一頁</a>
</body>
</html>

原始碼:

連結:https://pan.baidu.com/s/1zPvko3yKRELiQIMREhXekg 密碼:9om2

小結:

Mybatis的多表查詢
註解
快取
其他知識點
小案例

相關文章