懒加载针对什么使用的?为什么要用懒加载?
懒加载针对级联使用的,懒加载的目的是减少内存的浪费和减轻系统负担。
懒加载是什么?
你可以理解为按需加载,当我调用到关联的数据时才与数据库交互否则不交互。
再具体点来说:
比如user表和role表有关联关系,有这样一条语句:查询uesr的同时将user的某一列数据作为参数一并查询role表符合条件的数据,mybatis里叫做级联。只要执行这条语句,就会将这两张表符合需求的信息一起加载出来。而懒加载只会加载uesr表的数据出来不加载role表的数据。
还不懂怎么办?
将下面的代码敲一遍,不要做任何的调用只运行下面的方法:
public void testFindAll(){
users = userDao.findAll();
}
至于为什么下面你将会知道。
如何使用开启懒加载?
在mybatis的主配置文件的Setings标签开启。
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
注意:标签的顺序,必须位于properties之后typeAliases之前。如果位置错乱会导致mybatis启动失败。
注意:这个是开启全局的懒加载开关。
lazyLoadingEnabled默认为false。
aggressiveLazyLoading 3.4.1(包含)前为true,之后为false。
开启懒加载一定要两个属性都配置吗?
不是的,真正开启懒加载标签的只是lazyLoadingEnabled:true表示开启,false表示关闭,默认为false。
如果我不想将全部的级联都设计懒加载怎么办?
association和collection有个fetchType属性可以覆盖全局的懒加载状态:eager表示这个级联不使用懒加载要立即加载,lazy表示使用懒加载。
注意:discriminator没有fetchType属性,因此它只能随大众不能有自己的小九九。
既然fetchType可以控制懒加载那么我仅仅配置fetchType不配置全局的可以吗?
可以的。
aggressiveLazyLoading是做什么么的?
它是控制具有懒加载特性的对象的属性的加载情况的。
true表示如果对具有懒加载特性的对象的任意调用会导致这个对象的完整加载,false表示每种属性按照需要加载。
还是不懂怎么办?
看具体效果:
日志:
# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE debug info warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE
# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
两个接口:
public interface IRole {
List<Role> findAll();
List<Role> findById(String id);
}
public interface IUser {
List<User> findAll();
}
两个实体类:
public class Role implements Serializable {
private String id;
private String userId;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
@Override
public String toString() {
return "Role{" +
"id='" + id + '\'' +
", userId='" + userId + '\'' +
'}';
}
}
public class User implements Serializable {
private String id;
private List<Role> role;
private String name ;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
name = "丽华";
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Role> getRole() {
return role;
}
public void setRole(List<Role> role) {
this.role = role;
}
@Override
public String toString() {
return "User{" +
"id='" + id + '\'' +
'}';
}
}
三个配置文件:
<?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">
<configuration>
<!--配置延迟加载-->
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
<!--使用typeAliases配置别名,它只能配置domain中类的别名 -->
<!-- 包下的实体类以小写类名为别名-->
<typeAliases>
<package name="com.itheima.domain"/>
</typeAliases>
<!--配置环境-->
<environments default="mysql">
<!-- 配置mysql的环境-->
<environment id="mysql">
<!-- 配置事务 -->
<transactionManager type="JDBC"/>
<!--配置连接池-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///test?serverTimezone=UTC"/>
<property name="username" value="rooot"/>
<property name="password" value=""/>
</dataSource>
</environment>
</environments>
<!-- 配置映射文件的位置 -->
<mappers>
<package name="com.itheima.dao"/>
</mappers>
</configuration>
<?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">
<!--
namespace:命名空间,其值为某一个dao层类的具体路径
-->
<mapper namespace="com.itheima.dao.IRole">
<resultMap id="resultMap" type="com.itheima.domain.Role">
<id property="id" column="id"/>
<result property="userId" column="user_id"/>
</resultMap>
<select id="findById" resultMap="resultMap" parameterType="string">
select * from role where user_id=#{id}
</select>
<select id="findAll" resultMap="resultMap">
select * from role
</select>
</mapper>
<?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">
<!--
namespace:命名空间,其值为某一个dao层类的具体路径
-->
<mapper namespace="com.itheima.dao.IUser">
<resultMap id="resultMap" type="com.itheima.domain.User">
<id property="id" column="id"/>
<collection property="role" column="id" select="com.itheima.dao.IRole.findById"/>
</resultMap>
<select id="findAll" resultMap="resultMap">
select * from user
</select>
</mapper>
这里简单描述一下;
uesr和role的关系为一对多。开启了全局懒加载。
并且在user的配置中配置级联,那么称user的实例为带有懒加载属性的对象。
aggressiveLazyLoading的属性为false,即每种属性按需加载,不调用就不加载。
运行测试方法:
@Test
public void testFindAll(){
users = userDao.findAll();
for(User user : users){
System.out.println("-----每个用户的信息------");
System.out.println(user.getName());
}
}
结果:
2019-11-26 19:37:21,627 128 [ main] DEBUG ansaction.jdbc.JdbcTransaction - Opening JDBC Connection
2019-11-26 19:37:22,323 824 [ main] DEBUG source.pooled.PooledDataSource - Created connection 793138072.
2019-11-26 19:37:22,326 827 [ main] DEBUG com.itheima.dao.IUser.findAll - ==> Preparing: select * from user
2019-11-26 19:37:22,347 848 [ main] DEBUG com.itheima.dao.IUser.findAll - ==> Parameters:
2019-11-26 19:37:22,400 901 [ main] DEBUG com.itheima.dao.IUser.findAll - <== Total: 4
-----每个用户的信息------
丽华
-----每个用户的信息------
丽华
-----每个用户的信息------
丽华
-----每个用户的信息------
丽华
2019-11-26 19:37:22,401 902 [ main] DEBUG ansaction.jdbc.JdbcTransaction - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2f465398]
2019-11-26 19:37:22,401 902 [ main] DEBUG source.pooled.PooledDataSource - Returned connection 793138072 to pool.
可以看到只执行user的sql语句,并且只加载调用的属性并没有加载 private List role;
下面将aggressiveLazyLoading设置为true:只要对这个类的任意操作将完整加载整个类的所有属性即执行级联的SQL语句
运行同样的测试方法:
2019-11-26 19:35:33,893 123 [ main] DEBUG ansaction.jdbc.JdbcTransaction - Opening JDBC Connection
2019-11-26 19:35:34,597 827 [ main] DEBUG source.pooled.PooledDataSource - Created connection 793138072.
2019-11-26 19:35:34,600 830 [ main] DEBUG com.itheima.dao.IUser.findAll - ==> Preparing: select * from user
2019-11-26 19:35:34,621 851 [ main] DEBUG com.itheima.dao.IUser.findAll - ==> Parameters:
2019-11-26 19:35:34,677 907 [ main] DEBUG com.itheima.dao.IUser.findAll - <== Total: 4
-----每个用户的信息------
2019-11-26 19:35:34,678 908 [ main] DEBUG com.itheima.dao.IRole.findById - ==> Preparing: select * from role where user_id=?
2019-11-26 19:35:34,679 909 [ main] DEBUG com.itheima.dao.IRole.findById - ==> Parameters: 1(String)
2019-11-26 19:35:34,680 910 [ main] DEBUG com.itheima.dao.IRole.findById - <== Total: 2
丽华
-----每个用户的信息------
2019-11-26 19:35:34,680 910 [ main] DEBUG com.itheima.dao.IRole.findById - ==> Preparing: select * from role where user_id=?
2019-11-26 19:35:34,680 910 [ main] DEBUG com.itheima.dao.IRole.findById - ==> Parameters: 2(String)
2019-11-26 19:35:34,681 911 [ main] DEBUG com.itheima.dao.IRole.findById - <== Total: 2
丽华
-----每个用户的信息------
2019-11-26 19:35:34,681 911 [ main] DEBUG com.itheima.dao.IRole.findById - ==> Preparing: select * from role where user_id=?
2019-11-26 19:35:34,681 911 [ main] DEBUG com.itheima.dao.IRole.findById - ==> Parameters: 4(String)
2019-11-26 19:35:34,682 912 [ main] DEBUG com.itheima.dao.IRole.findById - <== Total: 0
丽华
-----每个用户的信息------
2019-11-26 19:35:34,682 912 [ main] DEBUG com.itheima.dao.IRole.findById - ==> Preparing: select * from role where user_id=?
2019-11-26 19:35:34,682 912 [ main] DEBUG com.itheima.dao.IRole.findById - ==> Parameters: 5(String)
2019-11-26 19:35:34,683 913 [ main] DEBUG com.itheima.dao.IRole.findById - <== Total: 3
丽华
2019-11-26 19:35:34,684 914 [ main] DEBUG ansaction.jdbc.JdbcTransaction - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2f465398]
2019-11-26 19:35:34,684 914 [ main] DEBUG source.pooled.PooledDataSource - Returned connection 793138072 to pool.
我们只调用了getName方法没有调用getRole方法但mybatis却调用了查询role的语句。
现在可以更明确aggressiveLazyLoading的作用了:
true:
只要调用任意具有懒加载特性的对象的任意一个属性将完整加载整个对象,即触发级联效果。
false:
只加载调用的属性,不调用的属性不加载。
还是不懂怎么办?
将上面的过程自己来一遍。
还有一个问题,如果我仅仅使用aggressiveLazyLoading不使用lazyLoadingEnabled还有能按需加载吗?即调用getName不执行role的sql语句,就像第一种情况那样
如果不开启懒加载,在执行user的sql语句时也将执行role的sql语句。因此不能实现需求。