对象之间存在互相关联。
只要对方是单个对象,都使用<association…/>或@One映射
所谓嵌套select,就是指需要一条额外的select语句去获取关联实体
在这种策略下,无论是先拿到主表记录,还是先拿到从表记录,程序都需要执行额外的select语句去获取关联实体。
定义<association…/>或<collection…/>元素时,至少要指定property属性,用于指定代表关联关系的属性名
Person可以找到Address,并且Address可以找到Person
主类
package lee;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.itcheng.app.dao.AddressMapper;
import org.itcheng.app.dao.PersonMapper;
import org.itcheng.app.domain.Address;
import org.itcheng.app.domain.Person;
public class PersonManager
{
// SqlSessionFactory应该是应用级别
private static SqlSessionFactory sqlSessionFactory;
public static void main(String[] args) throws IOException
{
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 1. 创建SqlSessionFactory
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2. 打开SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// findPerson(sqlSession);
/* 结果
* DEBUG [main] org.itcheng.app.dao.PersonMapper.getPerson ==> Preparing: select * from person_inf where person_id = ?
* DEBUG [main] org.itcheng.app.dao.PersonMapper.getPerson ==> Parameters: 3(Integer)
* DEBUG [main] org.itcheng.app.dao.PersonMapper.getPerson <== Total: 1
* 白鼠精
* -----------------
* DEBUG [main] org.itcheng.app.dao.AddressMapper.getAddressByOwner ==> Preparing: select * from address_inf where owner_id = ?
* DEBUG [main] org.itcheng.app.dao.AddressMapper.getAddressByOwner ==> Parameters: 3(Integer)
* DEBUG [main] org.itcheng.app.dao.AddressMapper.getAddressByOwner <== Total: 1
* 陷空山无底洞
* */
findAddresses(sqlSession);
/* 结果
* DEBUG [main] org.itcheng.app.dao.AddressMapper.findAddressesById ==> Preparing: select * from address_inf where addr_id > ?
* DEBUG [main] org.itcheng.app.dao.AddressMapper.findAddressesById ==> Parameters: 3(Integer)
* DEBUG [main] org.itcheng.app.dao.PersonMapper.getPerson ====> Preparing: select * from person_inf where person_id = ?
* DEBUG [main] org.itcheng.app.dao.PersonMapper.getPerson ====> Parameters: 3(Integer)
* DEBUG [main] org.itcheng.app.dao.PersonMapper.getPerson <==== Total: 1
* DEBUG [main] org.itcheng.app.dao.PersonMapper.getPerson ====> Preparing: select * from person_inf where person_id = ?
* DEBUG [main] org.itcheng.app.dao.PersonMapper.getPerson ====> Parameters: 4(Integer)
* DEBUG [main] org.itcheng.app.dao.PersonMapper.getPerson <==== Total: 1
* DEBUG [main] org.itcheng.app.dao.AddressMapper.findAddressesById <== Total: 2
* 陷空山无底洞
* 积雷山摩云洞
* -----------------
* */
}
public static void findPerson(SqlSession sqlSession)
{
PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class);
Person p = personMapper.getPerson(3);
System.out.println(p.getName());
System.out.println("-----------------");
// Person获取关联实体是延迟加载,要等到真正访问关联实体时才去执行额外的SELECT语句
System.out.println(p.getAddr().getDetail());
// 4. 提交事务
sqlSession.commit();
// 5. 关闭资源
sqlSession.close();
}
public static void findAddresses(SqlSession sqlSession)
{
AddressMapper addressMapper = sqlSession.getMapper(AddressMapper.class);
List<Address> addrList = addressMapper.findAddressesById(3);
// 由于Address获取关联实体是立即加载,因此它会立即执行额外的SELECT语句
// 对于立即加载策略,即使不访问关联实体,它也会立即执行额外的SELECT语句
addrList.forEach(e -> {
System.out.println(e.getDetail());
});
System.out.println("-----------------");
// 4. 提交事务
sqlSession.commit();
// 5. 关闭资源
sqlSession.close();
}
}
接口类
package org.itcheng.app.dao;
import java.util.List;
import org.itcheng.app.domain.Address;
// Mapper组件相当于DAO组件
public interface AddressMapper
{
List<Address> findAddressesById(Integer id);
}
package org.itcheng.app.dao;
import org.itcheng.app.domain.Person;
// Mapper组件相当于DAO组件
public interface PersonMapper
{
Person getPerson(Integer id);
}
配置文件
<?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属性值相当于该mapper的唯一标识 -->
<mapper namespace="org.itcheng.app.dao.AddressMapper">
<select id="findAddressesById" resultMap="addrMap">
select * from address_inf where addr_id > #{id}
</select>
<resultMap type="address" id="addrMap">
<id column="addr_id" property="id"/>
<result column="addr_detail" property="detail"/>
<!--
fetchType="eager" 立即加载
-->
<association property="person" select="org.itcheng.app.dao.PersonMapper.getPerson"
column="owner_id" fetchType="eager"/>
</resultMap>
<select id="getAddressByOwner" resultMap="addrMap">
select * from address_inf where owner_id = #{id}
</select>
</mapper>
<?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属性值相当于该mapper的唯一标识 -->
<mapper namespace="org.itcheng.app.dao.PersonMapper">
<select id="getPerson" resultMap="personMap">
select * from person_inf where person_id = #{id}
</select>
<resultMap type="person" id="personMap">
<id column="person_id" property="id"/>
<result column="person_name" property="name"/>
<result column="person_age" property="age"/>
<!-- select指定使用AddressMapper中定义getAddressByOwner语句来获取关联实体
其中column指定将当前记录的person_id列的值传给该select语句
fetchType="lazy" 延迟加载
-->
<association property="addr"
select="org.itcheng.app.dao.AddressMapper.getAddressByOwner"
column="person_id" fetchType="lazy"/>
</resultMap>
</mapper>
bean类
package org.itcheng.app.domain;
public class Address
{
private Integer id;
private String detail;
// Address关联的对象
private Person person;
//get和set方法
}
package org.itcheng.app.domain;
public class Person
{
private Integer id;
private String name;
private int age;
// Person关联的对象
private Address addr;
//get和set方法
}