mybatis的延迟加载
1、问题提出
现一个用户有多个地址,同时一个地址对应一个用户。
- 在查询用户信息时,要不要把关联地址查出来。
- 在查询地址信息时,要不要把关联用户查出来。
- 对于第一个问题,我们要确认什么时候需要用户的地址信息,没有必要每次都把地址信息查询出来。因为每次查询地址信息,对我们的开销是很大的,而且每次查询都不一定需要用到地址信息。
- 对于第二个问题,如果我们只是关心地址信息,而不知道地址信息是隶属于哪个用户,那么查出来也没有意义,所以每次查询地址信息时,都要带上用户信息。
2、延迟加载和立即加载
第一个问题就是延迟加载,第二个问题就是立即加载延迟加载:只有在使用到了对应的数据才进行查询,否则不进行查询。立即加载:不管是否使用到了,只要一调用方法,就会立马查询出来。
说明:表之间对应关系可以大致分为四种:一对一、一对多、多对一、多对多。
- 一对多、多对多通常情况下都是使用延迟加载。
- 一对一、多对一通常情况下都是使用立即加载。
3、实现一对一延迟加载案例演示
user_info表

address_info表

实体类
@data
public class userinfo {
private integer id;
private string staffid;
private string staffname;
/**
* 逻辑删除
*/
private boolean enabled;
}
@data
public class addressinfo {
private integer addressid;
private string userid;
private string city;
}
输出dto对象
@data
public class addressinfodto {
private integer addressid;
private string userid;
private string city;
private userinfo userinfo;
}
@data
public class userinfodto {
private integer id;
private string staffid;
private string staffname;
private boolean enabled;
private list<addressinfo> addressinfo;
}
实现一对一延迟加载
核心配置文件
<settings>
<!--mybatis开启延迟加载,当开启时,所有关联对象都会延迟加载-->
<setting name="lazyloadingenabled" value="true"/>
<!--开启按需加载,当开启时,任何方法调用都会加载该对象的所有属性,否则,每个属性会按需加载-->
<setting name="aggressivelazyloading" value="false"/>
</settings>mapper和映射文件
public interface addressinfomapper {
//查询所有地址信息
list<addressinfodto> findalladdressinfo();
}
使用 association标签的select属性,指定查询地址信息的方法,后面加载地址的用户对象时,会根据配置方法路径,去调用方法执行查询用户信息。column是指定调用查询用户信息所需要的参数。
<?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.tencent.dao.mapper.addressinfomapper">
<resultmap id="baseresultmapper" type="com.tencent.dao.entity.addressinfo">
<id column="address_id" jdbctype="integer" property="addressid"/>
<result column="user_id" jdbctype="varchar" property="userid"/>
<result column="city" jdbctype="varchar" property="city"/>
</resultmap>
<resultmap id="addressinfodtomap" type="com.tencent.dto.addressinfodto">
<id column="address_id" jdbctype="integer" property="addressid"/>
<result column="user_id" jdbctype="varchar" property="userid"/>
<result column="city" jdbctype="varchar" property="city"/>
<association property="userinfo" column="user_id" javatype="com.tencent.dao.entity.userinfo" select="com.tencent.dao.mapper.userinfomapper.findbystaffid">
<id column="id" jdbctype="integer" property="id"/>
<result column="staff_id" jdbctype="varchar" property="staffid"/>
<result column="staff_name" jdbctype="varchar" property="staffname"/>
<result column="enbaled" jdbctype="" property="enabled"/>
</association>
</resultmap>
<!--查询所有地址信息-->
<select id="findalladdressinfo" resultmap="addressinfodtomap">
select * from address_info
</select>
</mapper>public interface userinfomapper {
//根据用户id查询用户信息
userinfo findbystaffid(@param("staffid") string staffid);
}
添加根据用户id查询用户信息方法。
<?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">
<!--指定映射文件对应的dao实体-->
<mapper namespace="com.tencent.dao.mapper.userinfomapper">
<resultmap id="baseresultmapper" type="com.tencent.dao.entity.userinfo">
<id column="id" jdbctype="integer" property="id"/>
<result column="staff_id" jdbctype="varchar" property="staffid"/>
<result column="staff_name" jdbctype="varchar" property="staffname"/>
<result column="enabled" jdbctype="bit" property="enabled"/>
</resultmap>
<!--根据用户id-->
<select id="findbystaffid" resulttype="com.tencent.dao.entity.userinfo">
select * from user_info where staff_id = #{staffid}
</select>
</mapper><?xml version="1.0" encoding="utf-8"?>
<!doctype configuration
public "-//mybatis.org//dtd config 3.0//en"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--mybatis的主配置文件-->
<configuration>
<settings>
<setting name="mapunderscoretocamelcase" value="true"/>
<!--mybatis开启延迟加载,当开启时,所有关联对象都会延迟加载-->
<setting name="lazyloadingenabled" value="true"/>
<!--开启按需加载,当开启时,任何方法调用都会加载该对象的所有属性,否则,每个属性会按需加载-->
<setting name="aggressivelazyloading" value="false"/>
</settings>
<!--配置数据源信息 default指的是选择数据源-->
<environments default="mysql">
<environment id="mysql">
<!--配置事务类型-->
<transactionmanager type="jdbc"></transactionmanager>
<!--配置数据源信息-->
<datasource type="pooled">
<property name="driver" value="com.mysql.jdbc.driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/study-demo"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</datasource>
</environment>
</environments>
<!--配置映射文件mapper文件地址-->
<mappers>
<mapper resource="mapper/userinfomapper.xml"/>
<mapper resource="mapper/addressinfomapper.xml"/>
</mappers>
</configuration>public class testservice {
private inputstream in = null;
private sqlsession sqlsession = null;
private userinfomapper userinfomapper;
private addressinfomapper addressinfomapper;
@before
public void init() throws ioexception {
//读取配置文件
in = resources.getresourceasstream("mybatisconfig.xml");
//创建工厂构建者
sqlsessionfactorybuilder builder = new sqlsessionfactorybuilder();
//构建工厂
sqlsessionfactory factory = builder.build(in);
//根据工厂获取session
sqlsession = factory.opensession();
//sqlsession构建代理对象
userinfomapper = sqlsession.getmapper(userinfomapper.class);
addressinfomapper = sqlsession.getmapper(addressinfomapper.class);
system.out.println();
}
@after
public void after(){
sqlsession.commit();
if(sqlsession != null){
sqlsession.close();
}
if(in!= null){
try {
in.close();
} catch (ioexception e) {
e.printstacktrace();
}
}
}
@test
public void test1(){
//测试一对一延迟加载
list<addressinfodto> alladdressinfo = addressinfomapper.findalladdressinfo();
for (addressinfodto addressinfo : alladdressinfo) {
system.out.println("地址信息"+addressinfo.getcity());
system.out.println("用户地址"+addressinfo.getuserid());
}
}
}
执行结果

