Mybatis 50_基于嵌套select的1-N关联

50_基于嵌套select的1-N关联

  • 嵌套select的1-N关联映射
    • 基于嵌套select的映射时,可指定如下独有属性:
    • 使用@Many注解
    • 项目0518基于嵌套select的1-N
    • 项目0519基于嵌套select的1-N_注解

嵌套select的1-N关联映射

只要对方是多个对象,都使用或@Many映射
所谓嵌套select,就是指需要一条额外的select语句去获取关联实体
在这种策略下,无论是先拿到主表记录,还是先拿到从表记录,程序都需要执行额外的select语句去获取关联实体。
定义元素时,至少要指定property属性,用于指定代表关联关系的属性名
此时javaType指定集合属性类型(比如List、Set),ofType指定集合元素的类型

基于嵌套select的映射时,可指定如下独有属性:

  • select: 指定额外的select语句的ID
  • column: 指定将当前实体的哪一列或哪些列传给select语句作为参数
  • fetchType:指定抓取策略。延迟加载或立即加载。
    延迟加载:只有等到真正去访问关联实体时采取执行额外的select语句。

使用@Many注解

= @Result + @Many
@Many只需要指定select和fetchType,而column依然放在@Result中指定

项目0518基于嵌套select的1-N

主类

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.AddressMapper.findAddressesById <==      Total: 2
		 * 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
		 * 积雷山摩云洞-->玉面狐狸
		 * -----------------
		 * */
	}
	
	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 * 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"/>
		
		<association property="person" select="org.itcheng.app.dao.PersonMapper.getPerson" 
			column="owner_id" fetchType="lazy"/>
	resultMap>
	
	<select id="getAddressByOwner" resultMap="addrMap">
		select * from address_inf where owner_id = #{id}
	select>
	
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 * 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"/>
		
		<collection property="addresses" 
			javaType="ArrayList"
			ofType="address"
			select="org.itcheng.app.dao.AddressMapper.getAddressByOwner" 
			column="person_id" fetchType="lazy"/>
	resultMap>
mapper>

项目0519基于嵌套select的1-N_注解

主类

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: 2
		 * 陷空山无底洞
		 * 灵山大雷音寺
		 * */
	
		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.AddressMapper.findAddressesById <==      Total: 6
		 * 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
		 * 斜月三星洞-->孙悟空
		 * 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: 2(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: 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
		 * 积雷山摩云洞-->玉面狐狸
		 * -----------------
		 * */
	}
	
	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.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 java.util.ArrayList;

import org.apache.ibatis.annotations.Many;
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="addresses",  column="person_id", 
			javaType = ArrayList.class,
			many = @Many(select = "org.itcheng.app.dao.AddressMapper.getAddressByOwner",
			fetchType = FetchType.LAZY))
	})
	Person getPerson(Integer id);
}

你可能感兴趣的:(mybatis,eclipse,java,mysql,数据库)