MyBatis復雜Sql查詢實現(xiàn)示例介紹
resultMap 結果映射
resultMap 元素是 MyBatis 中最重要最強大的元素,之前所寫的 sql 語句,返回值都是簡單的基本數據類型或者某一個實體類,比如下面這段 sql 返回的就是最簡單的 User 類型。
<select id="getUserById" resultType="user" parameterType="int"> select * from user where id=#{id}; </select>
現(xiàn)在思考一下下面這種情況,如果實體類中定義的某一個字段和數據庫中的字段不一致怎么辦?
public class User { private int id; private String lastname; //..... }
比如我定義了一個 User 類,包含 id 和 lastname 兩個屬性,而數據庫中這兩個字段的名字為 id 和 name。此時再執(zhí)行查詢時結果如下:lastname 這個字段直接為 null。
這時候我們就可以使用 resultMap 來解決這個問題,resultMap 可以將數據庫中的字段映射到實體類上。column 代表數據庫中的字段名,properties 代表實體類中的字段名,通過映射之后 Mybatis 就可以找到對應的字段。
<resultMap id="UserMap" type="User"> <!--column代表數據庫中的字段名,properties代表實體類中的字段名--> <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>
準備數據
接下來結合學生與教室的案例模擬復雜場景:
//創(chuàng)建教室表 create table classroom ( id int not null AUTO_INCREMENT, classname VARCHAR(40) not null, PRIMARY KEY (id) ); //創(chuàng)建學生表 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)建一些數據 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);
多對一查詢(association)
現(xiàn)在要實現(xiàn)一個多對一的查詢需求,查詢所有的學生,并將每個學生所在的教室包含在內。由于現(xiàn)在的情況是多學生和教室的關系是多對一,因此在構建實體類時在 Student 類上要加上 ClassRoom 變量。
在 Java 的實體類代碼中分別建立 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 + '}'; } }
定義一個 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 編寫模式稱為結果嵌套查詢,首先通過一段 sql 查詢語句將需要的信息查詢出來,接著通過 resultMap 對結果進行拼接。這里使用 association 將 classRoom 的信息拼接到了 classRoom 類中,實現(xiàn)多對一查詢。
別忘了在配置類里把 mapper 映射加上,編寫測試類:
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); } }
一對多查詢(collection)
一個教室里有多個學生,如果想要查詢每個教室中的所有學生,就會用到一對多查詢。
修改兩個實體類,命名為 Student2 和 ClassRoom2,因為一個教室中有多個學生,因此在教室類中通過 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 接口和對應的 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"/> <!--對于集合屬性,需要使用collection來實現(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>
依舊是通過結果嵌套查詢的方式,通過 sql 語句查詢出結果,再通過 resultMap 進行組裝,一對多查詢用的是 collection。
在配置文件中增加 mapper 映射器之后,編寫一個測試類:
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); } }
總結成一點:對象的關聯(lián)(多對一)使用 association,集合的關聯(lián)(一對多)使用 collection。
懶加載
在上面的兩個例子中,一次 sql 查詢就將兩個表的數據一次性查詢了出來,這種方式就是即時加載。但是在某些業(yè)務場景下,可能只需要學生的信息或者教室的信息,而不需要兩者的聯(lián)表數據,這種時候就可以使用懶加載。
以上邊的 association 案例解釋懶加載的實現(xiàn)。
上邊的例子中,通過聯(lián)表查詢一次性就查詢出了學生信息和教室信息:
select s.id sid,s.name sname,c.id cid,c.classname cname from student s,classroom c where s.classid=c.id
如果想要通過懶加載實現(xiàn),就需要把 sql 語句轉換為:
select * from student; select * from classroom where id = #{classid}
按照這個思路,建立 StudentLazyMapper 類:
package com.cn.mapper; import java.util.List; import com.cn.pojo.Student; public interface StudentLazyMapper { List<Student> selectAllStudent(); }
創(chuàng)建對應的 StudentLazyMapper.xml 文件,將原先的一條 sql 轉換為兩條 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 映射,為了更好地看到懶加載效果,開啟控制臺日志輸出,完整 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> <!--每個mapper.xml都需要在mybatis配置文件中進行配置--> <mappers> <mapper resource="mapper/UserMapper.xml"/> <mapper resource="mapper/StudentMapper.xml"/> <mapper resource="mapper/StudentLazyMapper.xml"/> </mappers> </configuration>
新建一個測試類 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()); } }
這個時候是還沒開啟懶加載的,從運行結果可以看出,雖然代碼中只需要得到 student 的 id,但是卻查詢了兩張表:
在配置文件的 setting 節(jié)點下開啟懶加載的配置:
<setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="false"/>
再次運行測試代碼:
可以看到,只有 student 一張表被查詢,實現(xiàn)了懶加載
到此這篇關于MyBatis復雜Sql查詢實現(xiàn)示例介紹的文章就介紹到這了,更多相關MyBatis Sql查詢內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SpringBoot ThreadLocal 簡單介紹及使用詳解
ThreadLocal 叫做線程變量,意思是 ThreadLocal 中填充的變量屬于當前線程,該變量對其他線程而言是隔離的,也就是說該變量是當前線程獨有的變量,這篇文章主要介紹了SpringBoot ThreadLocal 的詳解,需要的朋友可以參考下2024-01-01Java案例使用集合方法實現(xiàn)統(tǒng)計任意字符串中字符出現(xiàn)的次數
這篇文章主要介紹了Java案例使用集合方法實現(xiàn)統(tǒng)計任意字符串中字符出現(xiàn)的次數,下面我們將用兩種方法實現(xiàn),需要的小伙伴可以參考一下文章具體內容2022-04-04Springboot+Flowable?快速實現(xiàn)工作流的開發(fā)流程
這篇文章主要介紹了Springboot+Flowable?快速實現(xiàn)工作流的開發(fā)流程,本文通過實例代碼圖文相結合給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-02-02Java實現(xiàn)Json字符串與Object對象相互轉換的方式總結
這篇文章主要介紹了Java實現(xiàn)Json字符串與Object對象相互轉換的方式,結合實例形式總結分析了java基于Json-Lib、Org.Json、Jackson、Gson、FastJson五種方式轉換json類型相關操作技巧,需要的朋友可以參考下2019-03-03教你如何在IDEA?中添加?Maven?項目的?Archetype(解決添加不起作用的問題)
這篇文章主要介紹了如何在?IDEA?中添加?Maven?項目的?Archetype(解決添加不起作用的問題),本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-08-08