将延迟加载打开后执行结果
<settings>
<!--mybatis开启延迟加载,当开启时,所有关联对象都会延迟加载-->
<setting name="lazyloadingenabled" value="true"/>
<!--开启按需加载,当开启时,任何方法调用都会加载该对象的所有属性,否则,每个属性会按需加载-->
<setting name="aggressivelazyloading" value="true"/>
</settings>
通过比较可以看出,当开启延迟加载,执行结果虽然相同,但是开启延迟加载后会在查看用户信息才会去数据库中进行查询,这样可以省去数据库的一下基本开销。
4、实现一对多延迟加载
实现一对多延迟加载是以查询用户信息为案例,一个用户对应多个地址信息,相关user_info的mapper文件如下
- 使用collection 标签的select属性,指定查询用户对应地址信息的方法,当加载用户地址信息时,会根据column属性所配置的参数,执行查询用户地址信息方法。
<?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.tencent.dao.mapper.userinfomapper">
<resultmap id="baseresultmapper" type="com.tencent.dao.entity.userinfo">
<id column="id" jdbctype="integer" property="id"/>
<result column="staff_id" jdbctype="varchar" property="staffid"/>
<result column="staff_name" jdbctype="varchar" property="staffname"/>
<result column="enabled" jdbctype="bit" property="enabled"/>
</resultmap>
<resultmap id="userinfodtomap" type="com.tencent.dto.userinfodto">
<id column="id" jdbctype="integer" property="id"/>
<result column="staff_id" jdbctype="varchar" property="staffid"/>
<result column="staff_name" jdbctype="varchar" property="staffname"/>
<result column="enabled" jdbctype="bit" property="enabled"/>
<collection property="addressinfo" column="staff_id" select="com.tencent.dao.mapper.addressinfomapper.findbyuserid" oftype="com.tencent.dao.entity.addressinfo"/>
</resultmap>
<select id="findalluserinfo" resultmap="userinfodtomap">
select * from user_info
</select>
</mapper>地址信息对应的映射mapper文件
- 提供一个根据用户id查询所有的地址信息方法
<?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.tencent.dao.mapper.addressinfomapper">
<resultmap id="baseresultmapper" type="com.tencent.dao.entity.addressinfo">
<id column="address_id" jdbctype="integer" property="addressid"/>
<result column="user_id" jdbctype="varchar" property="userid"/>
<result column="city" jdbctype="varchar" property="city"/>
</resultmap>
<select id="findbyuserid" resulttype="com.tencent.dao.entity.addressinfo">
select * from address_info where user_id = #{userid}
</select>
</mapper>测试开启延迟加载执行结果
<settings>
<!--mybatis开启延迟加载,当开启时,所有关联对象都会延迟加载-->
<setting name="lazyloadingenabled" value="true"/>
<!--开启按需加载,当开启时,任何方法调用都会加载该对象的所有属性,否则,每个属性会按需加载-->
<setting name="aggressivelazyloading" value="true"/>
</settings>
可以看出,先执行了查询所有用户信息的sql语句,然后再挨个查询每个用户下的地址信息,实现了延迟加载。
总结
mybatis的延迟加载是通过 lazyloadingenabled 和 aggressivelazyloading 属性进行控制的,当一对一需要实现延迟加载时,需要打开延迟加载开关以及通过<association>标签的select 属性指定延迟加载对象查询的方法路径,column属性指定执行参数,在使用到其延迟加载对象时,mybatis才会进行查询。
当一对多时,通过<collection>标签的select属性指定延迟加载对象查询的方法路径,column属性指定执行参数,在使用到其延迟加载对象时,mybatis才会进行查询。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论