MyBatis学习——分步查询与延迟加载

本文详细介绍了MyBatis中分步查询的实现方法及其与关联查询的区别,通过具体实例展示了如何在OA系统中应用分步查询来获取员工及部门信息,同时深入探讨了延迟加载的配置与实现,旨在提高数据库查询效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自https://blog.youkuaiyun.com/postersxu/article/details/79053916

分步查询通常应用于关联表查询,如:

电商平台,查询订单信息时需要查询部分的用户信息;

OA系统,查询个人信息时需要查询部门信息,反之亦是。

相对于关联查询来说,分步查询将查询sql拆分,这里引申出一个问题是:分步查询与关联表查询的不同。

1)关联表查询毕竟只需要查询一次数据库,对于业务量较小的系统来说,效率更高,数据库压   力相对较小;

2)分步查询虽然需要多次查询数据,但是这也意味着能够更好地使用数据缓存服务,且缓存的数据耦合度低,利用率高,而且单次查询效率很高,数据库压力较小(对于业务量较大的系统来说)

分步查询的实现(以简单的OA系统为例)

业务场景一:嵌套标签association的应用---查询员工信息时,获取员工所在的部门信息。

 1.建立员工与部门实体类


/**员工实体类*/
public class Employee { 
	private Integer id;
	private String lastName;
	private String gender;
	private String email;
        private Department department;
        private Integer dId;

        getters and setters ...

}


/** 部门实体类*/
public class Department {
        private Integer id;
        private String departmentName;
        private List<Employee> employee;

        getters and setters...

}

2.一个员工对应一个部门,所以用association标签

在员工的Mapper中定义接口,并在员工Mapper.xml文件中增加对应的方法和resultMap

//员工类Mapper接口
public interface EmployeeMapper {
	Employee getEmpByIdStep(Integer id);
}

//员工Mapper.xml

<!-- 分步查询映射定义 -->

 <resultMap type="com.xuyong.entity.Employee" id="员工的resultMap">
        	<id column="id" property="id"/>
        	<result column="last_name" property="lastName"/>
        	<result column="gender" property="gender"/>
        	<result column="email" property="email"/>
        	<association property="department" select="com.xuyong.dao.DepartmentDao.getDepartmentById" column="id">
        	</association>
 </resultMap>

<!-- 使用association分布查询 -->
<select id="getEmpByIdStep" resultMap="员工的resultMap">
                select * from employee where id=#{id}
</select>

property---JavaBean内成员变量名,这里就是员工实体类里定义的部门类变量名

select---指定查询方法,命名方式为对应XML文件的命名空间+查询ID(Mapper接口的包路径+方法名)

column---参数列名,指下一步查询的参数对应的列名。这里查询部门需要用到的参数为员工主键,因此此处的column应为员工主键的数据库列名

3.定义部门Mapper接口,与上文中的select值相对应

/**
 * 部门类Mapper接口
 */
public interface DepartmentDao {
	/**
	 * 根据部门主键获取部门信息
	 */
	Department getDepartmentById(Integer id);
}

相应的xml编写
这里直接使用resultType进行映射,开发中建议使用resultMap

<!-- 根据主键获取部门信息 -->
        <select id="getDepartmentById" resultType="com.xuyong.entity.Department">
        	select id,department_name from department where id=#{id}
        </select>

以下为查询结果,可以看到打印了两次sql


[com.xuyong.dao.EmployeeDaoPlus.getEmpByIdStep]-==>  Preparing: select * from employee where id=? 

  [com.xuyong.dao.EmployeeDaoPlus.getEmpByIdStep]-==> Parameters: 1(Integer)

  [com.xuyong.dao.EmployeeDaoPlus.getEmpByIdStep]-<==    Columns: id, last_name, gender, email, d_id

  [com.xuyong.dao.EmployeeDaoPlus.getEmpByIdStep]-<==        Row: 1, 徐永, 男, t1heluosh1@163.com, 1

  [com.xuyong.dao.DepartmentDao.getDepartmentById]-====>  Preparing: select id,department_name from department where id=? 

  [com.xuyong.dao.DepartmentDao.getDepartmentById]-====> Parameters: 1(Integer)

  [com.xuyong.dao.DepartmentDao.getDepartmentById]-<====    Columns: id, department_name

  [com.xuyong.dao.DepartmentDao.getDepartmentById]-<====        Row: 1, 文案部

  [com.xuyong.dao.DepartmentDao.getDepartmentById]-<====      Total: 1

  [com.xuyong.dao.EmployeeDaoPlus.getEmpByIdStep]-<==      Total: 1

  Employee [dId=1, department=Department [departmentName=文案部, employee=null, id=1], email=t1heluosh1@163.com, gender=男, id=1, lastName=徐永]

二、延迟加载

什么是延迟加载?

当我们在某项业务里需要同时获取A、B两份数据,但是B这份数据又不需要立即使用(或者存在压根就不会使用的情况),当程序需要加载B时,再去请求数据库来获取B数据,而不是一次性将数据全部取出来或者重新发送一份请求,这就是延迟加载。

MyBatis默认关闭延迟加载技术,需要我们在配置文件里手动配置,配置如下:


<!-- 设置 -->
    <settings>

    	<!-- 驼峰命名映射 -->
    	<setting name="mapUnderscoreToCamelCase" value="true"/>

    	<setting name="jdbcTypeForNull" value="NULL"/>

    	<!-- 懒加载设置 -->
    	<setting name="lazyLoadingEnabled" value="true"/>  

    	<!-- 侵入懒加载,设置为false则按需加载,否则会全部加载 -->
    	<setting name="aggressiveLazyLoading" value="false"/>
    	
    	<!-- 标准日志输出 -->
    	<!--<setting name="logImpl" value="STDOUT_LOGGING"/>-->

    	<!-- log4j日志输出 -->
    	<setting name="logImpl" value="LOG4J"/>

    </settings>

注意:

1. lazyLoadingEnabled与aggressiveLazyLoading必须全部设置,且lazyLoadingEnabled为true,aggressiveLazyLoading为false才能让延迟加载真正生效

2.  toString与重载方法过滤:

     通常我们在测试时会在实体类加入toString,或者存在了一些重载方法,这些MyBatis会对其进行过滤,但是过滤会调     用cglib与asm指定包,因此要将两个包添加到buildpath。以下为两个包的maven依赖:

         <dependency>
	    	<groupId>cglib</groupId>
		<artifactId>cglib</artifactId>
		<version>3.1</version>
	 </dependency>

        <dependency>
            <groupId>asm</groupId>
            <artifactId>asm</artifactId>
            <version>3.3.1</version>
        </dependency>
 

3.如果想单个开启或禁用延迟加载,可以使用fetchType属性来实现

<!-- collection分布查询 -->       
 <resultMap type="com.xuyong.entity.Department" id="DepartAndEmpByStep">        
    <id column="id" property="id"/>        
    <result column="department_name" property="departmentName"/>        
    <!-- 多个值传递可封装成map如:column="{key1=column1,...}"    fetchType="lazy" 表示使用懒加载   fetchType="eager"表示禁用懒加载        -->        
    <collection property="employee" select="com.xuyong.dao.EmployeeDaoPlus.getEmpByDid"   
  column="{id=id}" fetchType="lazy">
    </collection>        
</resultMap>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值