元素中,包含了一個(gè) 更新時(shí)間:2021年06月24日18時(shí)01分 來(lái)源:傳智教育 瀏覽次數(shù): 圖1 人與身份證的關(guān)聯(lián)關(guān)系 那么使用MyBatis是怎么處理圖1中的這種一對(duì)一關(guān)聯(lián)關(guān)系的呢?在<resultMap>元素中,包含了一個(gè)<association>子元素,MyBatis就是通過(guò)該元素來(lái)處理一對(duì)一關(guān)聯(lián)關(guān)系的。 在<association>元素中,通??梢耘渲靡韵聦傩裕?/p>
● property:指定映射到的實(shí)體類對(duì)象屬性,與表字段一一對(duì)應(yīng); ● column:指定表中對(duì)應(yīng)的字段; ● javaType:指定映射到實(shí)體對(duì)象屬性的類型; ● select:指定引入嵌套查詢的子SQL語(yǔ)句,該屬性用于關(guān)聯(lián)映射中的嵌套查詢; ● fetchType:指定在關(guān)聯(lián)查詢時(shí)是否啟用延遲加載。fetchType屬性有l(wèi)azy和eager兩個(gè)屬性值,默認(rèn)值為lazy(即默認(rèn)關(guān)聯(lián)映射延遲加載)。 <association>元素的使用非常簡(jiǎn)單,只需要參考如下兩種示例配置即可,具體如下: MyBatis在映射文件中加載關(guān)聯(lián)關(guān)系對(duì)象主要通過(guò)兩種方式:嵌套查詢和嵌套結(jié)果。嵌套查詢是指通過(guò)執(zhí)行另外一條SQL映射語(yǔ)句來(lái)返回預(yù)期的復(fù)雜類型;嵌套結(jié)果是使用嵌套結(jié)果映射來(lái)處理重復(fù)的聯(lián)合結(jié)果的子集。開發(fā)人員可以使用上述任意一種方式實(shí)現(xiàn)對(duì)關(guān)聯(lián)關(guān)系的加載。 了解了MyBatis中處理一對(duì)一關(guān)聯(lián)關(guān)系的元素和方式后,接下來(lái)就以個(gè)人和身份證之間的一對(duì)一關(guān)聯(lián)關(guān)系為例,進(jìn)行詳細(xì)講解。 查詢個(gè)人及其關(guān)聯(lián)的身份證信息是先通過(guò)查詢個(gè)人表中的主鍵來(lái)獲個(gè)人信息,然后通過(guò)表中的外鍵,來(lái)獲取證件表中的身份證號(hào)信息。其具體實(shí)現(xiàn)步驟如下: (1)創(chuàng)建數(shù)據(jù)表。在mybatis數(shù)據(jù)庫(kù)中分別創(chuàng)建名為tb_idcard和tb_person的數(shù)據(jù)表,同時(shí)預(yù)先插入兩條數(shù)據(jù)。其執(zhí)行的SQL語(yǔ)句如下所示: 完成上述操作后,數(shù)據(jù)庫(kù)tb_idcard和tb_person表中的數(shù)據(jù)如圖2所示。 圖2 tb_idcard和tb_person表 (2)在Eclipse中創(chuàng)建一個(gè)名為chapter09的Web項(xiàng)目,然后引入相關(guān)JAR包、log4j日志文件、MybatisUtils工具類以及mybatis-config.xml核心配置文件。項(xiàng)目環(huán)境搭建完成后的文件結(jié)構(gòu),如圖3所示。 圖3 項(xiàng)目文件結(jié)構(gòu) (3)在項(xiàng)目的com.itheima.po包下創(chuàng)建持久化類IdCard和Person,編輯后的代碼,如文件1和文件2所示。 文件1 IdCard.java 在上述兩個(gè)文件中,分別定義了各自的屬性以及對(duì)應(yīng)的getter/setter方法,同時(shí)為了方便查看輸出結(jié)果還重寫了toString()方法。 (4)在com.itheima.mapper包中,創(chuàng)建證件映射文件IdCardMapper.xml和個(gè)人映射文件PersonMapper.xml,并在兩個(gè)映射文件中編寫一對(duì)一關(guān)聯(lián)映射查詢的配置信息,如文件3和文件4所示。 文件3 IdCardMapper.xml 在上述兩個(gè)映射文件中,使用了MyBatis中的嵌套查詢方式進(jìn)行了個(gè)人及其關(guān)聯(lián)的證件信息查詢,因?yàn)榉祷氐膫€(gè)人對(duì)象中除了基本屬性外還有一個(gè)關(guān)聯(lián)的card屬性,所以需要手動(dòng)編寫結(jié)果映射。從映射文件PersonMapper.xml中可以看出,嵌套查詢的方法是先執(zhí)行一個(gè)簡(jiǎn)單的SQL語(yǔ)句,然后在進(jìn)行結(jié)果映射時(shí),將關(guān)聯(lián)對(duì)象在<association>元素中使用select屬性執(zhí)行另一條SQL語(yǔ)句(即IdCardMapper.xml中的SQL)。 (5)在核心配置文件mybatis-config.xml中,引入Mapper映射文件并定義別名,如文件5所示。 文件5 mybatis-config.xml 在上述核心配置文件中,首先引入了數(shù)據(jù)庫(kù)連接的配置文件,然后使用掃描包的形式自定義別名,接下來(lái)進(jìn)行環(huán)境的配置,最后配置了Mapper映射文件的位置信息。 (6)在com.itheima.test包中,創(chuàng)建測(cè)試類MybatisAssociatedTest,并在類中編寫測(cè)試方法findPersonByIdTest(),如文件6所示。 文件6 MybatisAssociatedTest.java 在文件6的findPersonByIdTest()方法中,首先通過(guò)MybatisUtils工具類獲取了SqlSession對(duì)象,然后通過(guò)SqlSession對(duì)象的selectOne()方法獲取了個(gè)人信息。為了查看結(jié)果,這里使用了輸出語(yǔ)句輸出查詢結(jié)果信息。最后程序執(zhí)行完畢時(shí),關(guān)閉了SqlSession。 使用JUnit4執(zhí)行findPersonByIdTest()方法后,控制臺(tái)的輸出結(jié)果如圖4所示。 圖4 運(yùn)行結(jié)果 從圖4可以看出,使用MyBatis嵌套查詢的方式查詢出了個(gè)人及其關(guān)聯(lián)的身份證信息,這就是MyBatis中的一對(duì)一關(guān)聯(lián)查詢。 雖然使用嵌套查詢的方式比較簡(jiǎn)單,但是從圖4中可以看出,MyBatis嵌套查詢的方式要執(zhí)行多條SQL語(yǔ)句,這對(duì)于大型數(shù)據(jù)集合和列表展示不是很好,因?yàn)檫@樣可能會(huì)導(dǎo)致成百上千條關(guān)聯(lián)的SQL語(yǔ)句被執(zhí)行,從而極大的消耗數(shù)據(jù)庫(kù)性能并且會(huì)降低查詢效率。這并不是開發(fā)人員所期望的。為此,我們可以使用MyBatis提供的嵌套結(jié)果方式,來(lái)進(jìn)行關(guān)聯(lián)查詢。 在PersonMapper.xml中,使用MyBatis嵌套結(jié)果的方式進(jìn)行個(gè)人及其關(guān)聯(lián)的證件信息查詢,所添加的代碼如下所示: 從上述代碼中可以看出,MyBatis嵌套結(jié)果的方式只編寫了一條復(fù)雜的多表關(guān)聯(lián)的SQL語(yǔ)句,并且在<association>元素中繼續(xù)使用相關(guān)子元素進(jìn)行數(shù)據(jù)庫(kù)表字段和實(shí)體類屬性的一一映射。 在測(cè)試類MybatisAssociatedTest中,編寫測(cè)試方法findPersonByIdTest2(),其代碼如下所示。 使用JUnit4執(zhí)行findPersonByIdTest2()方法后,控制臺(tái)的輸出結(jié)果如圖5所示。 圖5 運(yùn)行結(jié)果 從圖5可以看出,使用MyBatis嵌套結(jié)果的方式只執(zhí)行了一條SQL語(yǔ)句,并且同樣查詢出了個(gè)人及其關(guān)聯(lián)的身份證的信息。 MyBatis延遲加載的配置: 在使用MyBatis嵌套查詢方式進(jìn)行MyBatis關(guān)聯(lián)查詢映射時(shí),使用MyBatis的延遲加載在一定程度上可以降低運(yùn)行消耗并提高查詢效率。MyBatis默認(rèn)沒(méi)有開啟延遲加載,需要在核心配置文件mybatis-config.xml中的<settings>元素內(nèi)進(jìn)行配置,具體配置方式如下: 在映射文件中,MyBatis關(guān)聯(lián)映射的<association>元素和<collection>元素中都已默認(rèn)配置了延遲加載屬性,即默認(rèn)屬性fetchType="lazy"(屬性fetchType="eager"表示立即加載),所以在配置文件中開啟延遲加載后,無(wú)需在映射文件中再做配置。 Mybatis原理介紹:MyBatis如何操作數(shù)據(jù)庫(kù)? 什么是Mybatis?Mybaits有哪些優(yōu)點(diǎn)? 北京校區(qū)MyBatis怎樣處理一對(duì)一關(guān)聯(lián)關(guān)系?分步驟介紹
<!--方式一:嵌套查詢-->
<association property="card" column="card_id"
javaType="com.itheima.po.IdCard"
select="com.itheima.mapper.IdCardMapper.findCodeById" />
<!--方式二:嵌套結(jié)果-->
<association property="card" javaType="com.itheima.po.IdCard">
<id property="id" column="card_id" />
<result property="code" column="code" />
</association>
注意:
USE mybatis;
# 創(chuàng)建一個(gè)名稱為tb_idcard的表
CREATE TABLE tb_idcard(
id INT PRIMARY KEY AUTO_INCREMENT,
CODE VARCHAR(18)
);
# 插入2條數(shù)據(jù)
INSERT INTO tb_idcard(CODE) VALUES('152221198711020624');
INSERT INTO tb_idcard(CODE) VALUES('152201199008150317');
# 創(chuàng)建一個(gè)名稱為tb_person的表
CREATE TABLE tb_person(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(32),
age INT,
sex VARCHAR(8),
card_id INT UNIQUE,
FOREIGN KEY(card_id) REFERENCES tb_idcard(id)
);
# 插入2條數(shù)據(jù)
INSERT INTO tb_person(name,age,sex,card_id) VALUES('Rose',29,'女',1);
INSERT INTO tb_person(name,age,sex,card_id) VALUES('tom',27,'男',2);
package com.itheima.po;
/**
* 證件持久化類
*/
public class IdCard {
private Integer id;
private String code;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
@Override
public String toString() {
return "IdCard [id=" + id + ", code=" + code + "]";
}
}
文件2 Person.java
package com.itheima.po;
/**
* 個(gè)人持久化類
*/
public class Person {
private Integer id;
private String name;
private Integer age;
private String sex;
private IdCard card; //個(gè)人關(guān)聯(lián)的證件
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public IdCard getCard() {
return card;
}
public void setCard(IdCard card) {
this.card = card;
}
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + ", "
+ "age=" + age + ", sex=" + sex + ", card=" + card + "]";
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.IdCardMapper">
<!-- 根據(jù)id查詢證件信息 -->
<select id="findCodeById" parameterType="Integer" resultType="IdCard">
SELECT * from tb_idcard where id=#{id}
</select>
</mapper>
文件4 PersonMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.PersonMapper">
<!-- 嵌套查詢:通過(guò)執(zhí)行另外一條SQL映射語(yǔ)句來(lái)返回預(yù)期的特殊類型 -->
<select id="findPersonById" parameterType="Integer"
resultMap="IdCardWithPersonResult">
SELECT * from tb_person where id=#{id}
</select>
<resultMap type="Person" id="IdCardWithPersonResult">
<id property="id" column="id" />
<result property="name" column="name" />
<result property="age" column="age" />
<result property="sex" column="sex" />
<!-- 一對(duì)一:association使用select屬性引入另外一條SQL語(yǔ)句 -->
<association property="card" column="card_id" javaType="IdCard"
select="com.itheima.mapper.IdCardMapper.findCodeById" />
</resultMap>
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 引入數(shù)據(jù)庫(kù)連接配置文件 -->
<properties resource="db.properties" />
<!--使用掃描包的形式定義別名 -->
<typeAliases>
<package name="com.itheima.po" />
</typeAliases>
<!--配置環(huán)境 ,默認(rèn)的環(huán)境id為mysql -->
<environments default="mysql">
<!-- 配置id為mysql的數(shù)據(jù)庫(kù)環(huán)境 -->
<environment id="mysql">
<!-- 使用JDBC的事務(wù)管理 -->
<transactionManager type="JDBC" />
<!--數(shù)據(jù)庫(kù)連接池 -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<!--配置Mapper的位置 -->
<mappers>
<mapper resource="com/itheima/mapper/IdCardMapper.xml" />
<mapper resource="com/itheima/mapper/PersonMapper.xml" />
</mappers>
</configuration>
package com.itheima.test;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import com.itheima.po.Person;
import com.itheima.utils.MybatisUtils;
/**
* Mybatis關(guān)聯(lián)查詢映射測(cè)試類
*/
public class MybatisAssociatedTest {
/**
* 嵌套查詢
*/
@Test
public void findPersonByIdTest() {
// 1、通過(guò)工具類生成SqlSession對(duì)象
SqlSession session = MybatisUtils.getSession();
// 2.使用MyBatis嵌套查詢的方式查詢id為1的人的信息
Person person = session.selectOne("com.itheima.mapper."
+ "PersonMapper.findPersonById", 1);
// 3、輸出查詢結(jié)果信息
System.out.println(person);
// 4、關(guān)閉SqlSession
session.close();
}
}
<!-- 嵌套結(jié)果:使用嵌套結(jié)果映射來(lái)處理重復(fù)的聯(lián)合結(jié)果的子集 -->
<select id="findPersonById2" parameterType="Integer"
resultMap="IdCardWithPersonResult2">
SELECT p.*,idcard.code
from tb_person p,tb_idcard idcard
where p.card_id=idcard.id
and p.id= #{id}
</select>
<resultMap type="Person" id="IdCardWithPersonResult2">
<id property="id" column="id" />
<result property="name" column="name" />
<result property="age" column="age" />
<result property="sex" column="sex" />
<association property="card" javaType="IdCard">
<id property="id" column="card_id" />
<result property="code" column="code" />
</association>
</resultMap>
/**
* 嵌套結(jié)果
*/
@Test
public void findPersonByIdTest2() {
// 1、通過(guò)工具類生成SqlSession對(duì)象
SqlSession session = MybatisUtils.getSession();
// 2.使用MyBatis嵌套結(jié)果的方法查詢id為1的人的信息
Person person = session.selectOne("com.itheima.mapper."
+ "PersonMapper.findPersonById2", 1);
// 3、輸出查詢結(jié)果信息
System.out.println(person);
// 4、關(guān)閉SqlSession
session.close();
}
<settings>
<!-- 打開延遲加載的開關(guān) -->
<setting name="lazyLoadingEnabled" value="true" />
<!-- 將積極加載改為消息加載,即按需加載 -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
最新資訊