MyBatis的關聯映射
Mybatis的關聯映射
實際的開發中,對資料庫的操作常常會涉及到多張表,這在面向物件中就涉及到了物件與物件之間的關聯關系,針對多表之間的操作,MyBatis提供了關聯映射,通過關聯映射就可以很好的處理物件與物件之間的關聯關系,
1.關聯關系概述
在關系型資料庫中,多表之間存在著三種關系,分別是一對一,一對多,多對多,
-
一對一:在任意一個表中引入另外一個表的主鍵作為外鍵,
-
一對多:在多個表中都引入了某一個表的主鍵作為外鍵
-
多對多:需要用一張中間表表示多對多的關系,這張中間表引入兩張表的主鍵作為外鍵,
一般來說一個物件映射一張表,因此一對一的關系就是在A類中定義B類屬性,一對多的關系就是在A類中定義List< B> 的屬性,多對多就是分別在A、B類中定義對方的List 屬性,
2.一對一
一對一關系是一個基本的映射關系,比如Person(人)--IDCard(身份證),我們可以通過如下兩種方式實作:
- 通過配置XxxMapper.xml實作1對1 [配置方式]
- 通過注解的方式實作1對1 [注解方式]
2.1配置方式
2.1.1環境搭建
配置映射檔案來實作一對一的映射關系,實作級聯查詢,要求通過person可以獲取到對應的idencard資訊
關于級聯查詢:若表A中有一個外鍵參考了表B的主鍵,A表就是子表,B表就是父表,當查詢表A的資料時,通過表A的外鍵將表B的記錄也查找出來,這就是級聯查詢,相應的還有級聯洗掉,當洗掉B表的記錄時,會先將A表中關聯的記錄刪掉
(1)person表和 idencard表
-- 創建 idencard 表
-- 記錄身份證
CREATE TABLE `idencard`(
`id` INT PRIMARY KEY AUTO_INCREMENT,
`card_sn` VARCHAR(32) NOT NULL DEFAULT ''
)CHARSET utf8;
INSERT INTO `idencard` VALUES(1,'123456789098765');
-- 創建person表
CREATE TABLE `person`(
`id` INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(32) NOT NULL DEFAULT '',
`card_id` INT, -- 對應idencard表的主鍵-id
FOREIGN KEY (`card_id`) REFERENCES idencard (`id`)-- card_id作為外鍵
)CHARSET utf8;
INSERT INTO `person` VALUES(1,'張三',1);
(2)物體類 IdenCard 和 Person
package com.li.entity;
/**
* @author 李
* @version 1.0
*/
public class IdenCard {
private Integer id;
private String card_sn;
//省略setter,getter,toString方法
}
package com.li.entity;
/**
* @author 李
* @version 1.0
*/
public class Person {
private Integer id;
private String name;
private IdenCard card;
//省略setter,getter,toString方法
}
(3)PersonMapper 介面
package com.li.mapper;
import com.li.entity.Person;
/**
* @author 李
* @version 1.0
*/
public interface PersonMapper {
//通過Person的id獲取到Person,包括這個Person關聯的IdenCard物件(級聯操作)
public Person getPersonById(Integer id);
}
2.1.2方式1:多表聯查
mybatis – MyBatis 3 | XML 映射器
PersonMapper.xml映射檔案實作級聯查詢,實作方法是使用多表聯查,回傳的資料通過resultMap結果映射
<mapper namespace="com.li.mapper.PersonMapper">
<!--1.介面宣告:public Person getPersonById(Integer id);
2.通過Person的id獲取到Person,包括這個Person關聯的IdenCard物件(級聯操作)
3.回傳型別如果配置成resultType="Person",不能實作級聯查詢,
在回傳的person物件中IdenCard屬性物件為 null
4.因此需要使用自定義resultMap,在resultMap中指定級聯關系-->
<select id="getPersonById" parameterType="Integer" resultMap="PersonResultMap">
SELECT * FROM `person`,`idencard` WHERE `person`.`id`= #{id} AND
`person`.`card_id` = `idencard`.`id`;
</select>
<!--association – 一個復雜型別的關聯;許多結果將包裝成這種型別嵌套結果映射 – 關聯可以是
resultMap 元素,或是對其它結果映射的參考
1.property="card" 表示 Person物件的card屬性
2.javaType="IdenCard" 表示card屬性的型別-->
<resultMap id="PersonResultMap" type="Person">
<!--id標簽–一個ID結果(就是主鍵);標記出作為主鍵的結果可以幫助提高整體性能-->
<!--這里的property表示Person類的屬性名,column表示對應表的欄位-->
<id property="id" column="id"/>
<result property="name" column="name"/>
<association property="card" javaType="IdenCard">
<!--這里的property表示IdenCard類的屬性名,column表示表的欄位名-->
<result property="id" column="id"/>
<result property="card_sn" column="card_sn"/>
</association>
</resultMap>
</mapper>
測驗:
@Test
public void getPersonById() {
Person person = personMapper.getPersonById(1);
System.out.println("person=" + person);
if (sqlSession != null) {
sqlSession.close();
}
}
2.2.3方式2:分解為多次單表操作(推薦使用)
第一種方式使用了多表聯查的形式實作級聯查詢,但是如果涉及的表過多,sql陳述句可讀性就會變差,第二種方式的核心思想是將多表聯查分解成單表操作,這樣更簡潔,易于維護,而且可以復用你寫好的方法,推薦使用
(1)創建IdenCardMapper介面
public interface IdenCardMapper {
//根據id獲取到身份證序列號
public IdenCard getIdenCardById(Integer id);
}
(2)在IdenCardMapper的映射檔案中實作該方法
<mapper namespace="com.li.mapper.IdenCardMapper">
<!--配置實作public IdenCard getIdenCardById(Integer id);-->
<select id="getIdenCardById" parameterType="Integer" resultType="IdenCard">
SELECT * FROM `idencard` WHERE `id` = #{id}
</select>
</mapper>
(3)PersonMapper介面
//通過Person的id獲取到Person,包括這個Person關聯的IdenCard物件(方式2)
public Person getPersonById2(Integer id);
(4)實作PersonMapper介面的映射檔案
1. 先通過 SELECT * FROM person WHERE id =#{id} 回傳 person 資訊
2. 以第一個操作回傳的 card_id 欄位資料,作為條件再次查詢,得到對應的 IdenCard 資料
如果第一個操作使用了別名,那么回傳的時候的欄位也是別名,因此第二個操作也要使用別名才能匹配到
<!--通過Person的id獲取到Person,包括這個Person關聯的IdenCard物件(方式2)
介面方法:public Person getPersonById2(Integer id);-->
<resultMap id="PersonResultMap2" type="Person">
<id property="id" column="id"/>
<result property="name" column="name"/>
<!--第二種方式的核心思想是將多表聯查操作分解成單表操作,
這樣更簡潔,易于維護,復用性更強,推薦使用-->
<!--1.property="card"表示Person物件的card屬性
2.column="card_id"是SELECT * FROM person WHERE id = #{id}陳述句回傳的card_id欄位名/別名
3.回傳的欄位card_id資訊/資料會作為getIdenCardById()的入參來執行方法-->
<association property="card" column="card_id"
select="com.li.mapper.IdenCardMapper.getIdenCardById"/>
</resultMap>
<select id="getPersonById2" parameterType="Integer" resultMap="PersonResultMap2">
SELECT * FROM person WHERE id = #{id};
</select>
測驗結果:
可以看到底層執行了兩次sql查詢操作,首先對person表進行查詢,查詢結果(card_id)作為第二張表的查詢條件(id),再對idencard表進行查詢,
2.2注解方式
通過注解的方式來實作一對一的映射關系,實作級聯查詢,通過person可以獲取到對應的idencard的資訊,這里只進行方式二的演示,
在實際開發中還是推薦使用配置方式
(1)注解實作方法
IdenCardMapperAnnotation 介面:
package com.li.mapper;
import com.li.entity.IdenCard;
import org.apache.ibatis.annotations.Select;
/**
* @author 李
* @version 1.0
* 使用注解的方式實作一對一的映射
*/
public interface IdenCardMapperAnnotation {
//根據id獲取到身份證序列號
@Select(value = "https://www.cnblogs.com/liyuelian/archive/2023/02/28/SELECT * FROM `idencard` WHERE `id` = #{id}")
public IdenCard getIdenCardById(Integer id);
}
PersonMapperAnnotation 介面:
package com.li.mapper;
import com.li.entity.Person;
import org.apache.ibatis.annotations.One;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
/**
* @author 李
* @version 1.0
*/
public interface PersonMapperAnnotation {
//通過Person的id獲取到Person,包括這個Person關聯的IdenCard物件
//注解的形式就是對前面xml配置方式的體現
@Select(value = "https://www.cnblogs.com/liyuelian/archive/2023/02/28/SELECT * FROM person WHERE id = #{id}")//如果這里回傳的欄位使用了別名,則@result的card_id也要使用該別名
@Results({//配置回傳資料的映射
@Result(id = true, property = "id", column = "id"),
@Result(property = "name", column = "name"),
@Result(property = "card", column = "card_id",
one = @One(select = "com.li.mapper.IdenCardMapper.getIdenCardById"))
})
public Person getPersonById(Integer id);
}
(2)測驗
@Test
public void getIdenCardById() {
Person person = personMapperAnnotation.getPersonById(1);
System.out.println("person=" + person);
if (sqlSession != null) {
sqlSession.close();
}
}
2.3注意事項
一張表是否設定了外鍵,對MyBatis進行物件級聯映射沒有影響,外鍵只是對表本身資料的約束
2.4練習
前面我們講解的是查詢Person可以級聯查詢到IdenCard,如果要求通過查詢IdenCard,也可以級聯查詢到Person,應該如何解決?
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/545306.html
標籤:其他
上一篇:自定義例外
