文章目录
- 映射关系一对一
- 映射关系-官方文档
- 映射关系1对1-基本介绍
- 基本介绍
- 注意细节
- 映射关系1 对1-映射方式
- 映射方式
- 配置Mapper.xml 的方式
- 方式1
- 方式2
- 注解的方式实现
- 应用实例
- 总结
映射关系一对一
映射关系-官方文档
文档地址: https://mybatis.org/mybatis-3/zh/sqlmap-xml.html
映射关系1对1-基本介绍
基本介绍
- 项目中1 对1 的关系是一个基本的映射关系,比如:Person(人) — IDCard(身份证)
- 我们看看再MyBatis 中如何实现1 对1 的处理.
注意细节
1 对1 ,我们这里研究一下单向1 对1。
映射关系1 对1-映射方式
映射方式
- 通过配置XxxMapper.xml 实现1 对1 [配置方式]
- 通过注解的方式实现1 对1 [注解方式]
- 我们用代码实现,应用举例
配置Mapper.xml 的方式
方式1
通过配置XxxMapper.xml 的方式来实现下面的1 对1 的映射关系,实现级联查询,通过person 可以获取到对应的idencard 信息。
完成功能示意(如下)
person--Person{id=1, name=' 张三', card=IdenCard{id=1,card_sn='111111111111110'}}
创建person 表和idencard 表
CREATE TABLE person
(id INT PRIMARY KEY AUTO_INCREMENT,NAME VARCHAR(32) NOT NULL DEFAULT '',card_id INT ,FOREIGN KEY (card_id) REFERENCES idencard(id)
)CHARSET utf8;-- 创建mybatis_idencard 表
CREATE TABLE idencard
(id INT PRIMARY KEY AUTO_INCREMENT,card_sn VARCHAR(32) NOT NULL DEFAULT ''
)CHARSET utf8 ;-- 添加数据
INSERT INTO idencard VALUES(1,'111111111111110');
INSERT INTO person VALUES(1,'张三',1);
创建新的module(mybatis-mapping), 相关配置文件可以从上一个module —自己实现MyBatis 底层机制–抽丝剥茧(上)拷贝。
创建com\nlc\entity\IdenCard.java
public class IdenCard {private Integer id;private String card_sn;//通过查询IdenCard 可以级联查询得到personprivate Person person;public Person getPerson() {return person;}public void setPerson(Person person) {this.person = person;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getCard_sn() {return card_sn;}public void setCard_sn(String card_sn) {this.card_sn = card_sn;}@Overridepublic String toString() {return "IdenCard{" +"id=" + id +", card_sn='" + card_sn + '\'' +", person=" + person +'}';}
}
创建com\nlc\entity\Person.java
public class Person {private Integer id;private String name;//因为我们的需要实现一个级联操作, 一个人需要对应一个身份证//这里需要直接定义IdenCard对象属性private IdenCard card;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 IdenCard getCard() {return card;}public void setCard(IdenCard card) {this.card = card;}@Overridepublic String toString() {return "Person{" +"id=" + id +", name='" + name + '\'' +", card=" + card +'}';}
}
创建com\nlc\mapper\IdenCardMapper.java
public interface IdenCardMapper {//根据id获取到身份证序列号public IdenCard getIdenCardById(Integer id);
}
创建com\nlc\mapper\IdenCardMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nlc.mapper.IdenCardMapper"><!--1、配置/实现//根据id获取到身份证序列号2、public IdenCard getIdenCardById(Integer id);--><select id="getIdenCardById" parameterType="Integer"resultType="IdenCard">SELECT * FROM `idencard` WHERE `id` = #{id}</select>
</mapper>
创建PersonMapper.java
public interface PersonMapper {//通过Person的id获取到Person,包括这个Person关联的IdenCard对象[级联查询]public Person getPersonById(Integer id);
}
创建PersonMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nlc.mapper.PersonMapper"><!--1、配置/实现public Person getPersonById(Integer id);2、完成通过Person的id获取到Person,包括这个Person关联的IdenCard对象[级联查询]3. 先用大家容易想到的方式-分析问题-解决问题4. 看到如果配置成简单 resultType="Person" 问题就是没有实现级联查询5. 自定义resultMap 搞定 映射返回的结果6. 因为 getPersonById 最终返回的是 Person对象[只是有级联的对象属性], type仍然配置"Person"--><resultMap id="PersonResultMap" type="Person"><!--<result property="id" column="id"/>--><!--id – 一个 ID 结果;标记出作为 ID 的结果可以帮助提高整体性能1.property="id" 表示person 属性 id ,通常是主键2.column="id" 表示对应表的字段--><id property="id" column="id"/><result property="name" column="name"/><!--association – 一个复杂类型的关联1. property="card" 表示 Person对象的 card 属性2. javaType="IdenCard" 表示card 属性 的类型3. column="id" 是从我们的 下面这个语句查询后返回的字段SELECT * FROM `person`,`idencard` WHERE `person`.id=1 AND `person`.card_id = `idencard`.id--><association property="card" javaType="IdenCard"><result property="id" column="id"/><result property="card_sn" column="card_sn"/></association></resultMap><select id="getPersonById" parameterType="Integer"resultMap="PersonResultMap">SELECT * FROM `person`,`idencard` WHERE `person`.id = #{id}AND `person`.card_id = `idencard`.id</select>
创建src\test\java\com\nlc\mapper\IdenCardMapperTest.java
public class IdenCardMapperTest {//属性private SqlSession sqlSession;private IdenCardMapper idenCardMapper;//初始化@Beforepublic void init() {//获取到sqlSessionsqlSession = MyBatisUtils.getSqlSession();idenCardMapper = sqlSession.getMapper(IdenCardMapper.class);}@Testpublic void getIdenCardById() {IdenCard idenCard = idenCardMapper.getIdenCardById(1);System.out.println("idenCard--" + idenCard);if (sqlSession != null) {sqlSession.close();}}
}
创建src\test\java\com\nlc\mapper\PersonMapperTest.java , 完成测试
public class PersonMapperTest {//属性private SqlSession sqlSession;private PersonMapper personMapper;//初始化@Beforepublic void init() {//获取到sqlSessionsqlSession = MyBatisUtils.getSqlSession();personMapper = sqlSession.getMapper(PersonMapper.class);}@Testpublic void getPersonById() {Person person = personMapper.getPersonById(1);System.out.println("person--" + person);if (sqlSession != null) {sqlSession.close();}}
}
方式2
通过配置XxxMapper.xml 的方式来实现下面的1 对1 的映射关系,实现级联查询,通过person 可以获取到对应的identcard 信息。
完成功能示意结果(如下)
person--Person{id=1, name=' 张三', card=IdenCard{id=1,card_sn='111111111111110'}}
修改PersonMapper.java 和PersonMapper.xml 使用第2 种映射方式,完成1 对1 映射关系
修改PersonMapper.java
public interface PersonMapper {
//通过Person 的id 获取到Person,包括这个Person 管理的IdenCard 对象
public Person getPersonById(Integer id);
//通过Person 的id 获取到Person,包括这个Person 管理的IdenCard 对象,方式2
public Person getPersonById2(Integer id);
}
修改PersonMapper.xml
<!--1、通过Person的id获取到Person,包括这个Person关联的IdenCard对象,方式22、public Person getPersonById2(Integer id);3. 这里的方式和前面不同.1) 先通过 SELECT * FROM `person` WHERE `id` = #{id} 返回 person信息2) 再通过 返回的card_id 值,再执行操作,得到IdenCard 数据--><resultMap id="PersonResultMap2" type="Person"><id property="id" column="id"/><result property="name" column="name"/><!--再次解读1. mybatis第二种方式核心思想: 将这个多表联查,分解成单表操作 , 这样简洁,而且易于维护 ,推荐2. 而且可以复用你已经写好的方法 -组合3. property="card": 表示 Person对象的 card 属性4. column="card_id" 这个是SELECT * FROM `person` WHERE `id` = #{id} 返回的 字段 card_id 信息/数据5. 返回的 字段 card_id 信息/数据 作为getIdenCardById入参, 来执行--><association property="card" column="card_id"select="com.nlc.mapper.IdenCardMapper.getIdenCardById" /></resultMap><select id="getPersonById2" parameterType="Integer" resultMap="PersonResultMap2">SELECT * FROM `person` WHERE `id` = #{id}</select>
修改PersonMapperTest.java 完成测试
@Testpublic void getPersonById2() {Person person = personMapper.getPersonById2(1);System.out.println("person---------" + person);if (sqlSession != null) {sqlSession.close();}}
注解的方式实现
应用实例
通过注解的方式来实现下面的1 对1 的映射关系,实现级联查询,通过person 可以获取到对应的identcard 信息。
在实际开发中还是推荐使用配置方式。
创建com\nlc\mapper\IdenCardMapperAnnotaion.java
public interface IdenCardMapperAnnotation {//根据id获取到身份证//这个方法不需要返回任何级联对象@Select("SELECT * FROM `idencard` WHERE `id` = #{id}")public IdenCard getIdenCardById(Integer id);
}
创建com\nlc\mapper\PersonMapperAnnotation.java
public interface PersonMapperAnnotation {//这里注解实现方法//说明: 注解的形式就是对前面xml配置方式的体现//因为返回类型和形参类型在下面的方法上,所以可以不用配置//返回的结果集参数还是需要配置,可以参照前面的xml 属性@Select("SELECT * FROM `person` WHERE `id` = #{id}")@Results({@Result(id = true, property = "id", column = "id"),@Result(property = "name", column = "name"),@Result(property = "card", column = "card_id",//card不对应简单的column,是通过一个方法获取,//card_id是通过以前的方法,返回的一个叫card_id的值,下面的方法是需要一个入参的one = @One(select = "com.nlc.mapper.IdenCardMapper.getIdenCardById"))//因为是一对一的映射所以采用one = @One(***)的形式,可以debug看一下他的源码里面的属性})public Person getPersonById(Integer id);
}
创建com\nlc\mapper\PersonMapperAnnotationTest.java 完成测试
public class PersonMapperAnnotationTest {//属性private SqlSession sqlSession;private PersonMapperAnnotation personMapperAnnotation;//初始化@Beforepublic void init() {//获取到sqlSessionsqlSession = MyBatisUtils.getSqlSession();personMapperAnnotation = sqlSession.getMapper(PersonMapperAnnotation.class);}@Testpublic void getPersonById() {Person person = personMapperAnnotation.getPersonById(1);System.out.println("person----" + person);if(sqlSession != null) {sqlSession.close();}}
}
总结
- 表是否设置外键, 对MyBatis 进行对象/级联映射没有影响
- 举例: 去掉person 表的外键, 进行测试, 依然可以获取相应的级联对象