MyBatis 實現多表查詢
- Mybatis 實現多表查詢方式
- 業務裝配. 對__兩個表編寫單表查詢語句__,在業務(Service)把查詢的兩個結果進行關聯
- 使用AutoMapping特性,在實現兩表聯合查詢時通過別名完成映射
- 使用 MyBatis 的標籤進行實現
- 多表查詢時,類中包含另一個類的對象的分類
- 單個對象
- 集合對象
resultMap 標籤
- 標籤寫在mapper.xml中,由程序員控制SQL查詢結果與實體類的映射關係
- 默認 MyBatis 使用 AutoMapping 特性(resultType)
- 使用標籤時,標籤不寫 resultType 屬性,而是使用 resultMap 屬性引用標籤
resultMap實現單表映射
使用 resultMap 實現單表映射關係(單從本例看不出什麼)
+ 數據庫設計:teacher(id,name)
+ 實體類設計(使用resultMap方式的話不要求屬性名和列名相同,但最好還是一樣)
public class Teacher{
private int id1;
private String name1;
}
- mapper.xml 代碼
<resultMap type="teacher" id="mymap">
<!-- 主鍵使用 id 標籤配置映射關係 -->
<id column="id" property="id1" />
<!-- 其他列使用 result 標籤配置映射關係 -->
<result column="name" property="name1"/>
</resultMap>
<select id="selAll" resultMap="mymap">
select * from teacher
</select>
resultMap關聯單個對象
使用 resultMap 實現關聯單個對象(N+1 方式)
- N+1 查詢方式,先查詢出某個表的全部信息,根據這個表的信息查詢另一個表的信息
- 與業務裝配的區別:
- 在 service 裏面寫的代碼,由 mybatis 完成裝配
- 實現步驟:
- 在 Student 實現類中包含了一個 Teacher 對象
public class Student {
private int id;
private String name;
private int age;
private int tid;
private Teacher teacher; // N+1
...
}
- 在 TeacherMapper 中提供一個查詢
<select id="selById" resultType="teacher" parameterType="int">
select * from teacher where id=#{0}
</select>
- 在 StudentMapper 中
- 裝配一個對象時使用
- property屬性: 對象在類中的屬性名
- select屬性:通過哪個查詢查詢出這個對象的信息
- column屬性: 把當前表的哪個列的值做爲參數傳遞給另一個查詢
- 大前提:使用 N+1 方式時如果列名和屬性名相同可以不配置,使用 Automapping 特性.但是mybatis 默認只會給列專配一次
<resultMap type="student" id="stuMap">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<result property="tid" column="tid"/>
<!-- 如果關聯一個對象 -->
<association
property="teacher"
select="com.buendia.mapper.TeacherMapper.selById"
column="tid">
</association>
</resultMap>
<select id="selAll" resultMap="stuMap">
select * from student
</select>
把上面代碼簡化成
<resultMap type="student" id="stuMap">
<!-- tid在下邊也引用到了,如果列和屬性名相同,可以省略,並且mybatis用automapping,但只會一次 -->
<result column="tid" property="tid"/>
<!-- 如果關聯一個對象 -->
<association
property="teacher"
select="com.buendia.mapper.TeacherMapper.selById"
column="tid">
</association>
</resultMap>
<select id="selAll" resultMap="stuMap">
select * from student
</select>
resultMap關聯單個對象(聯合查詢方式)
使用 resultMap 實現關聯單個對象(聯合查詢方式)
- 只需要編寫一個 SQL,在 StudentMapper 中添加下面效果
- 只要__專配一個對象就用這個標籤__
- 此時把當做小的看待
- javaType 屬性:< association/>專配完後返回一個什麼類型的對象.取值是一個類(或類的別名)
<resultMap type="Student" id="stuMap1">
<id column="sid" property="id"/>
<result column="sname" property="name"/>
<result column="age" property="age"/>
<result column="tid" property="tid"/>
<association property="teacher" javaType="Teacher" >
<id column="tid" property="id"/>
<result column="tname" property="name"/>
</association>
</resultMap>
<select id="selAll1" resultMap="stuMap1">
select s.id sid,s.name sname,age age,t.id tid,t.name tname
FROM student s left outer join teacher t on s.tid=t.id
</select>
N+1 方式和聯合查詢方式對比
- N+1:需求不確定時
- 聯合查詢:需求中確定查詢時兩個表一定都查詢
- N+1 名稱由來
- 舉例:學生中有 3 條數據
- 需求:查詢所有學生信息及授課老師信息
- 需要執行的 SQL 命令
- 查詢全部學生信息:select * from 學生
- 執行 3 遍 select * from 老師 where id = 學生的外鍵
- 使用多條 SQl 命令查詢兩表數據時,如果希望把需要的數據都查詢出來,需要執行 N+1 條 SQl 才能把所有數據庫查詢出來
- 缺點:
- 效率低
- 優點:
- 如果有的時候不需要查詢學生的同時查詢老師.只需要執行一個
select * from student;
- 如果有的時候不需要查詢學生的同時查詢老師.只需要執行一個
- 適用場景: 有的時候需要查詢學生同時查詢老師,有的時候只需要查詢學生
- 如何解決 N+1 查詢帶來的效率低的問題
- 默認帶的前提: 每次都是兩個都查詢
- 使用兩表聯合查詢
resultMap關聯集合對象
- 在 Teacher 中添加 List
public class Teacher {
private int id;
private String name;
private List<Student> list;
...
}
- 在 StudentMapper.xml 中添加通過 tid 查詢
<select id="selByTid" parameterType="int" resultType="student">
select * from student where tid=#{0}
</select>
- 在 TeacherMapper.xml 中添加查詢全部
- 當__屬性是集合類型時使用的標籤__
<resultMap type="teacher" id="mymap">
<id column="id" property="id"/>
<result column="name" property="name"/>
<collection
property="list"
select="com.bjsxt.mapper.StudentMapper.selByTid"
column="id">
</collection>
</resultMap>
<select id="selAll" resultMap="mymap">
select * from teacher
</select>
resultMap實現加載集合數據(聯合查詢方式)
- 在 teacherMapper.xml 中添加
- mybatis 可以通過主鍵判斷對象是否被加載過
- 不需要擔心創建重複 Teacher
<resultMap type="teacher" id="mymap1">
<id column="tid" property="id"/>
<result column="tname" property="name"/>
<collection property="students" ofType="student" > <!--property原來爲list,不對的話換下-->
<id column="sid" property="id"/>
<result column="sname" property="name"/>
<result column="age" property="age"/>
<result column="tid" property="tid"/>
</collection>
</resultMap>
<select id="selAll1" resultMap="mymap1">
select t.id tid,t.name tname,s.id sid,s.name sname,age,tid
from teacher t LEFT JOIN student s on t.id=s.tid;
</select>
使用 AutoMapping 結合別名實現多表查詢
- 只能使用多表聯合查詢方式
- 要求:查詢出的列別名和屬性名相同
- 實現方式
- 在 SQL 是關鍵字符,兩側添加反單引號
<select id="selAll" resultType="student">
select t.id `teacher.id`,t.name `teacher.name`,s.id id,s.name name,age,tid
from student s LEFT JOIN teacher t on t.id=s.tid
</select>