第三十八章:MyBatis框架之自定義結果集,一對一,延遲加載,多對一、一對多,賴加載08

13.1、自定義結果集介紹
自定義結果集,可以給複雜的對象使用。也就是對象內又嵌套一個對象。或者一個集合。
在這種情況下。前面學過的知識點,已經無法直接獲取出對象內對象的信息。
這個時候就需要使用resultMap自定義結果集來返回需要的數據。

13.2、創建一對一數據庫表

## 一對一數據表
## 創建鎖表
create table t_lock(
	`id` int primary key auto_increment,
	`name` varchar(50)
);
   
## 創建鑰匙表
create table t_key(
	`id` int primary key auto_increment,
	`name` varchar(50),
	`lock_id` int ,
	foreign key(`lock_id`) references t_lock(`id`)
);
    
## 插入初始化數據
insert into t_lock(`name`) values('阿里巴巴');
insert into t_lock(`name`) values('華爲');
insert into t_lock(`name`) values('聯想');

insert into t_key(`name`,`lock_id`) values('馬雲',1);
insert into t_key(`name`,`lock_id`) values('任正非',2);
insert into t_key(`name`,`lock_id`) values('柳傳志',3);

13.3、創建實體對象

鑰匙對象
public class Key {
	private int id;
	private String name;
	private Lock lock; 
鎖對象
public class Lock {
	private int id;
private String name;

13.4、一對一的使用示例
13.4.1、創建 KeyMapper 接口

public interface KeyMapper {	
	public Key queryKeyForSimple(int id);
}

13.4.2、級聯屬性的映射配置

<!-- 
	resultMap標籤專門用來定義自定義的結果集數據。
		type屬性設置返回的數據類型
		id屬性定義一個唯一標識
 -->
<resultMap type="com.bean.Key" id="queryKeyForSimple_resultMap">
	<!-- id定義主鍵列 -->
	<id column="id" property="id"/>
	<!-- result 定義一個列和屬性的映射 -->
	<result column="name" property="name"/>
	<!-- lock.id 和  lock.name 叫級聯屬性映射 -->
	<result column="lock_id" property="lock.id"/>
	<result column="lock_name" property="lock.name"/>
</resultMap>
<!-- 
	select 標籤用於定義一個select語句
		id屬性設置一個statement標識
		parameterType設置參數的類型
		resultMap 設置返回的結果類型
 -->
<select id="queryKeyForSimple" parameterType="int" resultMap="queryKeyForSimple_resultMap">
	select t_key.*,t_lock.name lock_name 
		from 
	t_key left join t_lock
		on
	t_key.lock_id = t_lock.id
		where 
	t_key.id = #{id}
</select>

13.4.3、<association /> 嵌套結果集映射配置
<association /> 標籤可以給返回結果中對象的屬性是子對象的情況,進行映射。
比如:Key對象中有一個子對象Lock。就可以使用<association /> 來進行映射返回

<!-- 
	resultMap標籤專門用來定義自定義的結果集數據。
		type屬性設置返回的數據類型
		id屬性定義一個唯一標識
 -->	
<resultMap type="com.bean.Key" id="queryKeyForSimple_resultMap_association">
	<!-- id定義主鍵列 -->
	<id column="id" property="id"/>
	<!-- result 定義一個列和屬性的映射 -->
	<result column="name" property="name"/>
	<!-- 
		association 標籤可以給一個子對象定義列的映射。
			property 屬性設置 子對象的屬性名 lock
			javaType 屬性設置子對象的全類名
	 -->
	<association property="lock" javaType="com.bean.Lock">
		<!-- id 屬性定義主鍵 -->
		<id column="lock_id" property="id"/>
		<!-- result 標籤定義列和對象屬性的映射 -->
		<result column="lock_name" property="name"/>
	</association>
</resultMap>

13.4.4、KeyMapper的測試代碼

@Test
public void testQueryKeyForSimple() {
	SqlSession session = sqlSessionFactory.openSession();
	try {
		KeyMapper keyMapper = session.getMapper( KeyMapper.class );
		System.out.println( keyMapper.queryKeyForSimple(1) );
	} finally {
		session.close();
	}
}

運行的結果:
在這裏插入圖片描述
13.4.5、 定義分步查詢
添加一個 LockMapper 接口

public interface LockMapper {
	public Lock queryLockById(int lockId);
}

添加 LockMapper 接口對應的配置文件

<?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="com.dao.LockMapper">	
	<!-- 定義一個根據id查詢鎖的select -->
	<select id="queryLockById" parameterType="int" resultType="com.bean.Lock">
		select id , name from t_lock where id = #{value}
	</select>
</mapper>

在KeyMapper接口中,添加另一個方法分步查詢:

public interface KeyMapper {
	public Key queryKeyForSimple(int id);
	public Key queryKeyByTwoStep(int id);
}

修改KeyMapper中的配置

<!-- 	resultMap 標籤定義複雜對象的結果集數據  -->
<resultMap type="com.bean.Key" id="queryKeyByTwoStep_resultMap">
	<id column="id" property="id"/>
	<result column="name" property="name"/>
	<!-- 
		association標籤定義一個子對象的集合集
			property 屬性映射子對象的名稱
			select 屬性定義執行的查詢語句
			也就是說。property指定的lock子對象,是通過執行。select標識的查詢語句返回
			column 屬性定義需要傳遞給select語句的參數
	 -->
	<association property="lock" select="com.dao.LockMapper.queryLockById" column="lock_id" />
</resultMap>
<!-- 
	定義分步查詢的select
 -->
<select id="queryKeyByTwoStep" parameterType="int" resultMap="queryKeyByTwoStep_resultMap">
	select id,name,lock_id from t_key where id = #{value}
</select>

分步查詢的測試代碼:

@Test
public void testQueryKeyByTwoStep() {
	SqlSession session = sqlSessionFactory.openSession();
	try {
		KeyMapper keyMapper = session.getMapper( KeyMapper.class );
		System.out.println( keyMapper.queryKeyByTwoStep(1) );
	} finally {
		session.close();
	}
}

運行結果:
在這裏插入圖片描述
13.5、延遲加載

延遲加載在一定程序上可以減少很多沒有必要的查詢。給數據庫服務器提升性能上的優化。
要啓用延遲加載,需要在mybatis-config.xml配置文件中,添加如下兩個全局的settings配置。

<!-- 打開延遲加載的開關 -->  
<setting name="lazyLoadingEnabled" value="true" />  
<!-- 將積極加載改爲消極加載  按需加載 -->  
<setting name="aggressiveLazyLoading" value="false"/>  

懶加載還需要同時引入兩個jar包

修改mybatis-config.xml配置文件,添加全局的設置

<!-- 配置全局mybatis的配置 -->
<settings>
	<!-- 啓用駝峯標識 -->
	<setting name="mapUnderscoreToCamelCase" value="true" />
	<!-- 打開延遲加載的開關 -->
	<setting name="lazyLoadingEnabled" value="true" />
	<!-- 將積極加載改爲消息加載即按需加載 -->
	<setting name="aggressiveLazyLoading" value="false" />
</settings>

添加類庫到工程項目中
在這裏插入圖片描述

13.6、多對一、一對多的使用示例
13.6.1、創建一對多數據庫

## 一對多數據表
## 創建班級表
create table t_clazz(
	`id` int primary key auto_increment,
	`name` varchar(50)
);

## 插入班級信息
insert into t_clazz(`name`) values('javaEE20170228');
insert into t_clazz(`name`) values('javaEE20170325');
insert into t_clazz(`name`) values('javaEE20170420');
insert into t_clazz(`name`) values('javaEE20170515');

## 創建學生表
create table t_student(
	`id` int primary key auto_increment,
	`name` varchar(50),
	`clazz_id` int,
	foreign key(`clazz_id`) references t_clazz(`id`)
);

## 插入班級信息
insert into t_student(`name`,`clazz_id`) values('stu0228_1',1);
insert into t_student(`name`,`clazz_id`) values('stu0228_2',1);
insert into t_student(`name`,`clazz_id`) values('stu0228_3',1);
insert into t_student(`name`,`clazz_id`) values('stu0325_1',2);
insert into t_student(`name`,`clazz_id`) values('stu0325_2',2);
insert into t_student(`name`,`clazz_id`) values('stu0420_1',3);

13.6.2、<collection/> 一對多,立即加載關聯查詢
創建實體對象
班級對象

public class Clazz {
	private int id;
	private String name;
	private List<Student> stus;

學生對象

public class Student {
	private int id;
	private String name;

創建ClazzMapper接口類:

public interface ClazzMapper {
	public Clazz queryClazzByIdForSimple(int id);
}

編寫ClazzMapper.xml配置文件

<mapper namespace="com.dao.ClazzMapper">
	<!-- 
		resultMap可以定義一個自定義的結果集返回
	 -->
	<resultMap type="com.bean.Clazz" id="queryClazzByIdForSimple_resultMap">
		<id column="id" property="id"/>
		<result column="name" property="name"/>
		<!-- 
			collection定義一個子集合對象返回
		 -->
		<collection property="stus" ofType="com.bean.Student">
			<id column="student_id" property="id"/>
			<result column="student_name" property="name"/>
		</collection>
	</resultMap>
	<!-- 定義一個立即加載的查詢Clazz對象 -->
	<select id="queryClazzByIdForSimple" parameterType="int" resultMap="queryClazzByIdForSimple_resultMap">
		select t_clazz.* , t_student.id student_id,t_student.name student_name 
		from 
			t_clazz left join t_student
		on 
			t_clazz.id = t_student.clazz_id
		where 
			t_clazz.id = #{id}
	</select>
</mapper>

測試代碼:

@Test
	public void testQueryClazzByIdForSimple() {
		SqlSession session = sqlSessionFactory.openSession();
		try {
			ClazzMapper clazzMapper = session.getMapper( ClazzMapper.class );
			System.out.println( clazzMapper.queryClazzByIdForSimple(1) );
			
		} finally {
			session.close();
		}
	}

運行效果:
在這裏插入圖片描述
13.6.3、一對多,賴加載
在ClazzMapper接口中添加一個分步查詢延遲加載的方法

public interface ClazzMapper {
	public Clazz queryClazzByIdForSimple(int id);
	public Clazz queryClazzByIdForLazy(int id);
}

創建一個StudentMapper接口

public interface StudentMapper {
	public List<Student> queryStudentsByClazzId(int clazzId);
}

創建StudentMapper.xml配置文件

<!-- 根據班級id查詢學生信息 -->
	<select id="queryStudentsByClazzId" parameterType="int" resultType="com.bean.Student">
		select id,name from t_student where clazz_id = #{value}
    </select>

修改ClazzMapper.xml配置文件內容:

<!-- 創建一個自定義集合集 -->
	<resultMap type="com.bean.Clazz" id="queryClazzByIdForLazy_resultMap">
		<id column="id" property="id"/>
		<result column="name" property="name"/>
		<collection property="stus" ofType="com.bean.Student" 
			select="com.dao.StudentMapper.queryStudentsByClazzId" column="id" />
	</resultMap>
	
