一对一级联关系在现实生活中是十分常见的,例如一个大学生只有一张一卡通,一张一卡通只属于一个学生。再如人与身份证的关系也是一对一的级联关系。
MyBatis 如何处理一对一级联查询呢?在 MyBatis 中,通过 元素的子元素 处理这种一对一级联关系。
在 元素中通常使用以下属性。
- property:指定映射到实体类的对象属性。
- column:指定表中对应的字段(即查询返回的列名)。
- javaType:指定映射到实体对象属性的类型。
- select:指定引入嵌套查询的子 SQL 语句,该属性用于关联映射中的嵌套查询。
下面以个人与身份证之间的关系为例讲解一对一级联查询的处理过程,读者只需参考该实例即可学会一对一级联查询的 MyBatis 实现。
在项目开始创建之前,先准备好spring和mybatis以及其联合的jar包,jar整理如图所示。
项目需要的jar包下载:
https://blog.csdn.net/Bonport/article/details/104986335
1)创建数据表
创建person表,是否指定外键都可。
CREATE TABLE `person` (
`id` int(2) NOT NULL,
`name` varchar(20) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`idcard_id` int(2) DEFAULT NULL,
PRIMARY KEY (`id`)
);
创建idcard表。
CREATE TABLE `idcard` (
`id` int(2) NOT NULL AUTO_INCREMENT,
`code` varchar(18) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`)
);
使用 insert into table_name values(xx,xx…)向表中添加数据。添加数据如图。
使用一对一关联查询:
select person.*,idcard.code from person,idcard where person.idcard_id=idcard.id and person.id=1;
预期得到的结果:
2)创建持久化类
创建项目【Mybatis_关联查询】 项目 onetoone.po 包中创建数据表对应的持久化类 Idcard 和 Person。
Idcard 的代码如下:
package onetoone.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 + "]";
}
}
Person 的代码如下:
package onetoone.po;
public class Person {
private Integer id;
private String name;
private Integer age;
//card对应表idcard_id列,类型为IdCard
private IdCard card;
public IdCard getCard() {
return card;
}
public void setCard(IdCard card) {
this.card = 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 Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + ", age=" + age + ", card=" + card + "]";
}
}
3)创建映射文件
首先,在 MyBatis 的核心配置文件 mybatis-config.xml(onetoone.mybatis包)中打开延迟加载开关,代码如下:
<?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>
<settings>
<!--在使用MyBatis嵌套查询方式进行关联查询时,使用MyBatis的延迟加载可以在一定程度上提高查询效率-->
<!--打开延迟加载的开关-->
<setting name= "lazyLoadingEnabled" value= "true"/>
<!--将积极加载改为按需加载-->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
<mappers>
<mapper resource="onetoone/mybatis/IdCardMapper.xml"/>
<mapper resource="onetoone/mybatis/PersonMapper.xml"/>
</mappers>
</configuration>
然后,在 myBatisDemo02 应用的 onetoone.mybatis包 中创建两张表对应的映射文件 IdCardMapper.xml 和 PersonMapper.xml。在 PersonMapper.xml 文件中以 3 种方式实现“根据 id 查询个人信息”的功能,详情请看代码备注。
IdCardMapper.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="onetoone.dao.IdCardDao">
<select id="selectCardById" parameterType="Integer" resultType="onetoone.po.IdCard">
select * from idcard where id=#{id}
</select>
</mapper>
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">
<!-- namespace命名空间,唯一标识。一般指定为自定义的接口文件,下面相当于这个接口的实现类 -->
<mapper namespace="onetoone.dao.PersonDao">
<!-- 第一种:一对一根据id查询个人信息:级联查询(嵌套查询,执行两个SQL语句)-->
<!-- 定义结果集,column表示sql查询列,property表示映射到实体的属性 -->
<resultMap type="onetoone.po.Person" id="cardAndPerson1">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<!-- 关联对象 -->
<!-- 使用select属性指定第二步调用的方法,并通过column指定传递的参数值,这个值是第一步的查询的数据 -->
<association property="card" column="idcard_id"
javaType="onetoone.po.IdCard" select="onetoone.dao.IdCardDao.selectCardById"/>
</resultMap>
<!-- 第一步值只查询person表 -->
<select id="selectPersonById1" parameterType="Integer" resultMap="cardAndPerson1">
select * from person where id=#{id}
</select>
<!--第二种:一对一根据id查询个人信息,级联查询(嵌套结果,执行一个SQL语句)-->
<resultMap type="onetoone.po.Person" id="cardAndPerson2">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<!-- 一对一级联查询-->
<association property="card" javaType="onetoone.po.IdCard">
<!-- idcard的id对应着person的idcard_id或者idcard.id -->
<id property="id" column="idcard_id"/>
<result property="code" column="code"/>
</association>
</resultMap>
<!-- resultMap指定使用上面定义的结果集,查询使用关联查询,查询列要和上面的column对应 -->
<select id="selectPersonById2" parameterType="Integer" resultMap="cardAndPerson2">
select p.*,ic.code
from person as p, idcard as ic
where p.idcard_id=ic.id and p.id=#{id}
</select>
<!-- 第三种:一对一根据id查询个人信息,连接查询(使用POJO存储结果)-->
<select id="selectPersonById3" parameterType="Integer" resultType= "onetoone.po.SelectPersonById">
select p.id,p.name,p.age,ic.code
from person as p, idcard as ic
where p.idcard_id = ic.id and p.id=#{id}
</select>
</mapper>
4)创建 POJO 类
在 【Mybatis_关联查询】 项目 onetoone.po 包中创建在第 3 步中使用的 POJO 类
package onetoone.po;
public class SelectPersonById {
private Integer id;
private String name;
private Integer age;
private String code;
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 getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
@Override
public String toString() {
return "Person [id=" +id+",name=" +name+ ",age=" +age+ ",code=" +code+ "]";
}
}
5)创建数据操作接口
在 【Mybatis_关联查询】项目 onetoone.dao 包中创建第 3 步中映射文件对应的数据操作接口 IdCardDao 和 PersonDao。
IdCardDao 的代码如下:
package onetoone.dao;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import onetoone.po.IdCard;
@Repository("idCardDao")
@Mapper
public interface IdCardDao {
public IdCard selectCardById(Integer id);
}
PersonDao 的代码如下:
package onetoone.dao;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import onetoone.po.Person;
import onetoone.po.SelectPersonById;
@Repository("personDao")
@Mapper
public interface PersonDao {
public Person selectPersonById1(Integer id);
public Person selectPersonById2(Integer id);
public SelectPersonById selectPersonById3(Integer id);
}
6)调用接口方法及测试
在【Mybatis_关联查询】项目 onetoone.controller 包中创建 OneToOneController 类,在该类中调用第 5 步的接口方法,同时创建测试类 TestOneToOne。
OneToOneController 的代码如下:
package onetoone.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import onetoone.dao.PersonDao;
import onetoone.po.Person;
import onetoone.po.SelectPersonById;
@Controller("oneToOneController")
public class OneToOneController {
@Autowired
private PersonDao personDao;
public void test() {
Person p1=personDao.selectPersonById1(1);
System.out.println(p1);
System.out.println("=============================");
Person p2 = personDao.selectPersonById2(1);
System.out.println(p2);
System.out.println("=============================");
SelectPersonById p3 = personDao.selectPersonById3(1);
System.out.println(p3);
}
}
TestOneToOne 的代码如下:
package onetoone.controller;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestOneToOne {
public static void main(String[] args) {
String xmlPath="/onetoone/mybatis/applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
xmlPath);
OneToOneController oneToOneController=(OneToOneController) applicationContext.getBean("oneToOneController");
oneToOneController.test();
}
}
上述测试类的运行结果如图,和预期估计一致。