MyBatis框架:第八章:自定義結(jié)果集,一對(duì)一,一對(duì)多,延遲加載,賴(lài)加載
13.1、自定義結(jié)果集介紹
自定義結(jié)果集,可以給復(fù)雜的對(duì)象使用。也就是對(duì)象內(nèi)又嵌套一個(gè)對(duì)象?;蛘咭粋€(gè)集合。
在這種情況下。前面學(xué)過(guò)的知識(shí)點(diǎn),已經(jīng)無(wú)法直接獲取出對(duì)象內(nèi)對(duì)象的信息。
這個(gè)時(shí)候就需要使用resultMap自定義結(jié)果集來(lái)返回需要的數(shù)據(jù)。
13.2、創(chuàng)建一對(duì)一數(shù)據(jù)庫(kù)表
一對(duì)一數(shù)據(jù)表
創(chuàng)建鎖表
create table t_lock(
id
int primary key auto_increment,
name
varchar(50)
);
創(chuàng)建鑰匙表
create table t_key(
id
int primary key auto_increment,
name
varchar(50),
lock_id
int ,
foreign key(lock_id
) references t_lock(id
)
);
插入初始化數(shù)據(jù)
insert into t_lock(name
) values(‘阿里巴巴’);
insert into t_lock(name
) values(‘華為’);
insert into t_lock(name
) values(‘聯(lián)想’);
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、創(chuàng)建實(shí)體對(duì)象
鑰匙對(duì)象
public class Key {
private int id;
private String name;
private Lock lock;
鎖對(duì)象
public class Lock {
private int id;
private String name;
13.4、一對(duì)一的使用示例
13.4.1、創(chuàng)建 KeyMapper 接口
public interface KeyMapper {
public Key queryKeyForSimple(int id);
}
13.4.2、級(jí)聯(lián)屬性的映射配置
<!--
resultMap標(biāo)簽專(zhuān)門(mén)用來(lái)定義自定義的結(jié)果集數(shù)據(jù)。
type屬性設(shè)置返回的數(shù)據(jù)類(lèi)型
id屬性定義一個(gè)唯一標(biāo)識(shí)
-->
<resultMap type="com.bean.Key" id="queryKeyForSimple_resultMap">
<!-- id定義主鍵列 -->
<id column="id" property="id"/>
<!-- result 定義一個(gè)列和屬性的映射 -->
<result column="name" property="name"/>
<!-- lock.id 和 lock.name 叫級(jí)聯(lián)屬性映射 -->
<result column="lock_id" property="lock.id"/>
<result column="lock_name" property="lock.name"/>
</resultMap>
<!--
select 標(biāo)簽用于定義一個(gè)select語(yǔ)句
id屬性設(shè)置一個(gè)statement標(biāo)識(shí)
parameterType設(shè)置參數(shù)的類(lèi)型
resultMap 設(shè)置返回的結(jié)果類(lèi)型
-->
<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、 嵌套結(jié)果集映射配置
標(biāo)簽可以給返回結(jié)果中對(duì)象的屬性是子對(duì)象的情況,進(jìn)行映射。
比如:Key對(duì)象中有一個(gè)子對(duì)象Lock。就可以使用 來(lái)進(jìn)行映射返回
<!--
resultMap標(biāo)簽專(zhuān)門(mén)用來(lái)定義自定義的結(jié)果集數(shù)據(jù)。
type屬性設(shè)置返回的數(shù)據(jù)類(lèi)型
id屬性定義一個(gè)唯一標(biāo)識(shí)
-->
<resultMap type="com.bean.Key" id="queryKeyForSimple_resultMap_association">
<!-- id定義主鍵列 -->
<id column="id" property="id"/>
<!-- result 定義一個(gè)列和屬性的映射 -->
<result column="name" property="name"/>
<!--
association 標(biāo)簽可以給一個(gè)子對(duì)象定義列的映射。
property 屬性設(shè)置 子對(duì)象的屬性名 lock
javaType 屬性設(shè)置子對(duì)象的全類(lèi)名
-->
<association property="lock" javaType="com.bean.Lock">
<!-- id 屬性定義主鍵 -->
<id column="lock_id" property="id"/>
<!-- result 標(biāo)簽定義列和對(duì)象屬性的映射 -->
<result column="lock_name" property="name"/>
</association>
</resultMap>
13.4.4、KeyMapper的測(cè)試代碼
@Test
public void testQueryKeyForSimple() {
SqlSession session = sqlSessionFactory.openSession();
try {
KeyMapper keyMapper = session.getMapper( KeyMapper.class );
System.out.println( keyMapper.queryKeyForSimple(1) );
} finally {
session.close();
}
}
運(yùn)行的結(jié)果:
13.4.5、 定義分步查詢
添加一個(gè) LockMapper 接口
public interface LockMapper {
public Lock queryLockById(int lockId);
}
添加 LockMapper 接口對(duì)應(yīng)的配置文件
<?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">
<!-- 定義一個(gè)根據(jù)id查詢鎖的select -->
<select id="queryLockById" parameterType="int" resultType="com.bean.Lock">
select id , name from t_lock where id = #{value}
</select>
</mapper>
在KeyMapper接口中,添加另一個(gè)方法分步查詢:
public interface KeyMapper {
public Key queryKeyForSimple(int id);
public Key queryKeyByTwoStep(int id);
}
修改KeyMapper中的配置
<!-- resultMap 標(biāo)簽定義復(fù)雜對(duì)象的結(jié)果集數(shù)據(jù) -->
<resultMap type="com.bean.Key" id="queryKeyByTwoStep_resultMap">
<id column="id" property="id"/>
<result column="name" property="name"/>
<!--
association標(biāo)簽定義一個(gè)子對(duì)象的集合集
property 屬性映射子對(duì)象的名稱(chēng)
select 屬性定義執(zhí)行的查詢語(yǔ)句
也就是說(shuō)。property指定的lock子對(duì)象,是通過(guò)執(zhí)行。select標(biāo)識(shí)的查詢語(yǔ)句返回
column 屬性定義需要傳遞給select語(yǔ)句的參數(shù)
-->
<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>
分步查詢的測(cè)試代碼:
@Test
public void testQueryKeyByTwoStep() {
SqlSession session = sqlSessionFactory.openSession();
try {
KeyMapper keyMapper = session.getMapper( KeyMapper.class );
System.out.println( keyMapper.queryKeyByTwoStep(1) );
} finally {
session.close();
}
}
運(yùn)行結(jié)果:
13.5、延遲加載
延遲加載在一定程序上可以減少很多沒(méi)有必要的查詢。給數(shù)據(jù)庫(kù)服務(wù)器提升性能上的優(yōu)化。
要啟用延遲加載,需要在mybatis-config.xml配置文件中,添加如下兩個(gè)全局的settings配置。
<!-- 打開(kāi)延遲加載的開(kāi)關(guān) -->
<setting name="lazyLoadingEnabled" value="true" />
<!-- 將積極加載改為消極加載 按需加載 -->
<setting name="aggressiveLazyLoading" value="false"/>
懶加載還需要同時(shí)引入兩個(gè)jar包
修改mybatis-config.xml配置文件,添加全局的設(shè)置
<!-- 配置全局mybatis的配置 -->
<settings>
<!-- 啟用駝峰標(biāo)識(shí) -->
<setting name="mapUnderscoreToCamelCase" value="true" />
<!-- 打開(kāi)延遲加載的開(kāi)關(guān) -->
<setting name="lazyLoadingEnabled" value="true" />
<!-- 將積極加載改為消息加載即按需加載 -->
<setting name="aggressiveLazyLoading" value="false" />
</settings>
添加類(lèi)庫(kù)到工程項(xiàng)目中
13.6、多對(duì)一、一對(duì)多的使用示例
13.6.1、創(chuàng)建一對(duì)多數(shù)據(jù)庫(kù)
一對(duì)多數(shù)據(jù)表
創(chuàng)建班級(jí)表
create table t_clazz(
id
int primary key auto_increment,
name
varchar(50)
);
插入班級(jí)信息
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’);
創(chuàng)建學(xué)生表
create table t_student(
id
int primary key auto_increment,
name
varchar(50),
clazz_id
int,
foreign key(clazz_id
) references t_clazz(id
)
);
插入班級(jí)信息
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、 一對(duì)多,立即加載關(guān)聯(lián)查詢
創(chuàng)建實(shí)體對(duì)象
班級(jí)對(duì)象
public class Clazz {
private int id;
private String name;
private List stus;
學(xué)生對(duì)象
public class Student {
private int id;
private String name;
創(chuàng)建ClazzMapper接口類(lèi):
public interface ClazzMapper {
public Clazz queryClazzByIdForSimple(int id);
}
編寫(xiě)ClazzMapper.xml配置文件
<mapper namespace="com.dao.ClazzMapper">
<!--
resultMap可以定義一個(gè)自定義的結(jié)果集返回
-->
<resultMap type="com.bean.Clazz" id="queryClazzByIdForSimple_resultMap">
<id column="id" property="id"/>
<result column="name" property="name"/>
<!--
collection定義一個(gè)子集合對(duì)象返回
-->
<collection property="stus" ofType="com.bean.Student">
<id column="student_id" property="id"/>
<result column="student_name" property="name"/>
</collection>
</resultMap>
<!-- 定義一個(gè)立即加載的查詢Clazz對(duì)象 -->
<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>
測(cè)試代碼:
@Test
public void testQueryClazzByIdForSimple() {
SqlSession session = sqlSessionFactory.openSession();
try {
ClazzMapper clazzMapper = session.getMapper( ClazzMapper.class );
System.out.println( clazzMapper.queryClazzByIdForSimple(1) );
} finally {
session.close();
}
}
運(yùn)行效果:
13.6.3、一對(duì)多,賴(lài)加載
在ClazzMapper接口中添加一個(gè)分步查詢延遲加載的方法
public interface ClazzMapper {
public Clazz queryClazzByIdForSimple(int id);
public Clazz queryClazzByIdForLazy(int id);
}
創(chuàng)建一個(gè)StudentMapper接口
public interface StudentMapper {
public List queryStudentsByClazzId(int clazzId);
}
創(chuàng)建StudentMapper.xml配置文件
<!-- 根據(jù)班級(jí)id查詢學(xué)生信息 -->
<select id="queryStudentsByClazzId" parameterType="int" resultType="com.bean.Student">
select id,name from t_student where clazz_id = #{value}
</select>
修改ClazzMapper.xml配置文件內(nèi)容:
<!-- 創(chuàng)建一個(gè)自定義集合集 -->
<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>
<!-- 創(chuàng)建一個(gè)懶加載Clazz對(duì)象的查詢 -->
<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
上面日記中標(biāo)黃的部分,是給日記添加當(dāng)前時(shí)間的輸出
測(cè)試延遲加載的代碼
@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 {
//暫停一會(huì)兒
Thread.sleep(5000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(clazz.getStus());
} finally {
session.close();
}
}
運(yùn)行效果:
13.6.4、雙向關(guān)聯(lián)
修改班級(jí)對(duì)象
public class Clazz {
private int id;
private String name;
private List stus;
修改學(xué)生對(duì)象
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>
<!-- 根據(jù)班級(jí)id查詢學(xué)生信息 -->
<select id="queryStudentsByClazzId" parameterType="int"
resultMap="queryStudentsByClazzId_resultMap">
select id,name,clazz_id from t_student where clazz_id = #{value}
</select>
注意:雙向關(guān)聯(lián),要小心進(jìn)入死循環(huán),
1、防止死循環(huán)就是不要調(diào)用toString方法
2、最后一次查詢返回resultType.
修改測(cè)試的代碼如下:
@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 {
//暫停一會(huì)兒
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();
}
}