▲ 使用@One注解
<association…/> = @Result + @One
@One只需要指定select和fetchType,而column依然放在@Result中指定
主类
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: 1(Integer)
* DEBUG [main] org.itcheng.app.dao.AddressMapper.findAddressesById <== Total: 4
* 花果山水帘洞
* 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: 1(Integer)
* DEBUG [main] org.itcheng.app.dao.PersonMapper.getPerson <== Total: 1
* 孙悟空
* 福陵山云栈洞
* 陷空山无底洞
* 积雷山摩云洞
* -----------------
* */
}
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(1);
// 由于Address获取关联实体是立即加载,因此它会立即执行额外的SELECT语句
// 对于立即加载策略,即使不访问关联实体,它也会立即执行额外的SELECT语句
addrList.forEach(e -> {
System.out.println(e.getDetail());
// 此处只获取水帘洞的主人
if(e.getDetail().contains("水帘洞"))
{
System.out.println(e.getPerson().getName());
}
});
System.out.println("-----------------");
// 4. 提交事务
sqlSession.commit();
// 5. 关闭资源
sqlSession.close();
}
}
接口类
package org.itcheng.app.dao;
import java.util.List;
import org.apache.ibatis.annotations.One;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.ResultMap;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.mapping.FetchType;
import org.itcheng.app.domain.Address;
// Mapper组件相当于DAO组件
public interface AddressMapper
{
@Select("select * from address_inf where addr_id > #{id}")
@Results(id = "addrMap", value = {
@Result(column="addr_id", property="id", id=true),
@Result(column="addr_detail", property="detail"),
@Result(property="person", column="owner_id",
one=@One(select="org.itcheng.app.dao.PersonMapper.getPerson",
fetchType=FetchType.LAZY))
})
List<Address> findAddressesById(Integer id);
@Select("select * from address_inf where owner_id = #{id}")
@ResultMap("addrMap") // 该注解表明引用一个已有ResultMap的id
List<Address> getAddressByOwner(Integer ownerId);
}
package org.itcheng.app.dao;
import org.apache.ibatis.annotations.One;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.mapping.FetchType;
import org.itcheng.app.domain.Person;
// Mapper组件相当于DAO组件
public interface PersonMapper
{
@Select("select * from person_inf where person_id = #{id}")
@Results({ @Result(column = "person_id", property = "id", id = true),
@Result(column = "person_name", property = "name"),
@Result(column = "person_age", property = "age"),
@Result(property="addr", column="person_id",
one = @One(select = "org.itcheng.app.dao.AddressMapper.getAddressByOwner",
fetchType = FetchType.LAZY))
})
Person getPerson(Integer id);
}
嵌套select(包括1-1、1-N、N-N)都存在一个显著的"1+N"select语句的性能问题:
比如你要查询Address及其关联实体,执行过程如下:
(1) MyBatis执行第一条select语句获取多条Address记录。
(2) MyBatis要为【每条】Address记录分别执行一条额外的select语句来获取关联的对象。
这意味着第一条SQL语句返回了N条记录,第二次就需要额外执行N条select语句来获取关联对象。