多表连接:一次查询获取对象及其关联对象的数据,然后将它们映射成对象及其关联的对象。
这种方式主要执行一次查询即可。
当关联实体是N时,使用
- resultMap: 再次指定一个映射对象对关联实体执行映射
- columnPrefix:指定使用列前缀进行区分。
- autoMapping:指定是否使用自动映射
- notNullColumn:默认情况,只要关联实体的任意列不为null,都会创建关联实体。
如果指定了该属性,只要当该属性所指定的全部列不为null,才会创建关联实体。
主类
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 p.*, ad.* from person_inf p join address_inf ad on ad.owner_id = p.person_id where person_id = ?
* DEBUG [main] org.itcheng.app.dao.PersonMapper.getPerson ==> Parameters: 3(Integer)
* DEBUG [main] org.itcheng.app.dao.PersonMapper.getPerson <== Total: 2
* 白素贞
* -----------------
* 陷空山无底洞
* 灵山大雷音寺
* */
findAddresses(sqlSession);
/* 结果
* DEBUG [main] org.itcheng.app.dao.AddressMapper.findAddressesById ==> Preparing: select ad.*, p.* from address_inf ad join person_inf p on ad.owner_id = p.person_id where addr_id > ?
* DEBUG [main] org.itcheng.app.dao.AddressMapper.findAddressesById ==> Parameters: 3(Integer)
* DEBUG [main] org.itcheng.app.dao.AddressMapper.findAddressesById <== Total: 6
* 斜月三星洞-->法海
* 福陵山云栈洞-->小青
* 高老庄-->小青
* 陷空山无底洞-->白素贞
* 灵山大雷音寺-->白素贞
* 积雷山摩云洞-->玉面狐狸
* -----------------
* */
}
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语句
List<Address> addresses = p.getAddresses();
addresses.forEach(e -> {
System.out.println(e.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() + "-->" + e.getPerson().getName());
});
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);
}
配置文件
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.itcheng.app.dao.AddressMapper">
<select id="findAddressesById" resultMap="addrMap">
select ad.*, p.*
from address_inf ad
join person_inf p
on ad.owner_id = p.person_id
where addr_id > #{id}
select>
<resultMap type="address" id="addrMap">
<id column="addr_id" property="id"/>
<result column="addr_detail" property="detail"/>
<association property="person"
resultMap="org.itcheng.app.dao.PersonMapper.personMap" />
resultMap>
mapper>
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.itcheng.app.dao.PersonMapper">
<select id="getPerson" resultMap="personMap">
select
p.*, ad.*
from person_inf p
join address_inf ad
on ad.owner_id = p.person_id
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"/>
<collection property="addresses"
javaType="ArrayList"
ofType="address"
resultMap="org.itcheng.app.dao.AddressMapper.addrMap"/>
resultMap>
mapper>
这种情况比较少见:它要求执行一次数据库查询,就能返回多个结果集。
通常表现为调用存储过程——调用一次,可能返回多个结果集
主类
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: {call p_get_person_address(?)}
* DEBUG [main] org.itcheng.app.dao.PersonMapper.getPerson ==> Parameters: 2(Integer)
* DEBUG [main] org.itcheng.app.dao.PersonMapper.getPerson <== Total: 1
* DEBUG [main] org.itcheng.app.dao.PersonMapper.getPerson <== Total: 2
* DEBUG [main] org.itcheng.app.dao.PersonMapper.getPerson <== Updates: 0
* 小青
* -----------------
* 福陵山云栈洞
* 高老庄
* */
findAddresses(sqlSession);
/* 结果
* DEBUG [main] org.itcheng.app.dao.AddressMapper.findAddressesById ==> Preparing: {call p_get_address_person(?)}
* DEBUG [main] org.itcheng.app.dao.AddressMapper.findAddressesById ==> Parameters: 3(Integer)
* DEBUG [main] org.itcheng.app.dao.AddressMapper.findAddressesById <== Total: 6
* DEBUG [main] org.itcheng.app.dao.AddressMapper.findAddressesById <== Total: 4
* DEBUG [main] org.itcheng.app.dao.AddressMapper.findAddressesById <== Updates: 0
* 斜月三星洞-->法海
* 福陵山云栈洞-->小青
* 高老庄-->小青
* 陷空山无底洞-->白素贞
* 灵山大雷音寺-->白素贞
* 积雷山摩云洞-->玉面狐狸
* -----------------
* */
}
public static void findPerson(SqlSession sqlSession)
{
PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class);
Person p = personMapper.getPerson(2);
System.out.println(p.getName());
System.out.println("-----------------");
// Person获取关联实体是延迟加载,要等到真正访问关联实体时才去执行额外的SELECT语句
List<Address> addresses = p.getAddresses();
addresses.forEach(e -> {
System.out.println(e.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() + "-->" + e.getPerson().getName());
});
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);
}
配置文件
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.itcheng.app.dao.AddressMapper">
<select id="findAddressesById" resultMap="addrMap" statementType="CALLABLE"
resultSets="addrs,persons">
{call p_get_address_person(#{id, mode=IN, jdbcType=INTEGER})}
select>
<resultMap type="address" id="addrMap">
<id column="addr_id" property="id"/>
<result column="addr_detail" property="detail"/>
<association property="person"
column="owner_id"
foreignColumn="person_id"
resultSet="persons"
resultMap="org.itcheng.app.dao.PersonMapper.personMap" />
resultMap>
mapper>
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.itcheng.app.dao.PersonMapper">
<select id="getPerson" resultMap="personMap" statementType="CALLABLE"
resultSets="persons,addrs">
{call p_get_person_address(#{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"/>
<collection property="addresses"
column="person_id" foreignColumn="owner_id"
resultSet="addrs"
resultMap="org.itcheng.app.dao.AddressMapper.addrMap"/>
resultMap>
mapper>