MyBatis復(fù)雜Sql查詢實(shí)現(xiàn)示例介紹
resultMap 結(jié)果映射
resultMap 元素是 MyBatis 中最重要最強(qiáng)大的元素,之前所寫的 sql 語(yǔ)句,返回值都是簡(jiǎn)單的基本數(shù)據(jù)類型或者某一個(gè)實(shí)體類,比如下面這段 sql 返回的就是最簡(jiǎn)單的 User 類型。
<select id="getUserById" resultType="user" parameterType="int">
select * from user where id=#{id};
</select>
現(xiàn)在思考一下下面這種情況,如果實(shí)體類中定義的某一個(gè)字段和數(shù)據(jù)庫(kù)中的字段不一致怎么辦?
public class User {
private int id;
private String lastname;
//.....
}
比如我定義了一個(gè) User 類,包含 id 和 lastname 兩個(gè)屬性,而數(shù)據(jù)庫(kù)中這兩個(gè)字段的名字為 id 和 name。此時(shí)再執(zhí)行查詢時(shí)結(jié)果如下:lastname 這個(gè)字段直接為 null。
這時(shí)候我們就可以使用 resultMap 來(lái)解決這個(gè)問(wèn)題,resultMap 可以將數(shù)據(jù)庫(kù)中的字段映射到實(shí)體類上。column 代表數(shù)據(jù)庫(kù)中的字段名,properties 代表實(shí)體類中的字段名,通過(guò)映射之后 Mybatis 就可以找到對(duì)應(yīng)的字段。
<resultMap id="UserMap" type="User">
<!--column代表數(shù)據(jù)庫(kù)中的字段名,properties代表實(shí)體類中的字段名-->
<result column="id" property="id"/>
<result column="name" property="lastname"/>
</resultMap>
<select id="getUserById" resultMap="UserMap" parameterType="int">
select * from user where id=#{id};
</select>
準(zhǔn)備數(shù)據(jù)
接下來(lái)結(jié)合學(xué)生與教室的案例模擬復(fù)雜場(chǎng)景:
//創(chuàng)建教室表 create table classroom ( id int not null AUTO_INCREMENT, classname VARCHAR(40) not null, PRIMARY KEY (id) ); //創(chuàng)建學(xué)生表 create table student ( id int not null AUTO_INCREMENT, name VARCHAR(40) not null, classid int not null, PRIMARY KEY (id), FOREIGN key (classid) REFERENCES classroom(id) ); //創(chuàng)建一些數(shù)據(jù) insert into classroom VALUES (1,'101班'); insert into classroom VALUES (2,'102班'); insert into student VALUES(1,'Amy',1); insert into student VALUES(2,'Bob',1); insert into student VALUES(3,'javayz',1);
多對(duì)一查詢(association)
現(xiàn)在要實(shí)現(xiàn)一個(gè)多對(duì)一的查詢需求,查詢所有的學(xué)生,并將每個(gè)學(xué)生所在的教室包含在內(nèi)。由于現(xiàn)在的情況是多學(xué)生和教室的關(guān)系是多對(duì)一,因此在構(gòu)建實(shí)體類時(shí)在 Student 類上要加上 ClassRoom 變量。
在 Java 的實(shí)體類代碼中分別建立 Student 和 ClassRoom 的類:
package com.cn.pojo;
public class ClassRoom {
private int id;
private String classname;
public ClassRoom(){}
public int getId() {
return id;
}
public String getClassname() {
return classname;
}
public void setId(int id) {
this.id = id;
}
public void setClassname(String classname) {
this.classname = classname;
}
@Override
public String toString() {
return "ClassRoom{" +
"id=" + id +
", classname='" + classname + '\'' +
'}';
}
}package com.cn.pojo;
public class Student {
private int id;
private String name;
private ClassRoom classRoom;
public Student(){}
public int getId() {
return id;
}
public String getName() {
return name;
}
public ClassRoom getClassRoom() {
return classRoom;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setClassRoom(ClassRoom classRoom) {
this.classRoom = classRoom;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", classRoom=" + classRoom +
'}';
}
}定義一個(gè) StudentMapper 接口:
package com.cn.mapper;
import java.util.List;
import com.cn.pojo.Student;
public interface StudentMapper {
List<Student> selectAllStudent();
}
編寫 StudentMapper.xml
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cn.mapper.StudentMapper">
<select id="selectAllStudent" resultMap="StudentAndClassRoom">
select s.id sid,s.name sname,c.id cid,c.classname cname
from student s,classroom c
where s.classid=c.id
</select>
<resultMap id="StudentAndClassRoom" type="com.cn.pojo.Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="classRoom" javaType="com.cn.pojo.ClassRoom">
<result property="id" column="cid"/>
<result property="classname" column="cname"/>
</association>
</resultMap>
</mapper>上面的這種 sql 編寫模式稱為結(jié)果嵌套查詢,首先通過(guò)一段 sql 查詢語(yǔ)句將需要的信息查詢出來(lái),接著通過(guò) resultMap 對(duì)結(jié)果進(jìn)行拼接。這里使用 association 將 classRoom 的信息拼接到了 classRoom 類中,實(shí)現(xiàn)多對(duì)一查詢。
別忘了在配置類里把 mapper 映射加上,編寫測(cè)試類:
public class StudentMapperTest {
public static void main(String[] args) {
// 獲取SqlSession
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> students = mapper.selectAllStudent();
System.out.println(students);
}
}一對(duì)多查詢(collection)
一個(gè)教室里有多個(gè)學(xué)生,如果想要查詢每個(gè)教室中的所有學(xué)生,就會(huì)用到一對(duì)多查詢。
修改兩個(gè)實(shí)體類,命名為 Student2 和 ClassRoom2,因?yàn)橐粋€(gè)教室中有多個(gè)學(xué)生,因此在教室類中通過(guò) List<Student2> 的方式引入 Student2 類
public class Student2 {
private int id;
private String name;
private int classId;
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", classId=" + classId +
'}';
}
}import java.util.List;
public class ClassRoom2 {
private int id;
private String classname;
private List<Student2> students;
@Override
public String toString() {
return "ClassRoom{" +
"id=" + id +
", classname='" + classname + '\'' +
", students=" + students +
'}';
}
}接著編寫 Mapper 接口和對(duì)應(yīng)的 Mapper.xml
import java.util.List;
import com.cn.pojo.ClassRoom2;
public interface ClassRoomMapper {
List<ClassRoom2> getClassRoomByid( int id);
}<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cn.mapper.ClassRoomMapper">
<select id="getClassRoomByid" resultMap="ClassRoomAndStudent" parameterType="int">
select c.id cid,c.classname cname,s.id sid,s.name sname,s.classid classid
from student s,classroom c
where s.classid=c.id and c.id=#{id}
</select>
<resultMap id="ClassRoomAndStudent" type="com.cn.pojo.ClassRoom2">
<result property="id" column="cid"/>
<result property="classname" column="cname"/>
<!--對(duì)于集合屬性,需要使用collection來(lái)實(shí)現(xiàn)-->
<collection property="students" ofType="com.cn.pojo.Student2">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="classId" column="classid"/>
</collection>
</resultMap>
</mapper>
依舊是通過(guò)結(jié)果嵌套查詢的方式,通過(guò) sql 語(yǔ)句查詢出結(jié)果,再通過(guò) resultMap 進(jìn)行組裝,一對(duì)多查詢用的是 collection。
在配置文件中增加 mapper 映射器之后,編寫一個(gè)測(cè)試類:
public class TeacherMapperTest {
public static void main(String[] args) {
// 獲取SqlSession
SqlSession sqlSession = MyBatisUtils.getSqlSession();
ClassRoomMapper mapper = sqlSession.getMapper(ClassRoomMapper.class);
List<ClassRoom2> classRoom = mapper.getClassRoomByid(1);
System.out.println(classRoom);
}
}
總結(jié)成一點(diǎn):對(duì)象的關(guān)聯(lián)(多對(duì)一)使用 association,集合的關(guān)聯(lián)(一對(duì)多)使用 collection。
懶加載
在上面的兩個(gè)例子中,一次 sql 查詢就將兩個(gè)表的數(shù)據(jù)一次性查詢了出來(lái),這種方式就是即時(shí)加載。但是在某些業(yè)務(wù)場(chǎng)景下,可能只需要學(xué)生的信息或者教室的信息,而不需要兩者的聯(lián)表數(shù)據(jù),這種時(shí)候就可以使用懶加載。
以上邊的 association 案例解釋懶加載的實(shí)現(xiàn)。
上邊的例子中,通過(guò)聯(lián)表查詢一次性就查詢出了學(xué)生信息和教室信息:
select s.id sid,s.name sname,c.id cid,c.classname cname from student s,classroom c where s.classid=c.id
如果想要通過(guò)懶加載實(shí)現(xiàn),就需要把 sql 語(yǔ)句轉(zhuǎn)換為:
select * from student;
select * from classroom where id = #{classid}
按照這個(gè)思路,建立 StudentLazyMapper 類:
package com.cn.mapper;
import java.util.List;
import com.cn.pojo.Student;
public interface StudentLazyMapper {
List<Student> selectAllStudent();
}創(chuàng)建對(duì)應(yīng)的 StudentLazyMapper.xml 文件,將原先的一條 sql 轉(zhuǎn)換為兩條 sql:
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cn.mapper.StudentLazyMapper">
<select id="selectAllStudent" resultMap="studentAndClassRoom">
select * from student
</select>
<resultMap id="studentAndClassRoom" type="com.cn.pojo.Student">
<id property="id" column="id"/>
<result property="name" column="name"/>
<association property="classRoom" javaType="com.cn.pojo.ClassRoom" column="classid" select="selectClassRoomById">
<result property="id" column="id"/>
<result property="classname" column="classname"/>
</association>
</resultMap>
<select id="selectClassRoomById" resultType="com.cn.pojo.ClassRoom">
select * from classroom where id = #{classid}
</select>
</mapper>在 mybatis-config.xml 中增加 mapper 映射,為了更好地看到懶加載效果,開(kāi)啟控制臺(tái)日志輸出,完整 xml 如下:
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</dataSource>
</environment>
</environments>
<!--每個(gè)mapper.xml都需要在mybatis配置文件中進(jìn)行配置-->
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
<mapper resource="mapper/StudentMapper.xml"/>
<mapper resource="mapper/StudentLazyMapper.xml"/>
</mappers>
</configuration>新建一個(gè)測(cè)試類 StudentMapperLazyTest:
public class StudentMapperLazyTest {
public static void main(String[] args) {
// 獲取SqlSession
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentLazyMapper mapper = sqlSession.getMapper(StudentLazyMapper.class);
List<Student> students = mapper.selectAllStudent();
System.out.println(students.get(0).getId());
}
}
這個(gè)時(shí)候是還沒(méi)開(kāi)啟懶加載的,從運(yùn)行結(jié)果可以看出,雖然代碼中只需要得到 student 的 id,但是卻查詢了兩張表:

在配置文件的 setting 節(jié)點(diǎn)下開(kāi)啟懶加載的配置:
<setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="false"/>
再次運(yùn)行測(cè)試代碼:

可以看到,只有 student 一張表被查詢,實(shí)現(xiàn)了懶加載
到此這篇關(guān)于MyBatis復(fù)雜Sql查詢實(shí)現(xiàn)示例介紹的文章就介紹到這了,更多相關(guān)MyBatis Sql查詢內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java實(shí)戰(zhàn)之自助進(jìn)行多張圖片合成拼接
在當(dāng)今數(shù)字化時(shí)代,圖像處理技術(shù)在各個(gè)領(lǐng)域都發(fā)揮著至關(guān)重要的作用,本文為大家詳細(xì)介紹了如何使用Java實(shí)現(xiàn)多張圖片合成拼接,需要的可以了解下2025-02-02
SpringCloud-Hystrix-Dashboard客戶端服務(wù)監(jiān)控的實(shí)現(xiàn)方法
這篇文章主要介紹了SpringCloud-Hystrix-Dashboard客戶端服務(wù)監(jiān)控的實(shí)現(xiàn)方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03
SpringBoot3整合pageHelper實(shí)現(xiàn)分頁(yè)功能
PageHelper是一個(gè)開(kāi)源的Java分頁(yè)插件,它提供了方便的分頁(yè)查詢功能,適用于大多數(shù)基于Java的持久層框架(如MyBatis、Hibernate等),本文給大家介紹了springboot3整合pageHelper實(shí)現(xiàn)分頁(yè)功能的方法,需要的朋友可以參考下2024-08-08
Java如何跳過(guò)https的ssl證書驗(yàn)證詳解
這篇文章主要介紹了Java跳過(guò)https的ssl證書驗(yàn)證的解決思路,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,下面我們來(lái)深入學(xué)習(xí)下吧2019-06-06
JavaFX實(shí)現(xiàn)拖拽結(jié)點(diǎn)效果
這篇文章主要為大家詳細(xì)介紹了JavaFX實(shí)現(xiàn)拖拽結(jié)點(diǎn)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-12-12