	<!-- 創建一個懶加載Clazz對象的查詢 -->
	<select id="queryClazzByIdForLazy" parameterType="int" resultMap="queryClazzByIdForLazy_resultMap">
		select id,name from t_clazz where id = #{value}
	</select>

修改log4j日記配置文件如下:

# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# MyBatis logging configuration...
#log4j.logger.org.mybatis.example.BlogMapper=TRACE
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t %d{HH:mm:ss}] - %m%n

上面日記中標黃的部分,是給日記添加當前時間的輸出

測試延遲加載的代碼

@Test
public void testQueryClazzByIdForLazy() {
	SqlSession session = sqlSessionFactory.openSession();
	try {
		ClazzMapper clazzMapper = session.getMapper( ClazzMapper.class );
		Clazz clazz = clazzMapper.queryClazzByIdForLazy( 1 );
		System.out.println(clazz.getName());
		try {
			//暫停一會兒
			Thread.sleep(5000);
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println(clazz.getStus());
	} finally {
		session.close();
	}
}

運行效果:
在這裏插入圖片描述
13.6.4、雙向關聯
修改班級對象

public class Clazz {
	private int id;
	private String name;
	private List<Student> stus;

修改學生對象

public class Student {
	private int id;
	private String name;
	private Clazz clazz;

修改StudentMapper配置文件

<resultMap type="com.bean.Student" id="queryStudentsByClazzId_resultMap">
	<id column="id" property="id"/>
	<result column="name" property="name"/>
	<association property="clazz" javaType="com.atguigu.bean.Clazz" 
		select="com.dao.ClazzMapper.queryClazzByIdForLazy"	column="clazz_id"></association>
</resultMap>

<!-- 根據班級id查詢學生信息 -->
<select id="queryStudentsByClazzId" parameterType="int"
	resultMap="queryStudentsByClazzId_resultMap">
	select id,name,clazz_id from t_student where clazz_id = #{value}
</select>

注意:雙向關聯,要小心進入死循環,
1、防止死循環就是不要調用toString方法
2、最後一次查詢返回resultType.

修改測試的代碼如下:

@Test
public void testQueryClazzByIdForLazy() {
	SqlSession session = sqlSessionFactory.openSession();
	try {
		ClazzMapper clazzMapper = session.getMapper( ClazzMapper.class );
		Clazz clazz = clazzMapper.queryClazzByIdForLazy( 1 );
		System.out.println(clazz.getName());
		try {
			//暫停一會兒
			Thread.sleep(3000);
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println(clazz.getStus().get(0).getName());
		System.out.println(clazz.getStus().get(0).getClazz().getName());
	} finally {
		session.close();
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章