MyBatis框架:第八章:自定义结果集,一对一,一对多,延迟加载,赖加载

简介: MyBatis框架:第八章:自定义结果集,一对一,一对多,延迟加载,赖加载

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();
  }
}
相关文章
|
3月前
|
SQL XML Java
8、Mybatis-Plus 分页插件、自定义分页
这篇文章介绍了Mybatis-Plus的分页功能,包括如何配置分页插件、使用Mybatis-Plus提供的Page对象进行分页查询,以及如何在XML中自定义分页SQL。文章通过具体的代码示例和测试结果,展示了分页插件的使用和自定义分页的方法。
8、Mybatis-Plus 分页插件、自定义分页
|
3月前
|
SQL Java 测试技术
3、Mybatis-Plus 自定义sql语句
这篇文章介绍了如何在Mybatis-Plus框架中使用自定义SQL语句进行数据库操作。内容包括文档结构、编写mapper文件、mapper.xml文件的解释说明、在mapper接口中定义方法、在mapper.xml文件中实现接口方法的SQL语句,以及如何在单元测试中测试自定义的SQL语句,并展示了测试结果。
3、Mybatis-Plus 自定义sql语句
|
11天前
|
SQL Java 数据库连接
持久层框架MyBatisPlus
持久层框架MyBatisPlus
29 1
持久层框架MyBatisPlus
|
12天前
|
SQL 缓存 Java
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
本文详细介绍了MyBatis的各种常见用法MyBatis多级缓存、逆向工程、分页插件 包括获取参数值和结果的各种情况、自定义映射resultMap、动态SQL
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
|
2月前
|
SQL XML Java
mybatis复习04高级查询 一对多,多对一的映射处理,collection和association标签的使用
文章介绍了MyBatis中高级查询的一对多和多对一映射处理,包括创建数据库表、抽象对应的实体类、使用resultMap中的association和collection标签进行映射处理,以及如何实现级联查询和分步查询。此外,还补充了延迟加载的设置和用法。
mybatis复习04高级查询 一对多,多对一的映射处理,collection和association标签的使用
|
1月前
|
SQL XML Java
Mybatis中一对一和一对多的处理
这篇文章讲解了在Mybatis中如何处理一对一和一对多的关系映射,包括使用association和collection标签的具体方法。
20 1
|
25天前
|
缓存 Cloud Native 安全
探索阿里巴巴新型ORM框架:超越MybatisPlus?
【10月更文挑战第9天】在Java开发领域,Mybatis及其增强工具MybatisPlus长期占据着ORM(对象关系映射)技术的主导地位。然而,随着技术的发展,阿里巴巴集团推出了一种新型ORM框架,旨在提供更高效、更简洁的开发体验。本文将对这一新型ORM框架进行探索,分析其特性,并与MybatisPlus进行比较。
28 0
|
3月前
|
Java 数据库连接 Spring
后端框架入门超详细 三部曲 Spring 、SpringMVC、Mybatis、SSM框架整合案例 【爆肝整理五万字】
文章是关于Spring、SpringMVC、Mybatis三个后端框架的超详细入门教程,包括基础知识讲解、代码案例及SSM框架整合的实战应用,旨在帮助读者全面理解并掌握这些框架的使用。
后端框架入门超详细 三部曲 Spring 、SpringMVC、Mybatis、SSM框架整合案例 【爆肝整理五万字】
|
3月前
|
Java 数据库连接 mybatis
mybatis框架图
文章介绍了MyBatis框架的起源、发展和其作为持久层框架的功能,提供了MyBatis的框架图以帮助理解其结构和组件。
mybatis框架图
|
3月前
|
安全 Java 数据库连接
后端框架的学习----mybatis框架(3、配置解析)
这篇文章详细介绍了MyBatis框架的核心配置文件解析,包括环境配置、属性配置、类型别名设置、映射器注册以及SqlSessionFactory和SqlSession的生命周期和作用域管理。
后端框架的学习----mybatis框架(3、配置解析)