MyBatis框架關(guān)聯(lián)映射實(shí)例詳解
關(guān)系映射
1. 關(guān)聯(lián)映射概述
在關(guān)系型數(shù)據(jù)庫中,多表之間存在著三種關(guān)聯(lián)關(guān)系,分別為一對一,一對多和多對多,如圖

- 一對一的關(guān)系:就是在本類中定義對方類型的對象,如A類中定義B類類型的屬性b,B類中定義A類類型的屬性a。
- 一對多的關(guān)系:就是一個(gè)A類類型對應(yīng)多個(gè)B類類型的情況,需要在A類中以集合的方式引入B類類型的對象,在B類中定義A類類型的屬性a。
- 多對多的關(guān)系:在A類中定義B類類型的集合,在B類中定義A類類型的集合。
2. 環(huán)境搭建
創(chuàng)建t_emp表

t_dept表

實(shí)體類Dept
package com.atguigu.mybatis.pojo;
import java.util.List;
public class Dept {
private Integer deptId;
private String deptName;
private List<Emp> emps;
public Dept() {
}
public Dept(Integer deptId, String deptName) {
this.deptId = deptId;
this.deptName = deptName;
}
public Integer getDeptId() {
return deptId;
}
public void setDeptId(Integer deptId) {
this.deptId = deptId;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public List<Emp> getEmps() {
return emps;
}
public void setEmps(List<Emp> emps) {
this.emps = emps;
}
@Override
public String toString() {
return "Dept{" +
"deptId=" + deptId +
", deptName='" + deptName + '\'' +
", emps=" + emps +
'}';
}
}實(shí)體類Emp
package com.atguigu.mybatis.pojo;
public class Emp {
private Integer empId;
private String empName;
private Integer age;
private String gender;
private Dept dept;
public Emp() {
}
public Emp(Integer empId, String empName, Integer age, String gender) {
this.empId = empId;
this.empName = empName;
this.age = age;
this.gender = gender;
}
public Integer getEmpId() {
return empId;
}
public void setEmpId(Integer empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Emp{" +
"empId=" + empId +
", empName='" + empName + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
", dept=" + dept +
'}';
}
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
}
3.處理字段名和屬性名不一致的情況
SQL語句

接口:
public interface EmpMapper {
Emp getEmpById(@Param("empId") Integer empId);
}測試方法:
public void test(){
SqlSessionUtils sqlSessionUtils = new SqlSessionUtils();
SqlSession sqlSession = sqlSessionUtils.getSqlSession();
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
Emp empById = mapper.getEmpById(1);
System.out.println(empById.toString());
}執(zhí)行測試方法后會得到如下結(jié)果:

可以看到,我們的SQl語句并沒有問題,但為什么查詢出的結(jié)果會有NUll出現(xiàn)呢,這就是因?yàn)槲覀兊?strong>數(shù)據(jù)庫中的字段名于Emp實(shí)體類的屬性名不一致,因此出現(xiàn)了無法對應(yīng)的情況。
解決辦法:
1.可以通過為字段起別名的方式,保證和實(shí)體類中的屬性名保持一致
select emp_id empId,emp_name empName,age,gender from t_emp where emp_id = #{empId};再次執(zhí)行嘗試:

2.可以在MyBatis的核心配置文件中設(shè)置一個(gè)全局配置信息mapUnderscoreToCamelCase,
此屬性可以在查詢表中數(shù)據(jù)時(shí),自動(dòng)將_類型的字段名,即下劃線轉(zhuǎn)換為駝峰
舉個(gè)栗子:
例如:字段名user_id,設(shè)置了mapUnderscoreToCamelCase,此時(shí)字段名就會轉(zhuǎn)換為userId

<resultMap id="empResultMap" type="Emp">
<id property="empId" column="emp_id"></id>
<result property="empName" column="emp_name"></result>
<result property="age" column="age"></result>
<result property="gender" column="gender"></result>
</resultMap>
<select id="getEmpById" resultMap="empResultMap">
select * from t_emp where emp_id = #{empId};
</select>4. 處理一對一映射
調(diào)節(jié)數(shù)據(jù)庫字段與實(shí)體類的屬性對應(yīng)需要標(biāo)簽resultMap,如上文那個(gè)簡單的查詢例子就可以這樣寫:
<resultMap id="empResultMap" type="Emp">
<id property="empId" column="emp_id"></id>
<result property="empName" column="emp_name"></result>
<result property="age" column="age"></result>
<result property="gender" column="gender"></result>
</resultMap>
<select id="getEmpById" resultMap="empResultMap">
select * from t_emp where emp_id = #{empId};
</select>屬性:
- id:表示自定義映射的唯一標(biāo)識
- type:查詢的數(shù)據(jù)要映射的實(shí)體類的類型
子標(biāo)簽:
- id:設(shè)置主鍵的映射關(guān)系
- result:設(shè)置普通字段的映射關(guān)系
- association :設(shè)置多對一的映射關(guān)系
- collection:設(shè)置一對多的映射關(guān)系
屬性:
- property:設(shè)置映射關(guān)系中實(shí)體類中的屬性名
- column:設(shè)置映射關(guān)系中表中的字段名
5. 處理多對一映射
5.1 級聯(lián)方式處理
<resultMap id="empAndDeptResultMap" type="Emp">
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
<!--部門中的字段dept_id與Emp實(shí)體類中的屬性dept中的deptId相對應(yīng) -->
<!--部門中的字段dept_name與Emp實(shí)體類中的屬性dept中的deptName相對應(yīng) -->
<result column="dept_id" property="dept.deptId"></result>
<result column="dept_name" property="dept.deptName"></result>
</resultMap>
<select id="getEmpAndDeptById" resultMap="empAndDeptResultMap">
SELECT t_emp.*,t_dept.* FROM t_emp
LEFT JOIN t_dept
ON t_emp.dept_id=t_dept.dept_id
where t_emp.emp_id=#{empId}
</select>接口:

測試方法:
public void test(){
SqlSessionUtils sqlSessionUtils = new SqlSessionUtils();
SqlSession sqlSession = sqlSessionUtils.getSqlSession();
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
Emp empAndDeptById = mapper.getEmpAndDeptById(1);
System.out.println(empAndDeptById);
}查詢結(jié)果:

5.2 使用association處理映射關(guān)系
<resultMap id="empAndDeptResultMap" type="Emp">
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
<association property="dept" javaType="Dept">
<id column="dept_id" property="deptId"></id>
<result column="dept_name" property="deptName"></result>
</association>
</resultMap>5.3 分步查詢
第一步:查詢員工信息

<resultMap id="empAndDeptByStepResultMap" type="Emp">
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
<association property="dept"
select="com.atguigu.mybatis.mapper.DeptMapper.getDeptByStep" column="dept_id">
</association>
</resultMap>
<select id="getEmpAndDeptByStep" resultMap="empAndDeptByStepResultMap">
select * from t_emp where emp_id=#{empId};
</select>注意:
select:設(shè)置分步查詢,查詢某個(gè)屬性的值的sql的標(biāo)識(namespace.sqlid)
column:將sql以及查詢結(jié)果中的某個(gè)字段設(shè)置為分步查詢的條件
第二步:根據(jù)員工所對應(yīng)的部門 id 查詢部門信息

<select id="getDeptByStep" resultType="com.atguigu.mybatis.pojo.Dept">
select * from t_dept where dept_id=#{deptId};
</select>測試方法:
public void test(){
SqlSessionUtils sqlSessionUtils = new SqlSessionUtils();
SqlSession sqlSession = sqlSessionUtils.getSqlSession();
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
Emp empAndDeptByStep = mapper.getEmpAndDeptByStep(1);
System.out.println(empAndDeptByStep);
}執(zhí)行結(jié)果:

分步查詢的優(yōu)點(diǎn):可以實(shí)現(xiàn)延遲加載
但是必須在核心配置文件中設(shè)置全局配置信息:
lazyLoadingEnabled:延遲加載的全局開關(guān)。當(dāng)開啟時(shí),所有關(guān)聯(lián)對象都會延遲加載aggressiveLazyLoading:當(dāng)開啟時(shí),任何方法的調(diào)用都會加載該對象的所有屬性。否則,每個(gè)屬性會按需加載- 此時(shí)就可以實(shí)現(xiàn)按需加載,獲取的數(shù)據(jù)是什么,就只會執(zhí)行相應(yīng)的 sql 。此時(shí)可通 association和 collection 中的
fetchType屬性設(shè)置當(dāng)前的分步查詢是否使用延遲加載, fetchType=“lazy(延遲加載) | eager(立即加載)”

6. 處理一對多查詢
接口:

使用collection處理
- collection :設(shè)置一對多的映射關(guān)系
- ofType :設(shè)置 collection 標(biāo)簽所處理的集合屬性中存儲數(shù)據(jù)的類型
<resultMap id="DeptAndEmpByDeptIdResultMap" type="Dept">
<id column="dept_id" property="deptId"></id>
<result column="dept_name" property="deptName"></result>
<collection property="emps" ofType="Emp">
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
</collection>
</resultMap>
<select id="getDeptAndEmpByDeptId" resultMap="DeptAndEmpByDeptIdResultMap">
SELECT t_emp.*,t_dept.* FROM t_dept
LEFT JOIN t_emp
ON t_emp.dept_id=t_dept.dept_id
WHERE t_dept.dept_id=#{deptId}
</select>測試:
public void test4(){
SqlSessionUtils sqlSessionUtils = new SqlSessionUtils();
SqlSession sqlSession = sqlSessionUtils.getSqlSession();
DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
Dept deptAndEmpByDeptId = mapper.getDeptAndEmpByDeptId(1);
System.out.println(deptAndEmpByDeptId);
}執(zhí)行結(jié)果:

7. 小結(jié)
關(guān)系映射主要處理復(fù)雜的SQl查詢,如子查詢,多表聯(lián)查等復(fù)雜查詢,應(yīng)用此種需求時(shí)可以考慮使用。
到此這篇關(guān)于MyBatis框架關(guān)聯(lián)映射的文章就介紹到這了,更多相關(guān)MyBatis關(guān)聯(lián)映射內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java SpringCache+Redis緩存數(shù)據(jù)詳解
本篇文章主要介紹了淺談SpringCache與redis緩存數(shù)據(jù)的解決方案,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2021-10-10
Java增強(qiáng)for循環(huán)的增刪操作代碼
Foreach循環(huán)(Foreach loop)是計(jì)算機(jī)編程語言中的一種控制流程語句,通常用來循環(huán)遍歷數(shù)組或集合中的元素,本文通過實(shí)例演示普通for循環(huán)和foreach循環(huán)使用,java增強(qiáng)for循環(huán)的操作代碼感興趣的朋友一起看看吧2024-02-02
Spring MVC學(xué)習(xí)筆記之Controller查找(基于Spring4.0.3)
這篇文章主要給大家介紹了關(guān)于Spring MVC學(xué)習(xí)筆記之Controller查找(基于Spring4.0.3)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2018-03-03
Java?Spring的核心與設(shè)計(jì)思想你知道嗎
這篇文章主要為大家詳細(xì)介紹了Java?Spring的核心與設(shè)計(jì)思想,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-03-03
示例解析java重載Overloading與覆蓋Overriding
這篇文章主要介紹了java重載Overloading與覆蓋Overriding的示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05

