association 实现MyBatis分步查询与延迟加载
一、分步查詢
1.1什么時候可以用到分步查詢
有的時候需要我們對數據庫進行關聯查詢,比如Employee 持有另一個Department對象的一個引用,我們希望在查詢Employee 的時候把Department也一同查詢出來。這時候我們可以編寫關聯表的SQL 語句,從而將查詢出來的數據使用resultMap進行映射。
我們也可以使用其他的方式將關聯的信息查詢出來,MyBatis 提供了分步查詢的機制,把復雜的SQL 語句簡單化。
關于MyBatis關聯查詢可參考博文:
MyBatis使用resultMap自定義映射規則與關聯映射
1.2分步查詢完成JavaBean 之間關聯
需求:在查詢Employee信息的時候,把其對應的Department信息也一并查詢出來,這里使用分步查詢的方法。使用關聯映射的方法可以參考上面鏈接內的博文。
過程分析:
1根據員工id 向員工數據庫中查詢信息,獲得員工的信息與部門的id。
2.根據部門的id 查詢部門的信息。
3.對查詢的信息進行封裝。
由此可見,實現分步查詢的方法就是將復雜的SQL 語句拆分成簡單的多個SQL 語句,在某個SQL 執行結果的基礎上再進行數據查詢。
1.數據庫表結構:
t_employee 數據庫表結構(其中d_id用于關聯t_dept表 中的id):
DROP TABLE IF EXISTS `t_employee`; CREATE TABLE `t_employee` (`id` int(11) unsigned zerofill NOT NULL AUTO_INCREMENT,`username` varchar(30) DEFAULT NULL,`gender` char(1) DEFAULT NULL,`email` varchar(20) DEFAULT NULL,`d_id` int(11) DEFAULT NULL,PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8;t_dept數據庫表結構:
DROP TABLE IF EXISTS `t_dept`; CREATE TABLE `t_dept` (`id` int(11) NOT NULL AUTO_INCREMENT,`dept_name` varchar(20) DEFAULT NULL,PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;2.定義JavaBean
Employee類:
package com.jas.mybatis.bean;public class Employee {private Integer id;private String username;private Character gender;private String email;private Department department;// 省略set、get 與toString 方法 }Department類:
package com.jas.mybatis.bean;public class Department {private Integer id;private String departmentName;// 省略set、get 與toString 方法 }3.定義mapper 接口
EmployeeMapper 接口:
package com.jas.mybatis.mapper;import com.jas.mybatis.bean.Employee;public interface EmployeeMapper {/*** 根據員工id 獲取員工信息以及對應的部門信息* * @param id* @return*/Employee getEmpAndDeptById(Integer id); }DepatmentMapper 接口:
package com.jas.mybatis.mapper;import com.jas.mybatis.bean.Department;public interface DepatmentMapper {/*** 根據部門id 獲得部門信息* * @param id* @return*/Department getDeptById(Integer id); }4.編寫SQL 語句
DepartmentMpper.xmlSQL 映射文件:
<mapper namespace="com.jas.mybatis.mapper.DepatmentMapper"><!-- 根據部門的id 獲得部門信息 --><select id="getDeptById" resultType="com.jas.mybatis.bean.Department">SELECT id, dept_name departmentName FROM t_dept WHERE id = #{id}</select> </mapper>EmployeeMapper.xmlSQL 映射文件:
<mapper namespace="com.jas.mybatis.mapper.EmployeeMapper"><resultMap type="com.jas.mybatis.bean.Employee" id="BaseEmployeeResultMap"><!-- 進行數據庫字段與JavaBean 屬性映射 --><id column="id" property="id"/><result column="username" property="username"/><result column="gender" property="gender"/><result column="email" property="email"/><!--使用association 標簽完成分步查詢property:Employee 類中對應的屬性departmentselect:另外一個映射語句的 ID,也就是DepartmentMpper.xml 中的getDeptByIdcolumn:表示數據庫中的哪個字段名作為參數傳給select 中的SQL 語句,如果要傳遞多個參數,可以把多個參數封裝成map,比如:{id = d_id, ...}分析:執行流程是先根據員工的id 查詢到數據庫中的信息,將對應的員工信息先進行映射封裝,然后根據d_id 字段值,去部門表中查詢部門信息,然后再對部門信息進行映射封裝,從而獲得完整的員工信息。--><association property="department" column="d_id"select="com.jas.mybatis.mapper.DepatmentMapper.getDeptById"><!--將數據庫中的部門信息映射到Employee 類中的部門信息屬性中--><id column="d_id" property="id"/><result column="dept_name" property="departmentName"/></association></resultMap><select id="getEmpAndDeptById" resultMap="BaseEmployeeResultMap">SELECT * FROM t_employee WHERE id = #{id}</select> </mapper>5.測試代碼:
private SqlSession getSqlSession() throws IOException {String resource = "mybatis-config.xml";InputStream is = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);SqlSession sqlSession = sqlSessionFactory.openSession();return sqlSession;}@Testpublic void resultMapTest01() throws IOException {SqlSession sqlSession = getSqlSession();EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);Employee employee = employeeMapper.getEmpAndDeptById(1);System.out.println(employee);sqlSession.close();}6.查看結果:
從上面的執行結果可以看出在進行Employee查詢結果信息封裝的時候,向數據庫發了兩條SQL 語句,分別獲得員工信息與部門信息。通過把復雜的關聯SQL 語句進行分步,最終完成了分步查詢。
一般情況下Department getDeptById(Integer id);方法在實際的開發過程中是必須要定義的一個方法,這樣在進行關聯查詢的時候,我們只要使用現成的方法即可,不需要再定義復雜的關聯SQL 語句。分步查詢還有一個好處就是可以實現延遲加載,這個延遲加載功能在MyBatis 中可以說是一個非常重要的功能。
下面我們就來看看分步查詢是如何完成延遲加載的。
二、延遲加載
2.1什么是延遲加載
延遲加載也可以理解為按需加載。即在你需要的時候才進行的加載方式,才會向數據庫發送SQL 語句,不需要的時候不會向數據庫中發送SQL。這樣做可以用于減輕數據庫的壓力。
比如上面的分步查詢,我們通過分步查詢分別查詢出了員工信息與部門信息,并把這些信息封裝成了一個Employee對象。如果我們并不需要查詢員工的部門信息,在查詢員工信息的時候,由于分步查詢了部門信息,所以這時候部門信息也會被查出來,但是查詢出來的部門信息是不需要的。本來向數據庫發送一條SQL 語句就可以了,這時候發送了兩條。顯然這樣做不是好的解決辦法,這時候我們就可以使用延遲加載。
2.2實現延遲加載
其實在MyBais 中實現延遲加載的功能是很容易的,只需要在全局的配置文件中進行對應的setting設置即可。
<settings><!-- 延遲加載的全局開關。當開啟時,所有關聯對象都會延遲加載,默認為false --><setting name="lazyLoadingEnabled" value="true"/><!-- 設置屬性按需加載 --><setting name="aggressiveLazyLoading" value="false"/></settings>你有沒有覺得還需要點什么,其實只要配置了上面的兩個屬性,延遲加載就已經開啟了。
2.3測試:
如果我們只要獲得員工的姓名:
// 省略了 getSqlSession() 方法@Testpublic void resultMapTest01() throws IOException {SqlSession sqlSession = getSqlSession();EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);Employee employee = employeeMapper.getEmpAndDeptById(1);System.out.println(employee.getUsername());sqlSession.close(); }執行結果:
開啟延遲加載后只發送了一條SQL 語句。
下面我們來看看在沒有開啟延遲加載的情況下獲得員工的姓名:
發現即使你不想要獲得員工的部門信息,由于執行的是分步查詢,所以還是會發送兩條SQL 語句,這顯然不是我們想要的。
如果我們想要獲得員工的部門信息:
@Testpublic void resultMapTest01() throws IOException {SqlSession sqlSession = getSqlSession();EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);Employee employee = employeeMapper.getEmpAndDeptById(1);System.out.println(employee.getDepartment());sqlSession.close();}執行結果:
因為要獲得部門信息,必須先根據員工的id 獲得員工的部門id ,在根據部門id 獲得部門信息,因此發送了兩條SQL,所以只有在你需要部門信息的時候才會發送查詢部門信息的SQL。
三、總結
這篇博文主要對resultMap中的association標簽實現分步查詢的方式進行了實現,并對分步查詢中的延遲加載機制進行了實現。不管是分步查詢還是延遲加載都是MyBatis 中很重要的知識,希望讀者能夠通過這篇博客學習到一些知識,這也是一直支持著我寫博客的原因。
總結
以上是生活随笔為你收集整理的association 实现MyBatis分步查询与延迟加载的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 复制的文件怎么安装系统文件在哪里 复制文
- 下一篇: foreach 实现 MyBatis 遍