MyBatis 之关系映射(上)
- 2022-10-27 北京
本文字数:6831 字
阅读完需:约 22 分钟
一、一对一关系映射
一对一关系映射,说的通俗一点,就是一一对应关系,可以通过级联的方式,将两者相关的数据查询出来。
Country 表:
create table country(
countryId varchar(50) not null,
name varchar(255) not null,
constraint pk_countryId primary key(countryId)
)engine innodb;
Capital 表:
create table capital(
capitalId varchar(50) not null,
countryId varchar(50) not null,
name varchar(255) not null,
constraint pk_capitalId primary key(capitalId)
)engine innodb;
Capital 类:
package org.fuys.owndb.vo;
import java.io.Serializable;
@SuppressWarnings("serial")
public class Capital implements Serializable {
private String countryId;
private String capitalId;
private String name;
}
Country 类:
package org.fuys.owndb.vo;
import java.io.Serializable;
import java.util.List;
@SuppressWarnings("serial")
public class Country implements Serializable {
private String countryId;
private String name;
private Capital capital;
}
核心配置文件:
<typeAliases>
<typeAlias type="org.fuys.owndb.vo.Country" alias="Country"/>
<typeAlias type="org.fuys.owndb.vo.Capital" alias="Capital"/>
</typeAliases>
<mappers>
<mapper resource="org/fuys/owndb/vo/mapping/Country.xml"/>
<mapper resource="org/fuys/owndb/vo/mapping/Capital.xml"/>
</mappers>
Country.xml 配置文件:
<mapper namespace="org.fuys.owndb.vo.mapping.Country">
<resultMap type="Country" id="CountryMap">
<id column="countryId" property="countryId"/>
<result column="name" property="name"/>
<association column="countryId" property="capital" javaType="Capital" select="org.fuys.owndb.vo.mapping.Capital.selectByCountryId"/>
</resultMap>
<select id="selectByCountryId" parameterType="java.lang.String" resultMap="CountryMap">
SELECT countryId,name
FROM country
WHERE countryId = #{countryId}
</select>
<select id="select" parameterType="Country" resultMap="CountryMap">
SELECT countryId,name
FROM country
<where>
<if test="countryId !=null">
and countryId = #{countryId}
</if>
<if test="name !=null">
and name = #{name}
</if>
</where>
</select>
</mapper>
Capital.xml 配置文件:
<mapper namespace="org.fuys.owndb.vo.mapping.Capital">
<resultMap type="Capital" id="CapitalMap">
<id column="capitalId" property="capitalId"/>
<result column="name" property="name"/>
</resultMap>
<select id="selectByCountryId" parameterType="java.lang.String" resultMap="CapitalMap">
SELECT capitalId,countryId,name
FROM capital
WHERE countryId = #{countryId}
</select>
</mapper>
junit 测试代码:
@Test
public void testSelectOneVsOne(){
Country country = MyBatisSqlSessionFactory.getSqlSession().selectOne("org.fuys.owndb.vo.mapping.Country.selectByCountryId","CHINA");
TestCase.assertNotNull(country);
logger.info(country.toString());
country = new Country();
country.setCountryId("CHINA");
List<Country> countryList = MyBatisSqlSessionFactory.getSqlSession().selectList("org.fuys.owndb.vo.mapping.Country.select",country);
TestCase.assertNotNull(countryList);
logger.info(countryList.toString());
}
总结得出,配置 MyBatis 一对一关系信息,级联查询时,association 级联查询对象的方法只能是单条数据,不能是多条,同时级联查询对象属性的设置也只能是单一对象属性,不能是集合。
要实现关系映射,一定要使用 resultMap,这是不二法则。
疑问:
在原课的讲解上,老李讲到了“ 1 + N ”次查询的问题,但是,我仍然不明白,怎么会造成了“ 1 + N ”次,这个暂且留着,后续再研究。
二、一对多映射
数据库设计当中,第三范式也是使用广泛的一种关系,MyBatis 也提供了该功能的支持。同时仍然需要注意,实现关系的映射,需使用 resultMap。
country 表:
create table country(
countryId varchar(50) not null,
name varchar(255) not null,
constraint pk_countryId primary key(countryId)
)engine innodb;
province 表:
create table Province(
provinceId varchar(50) not null,
countryId varchar(50) not null,
name varchar(255) not null,
constraint pk_provinceId primary key(provinceId)
)engine innodb;
Country 类:
package org.fuys.owndb.vo;
import java.io.Serializable;
import java.util.List;
@SuppressWarnings("serial")
public class Country implements Serializable {
private String countryId;
private String name;
private List<Province> provinces;
}
Province 类:
package org.fuys.owndb.vo;
import java.io.Serializable;
@SuppressWarnings("serial")
public class Province implements Serializable {
private String provinceId;
private String name;
private Country country;
}
配置核心文件信息:
<typeAliases>
<typeAlias type="org.fuys.owndb.vo.Country" alias="Country"/>
<typeAlias type="org.fuys.owndb.vo.Province" alias="Province"/>
</typeAliases>
<mappers>
<mapper resource="org/fuys/owndb/vo/mapping/Country.xml"/>
<mapper resource="org/fuys/owndb/vo/mapping/Province.xml"/>
</mappers>
2.1、实现一对多的映射查询
Country.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="org.fuys.owndb.vo.mapping.Country">
<resultMap type="Country" id="CountryMap">
<id column="countryId" property="countryId"/>
<result column="name" property="name"/>
<collection property="provinces" column="countryId" javaType="java.util.List"
ofType="Province" select="org.fuys.owndb.vo.mapping.Province.selectByCountryId"/>
</resultMap>
<select id="selectByCountryId" parameterType="java.lang.String" resultMap="CountryMap">
SELECT countryId,name
FROM country
WHERE countryId = #{countryId}
</select>
</mapper>
Province.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="org.fuys.owndb.vo.mapping.Province">
<resultMap type="Province" id="ProvinceMap">
<id column="provinceId" property="provinceId" />
<result column="name" property="name" />
</resultMap>
<select id="selectByCountryId" parameterType="String"
resultMap="ProvinceMap">
SELECT provinceId,countryId,name
FROM province
WHERE
countryId = #{countryId}
</select>
</mapper>
2.2、实现多对一的映射查询
Country.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="org.fuys.owndb.vo.mapping.Country">
<resultMap type="Country" id="CountryMap">
<id column="countryId" property="countryId"/>
<result column="name" property="name"/>
<association column="countryId" property="capital" javaType="Capital" select="org.fuys.owndb.vo.mapping.Capital.selectByCountryId"/>
<!-- <collection property="provinces" column="countryId" javaType="java.util.List"
ofType="Province" select="org.fuys.owndb.vo.mapping.Province.selectByCountryId"/> -->
</resultMap>
<select id="selectByCountryId" parameterType="java.lang.String" resultMap="CountryMap">
SELECT countryId,name
FROM country
WHERE countryId = #{countryId}
</select>
</mapper>
Province.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="org.fuys.owndb.vo.mapping.Province">
<resultMap type="Province" id="ProvinceMap">
<id column="provinceId" property="provinceId" />
<result column="name" property="name" />
<!-- <association property="country" column="countryId" javaType="Country"
resultMap="org.fuys.owndb.vo.mapping.Country.CountryMap"/> -->
<association property="country" column="countryId" javaType="Country"
select="org.fuys.owndb.vo.mapping.Country.selectByCountryId"/>
</resultMap>
<select id="selectByProvinceId" parameterType="String"
resultMap="ProvinceMap">
SELECT provinceId,countryId,name
FROM province
WHERE
provinceId = #{provinceId}
</select>
<select id="selectByCountryId" parameterType="String"
resultMap="ProvinceMap">
SELECT provinceId,countryId,name
FROM province
WHERE
countryId = #{countryId}
</select>
</mapper>
执行结果:
DEBUG selectByProvinceId - ==> Preparing: SELECT provinceId,countryId,name FROM province WHERE provinceId = ?
DEBUG selectByProvinceId - ==> Parameters: GUIZHOU(String)
TRACE selectByProvinceId - <== Columns: provinceId, countryId, name
TRACE selectByProvinceId - <== Row: GUIZHOU, CHINA, GuiZhou
DEBUG selectByCountryId - ====> Preparing: SELECT countryId,name FROM country WHERE countryId = ?
DEBUG selectByCountryId - ====> Parameters: CHINA(String)
TRACE selectByCountryId - <==== Columns: countryId, name
TRACE selectByCountryId - <==== Row: CHINA, china
DEBUG selectByCountryId - ======> Preparing: SELECT capitalId,countryId,name FROM capital WHERE countryId = ?
DEBUG selectByCountryId - ======> Parameters: CHINA(String)
TRACE selectByCountryId - <====== Columns: capitalId, countryId, name
TRACE selectByCountryId - <====== Row: BEIJING, CHINA, beijing
DEBUG selectByCountryId - <====== Total: 1
DEBUG selectByCountryId - <==== Total: 1
DEBUG selectByProvinceId - <== Total: 1
INFO TestOneVsMore - Province [provinceId=GUIZHOU, name=GuiZhou, country=Country [countryId=CHINA, name=china, capital=Capital [countryId=CHINA, capitalId=BEIJING, name=beijing], provinces=null]]
方式二:
<?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="org.fuys.owndb.vo.mapping.Province">
<resultMap type="Province" id="ProvinceMap">
<id column="provinceId" property="provinceId" />
<result column="name" property="name" />
<association property="country" column="countryId" javaType="Country"
resultMap="org.fuys.owndb.vo.mapping.Country.CountryMap"/>
<!-- <association property="country" column="countryId" javaType="Country"
select="org.fuys.owndb.vo.mapping.Country.selectByCountryId"/> -->
</resultMap>
<select id="selectByProvinceId" parameterType="String"
resultMap="ProvinceMap">
SELECT provinceId,countryId,name
FROM province
WHERE
provinceId = #{provinceId}
</select>
<select id="selectByCountryId" parameterType="String"
resultMap="ProvinceMap">
SELECT provinceId,countryId,name
FROM province
WHERE
countryId = #{countryId}
</select>
</mapper>
执行结果:
DEBUG selectByProvinceId - ==> Preparing: SELECT provinceId,countryId,name FROM province WHERE provinceId = ?
DEBUG selectByProvinceId - ==> Parameters: GUIZHOU(String)
TRACE selectByProvinceId - <== Columns: provinceId, countryId, name
TRACE selectByProvinceId - <== Row: GUIZHOU, CHINA, GuiZhou
DEBUG selectByCountryId - ====> Preparing: SELECT capitalId,countryId,name FROM capital WHERE countryId = ?
DEBUG selectByCountryId - ====> Parameters: CHINA(String)
TRACE selectByCountryId - <==== Columns: capitalId, countryId, name
TRACE selectByCountryId - <==== Row: BEIJING, CHINA, beijing
DEBUG selectByCountryId - <==== Total: 1
DEBUG selectByProvinceId - <== Total: 1
INFO TestOneVsMore - Province [provinceId=GUIZHOU, name=GuiZhou, country=Country [countryId=CHINA, name=GuiZhou, capital=Capital [countryId=CHINA, capitalId=BEIJING, name=beijing], provinces=null]]
注意:
使用级联的 resultMap 和 select,返回查询的方式不同,resultMap 进行结果映射查询,select 则是使用查询语句进行查询,相当于重新调用了声明的查询语句,故又将所有的映射关系查询了一次;
当需要进行映射查询时,不要互相使用映射查询,会出现互相之间反复调用的情况,而抛出栈溢出问题;
建议较少使用映射关系,避免互相之间的多次调用,造成内存损耗。
“1 + N”问题的阐释:
父级查询多个数据,但是因为关联映射关系。那么,只要父级查询一条 sql 语句,,通过映射,也会去查询该条数据下的关联映射的所有 sql。那么,查询多个父级数据,就会出现了“1+N”的问题。
结果显示如下:
DEBUG select - ==> Preparing: SELECT countryId,name FROM country
DEBUG select - ==> Parameters:
TRACE select - <== Columns: countryId, name
TRACE select - <== Row: CHINA, china
DEBUG selectByCountryId - ====> Preparing: SELECT capitalId,countryId,name FROM capital WHERE countryId = ?
DEBUG selectByCountryId - ====> Parameters: CHINA(String)
TRACE selectByCountryId - <==== Columns: capitalId, countryId, name
TRACE selectByCountryId - <==== Row: BEIJING, CHINA, beijing
DEBUG selectByCountryId - <==== Total: 1
DEBUG selectByCountryId - ====> Preparing: SELECT provinceId,countryId,name FROM province WHERE countryId = ?
DEBUG selectByCountryId - ====> Parameters: CHINA(String)
TRACE selectByCountryId - <==== Columns: provinceId, countryId, name
TRACE selectByCountryId - <==== Row: BEIJING, CHINA, BeiJing
TRACE selectByCountryId - <==== Row: GUIZHOU, CHINA, GuiZhou
DEBUG selectByCountryId - <==== Total: 2
TRACE select - <== Row: JAPAN, japan
DEBUG selectByCountryId - ====> Preparing: SELECT capitalId,countryId,name FROM capital WHERE countryId = ?
DEBUG selectByCountryId - ====> Parameters: JAPAN(String)
TRACE selectByCountryId - <==== Columns: capitalId, countryId, name
TRACE selectByCountryId - <==== Row: TOKYO, JAPAN, tokyo
DEBUG selectByCountryId - <==== Total: 1
DEBUG selectByCountryId - ====> Preparing: SELECT provinceId,countryId,name FROM province WHERE countryId = ?
DEBUG selectByCountryId - ====> Parameters: JAPAN(String)
DEBUG selectByCountryId - <==== Total: 0
DEBUG select - <== Total: 2
INFO TestOneVsMore - [Country [countryId=CHINA, name=china, capital=Capital [countryId=CHINA, capitalId=BEIJING, name=beijing], provinces=[Province [provinceId=BEIJING, name=BeiJing, country=null], Province [provinceId=GUIZHOU, name=GuiZhou, country=null]]], Country [countryId=JAPAN, name=japan, capital=Capital [countryId=JAPAN, capitalId=TOKYO, name=tokyo], provinces=[]]]
andy
还未添加个人签名 2019-11-21 加入
还未添加个人简介
评论