MyBatis延迟加载
·~简单就好 人气:0有两种写法来表示查询信息,分别是链表查询和分步查询的方法。那么既然我么能用一个SQL语句能够执行完,那为什么还要分开来写呢?
原因很简单:可以发现如果我们把他们连在一起那么他们就是一个多表查询语句,如果不放在一起执行,那那就是单独一个表的查询语句。但是这需要我们设置mybatis的延迟加载(懒加载)
分步查询的优点
**可以实现延迟加载,**但是必须在核心配置文件中设置全局配置信息
lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载
aggressiveLazyLoding:当开启时,任何方式的调用都会加载该对象的所有属性。否则,该属性会按需加载 ,此时就可以实现按需加载,需要获取的数据是什么,就只会执行相应的sql.此时会通过association和collection中的fetchType属性设置当前的分步查询是否使用懒加载
fetchType=“lazy(延迟加载) | eager(立即加载)”
在主配置文件当中设置延迟加载
延迟加载:在SqlMapConfig.xml中配置延迟加载文件
<settings> <setting name="logImpl" value="STDOUT_LOGGING" /> <!-- 打印日志到控制台上 --> <setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="false"/> <!-- false才会按需加载,不开启调用所有的对象 --> </settings>
在studentDao.xml当中设置分步查询
测试结果
此时开启了懒加载,实现了分布查询
如何使用
public class UserDO { private Integer userId; private String username; private String password; private String nickname; private List<PermitDO> permitDOList; public UserDO() {} }
<resultMap id="BaseMap" type="org.apache.ibatis.study.entity.UserDO"> <id column="user_id" jdbcType="INTEGER" property="userId" /> <result column="username" jdbcType="VARCHAR" property="username" /> <result column="password" jdbcType="VARCHAR" property="password" /> <result column="nickname" jdbcType="VARCHAR" property="nickname"/> <collection property="permitDOList" column="user_id" select="getPermitsByUserId" fetchType="lazy"> </collection> </resultMap> <resultMap id="PermitBaseMap" type="org.apache.ibatis.study.entity.PermitDO"> <id column="id" jdbcType="INTEGER" property="id"/> <result column="code" jdbcType="VARCHAR" property="code"/> <result column="name" jdbcType="VARCHAR" property="name"/> <result column="type" jdbcType="TINYINT" property="type"/> <result column="pid" jdbcType="INTEGER" property="pid"/> </resultMap> <select id="getByUserId2" resultMap="BaseMap"> select * from user where user_id = #{userId} </select> <select id="getPermitsByUserId" resultMap="PermitBaseMap"> select p.* from user_permit up inner join permit p on up.permit_id = p.id where up.user_id = #{userId} </select>
通过fetchType=lazy指定子查询getPermitsByUserId使用懒加载,这样的话就不用管全局配置lazyLoadingEnabled是true还是false了。当然这里可以直接用多表关联查询不使用子查询,使用方法在这篇文章
测试代码
public class Test { public static void main(String[] args) throws IOException { try (InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml")) { // 构建session工厂 DefaultSqlSessionFactory SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); UserDO userDO = userMapper.getByUserId2(1); System.out.println(userDO); } } }
结果如下,打了断点可以看到原userDO对象已被代理并且permitDOList是null需要调用get方法才会去查询拿到值,咳咳这边之前直接运行显示是已经把permitDOList查询出来了,想了半天啥原因后来才发现println会调用userDO对象的toString方法,而toString方法也会走代理方法直接去调用子查询的
延迟加载的好处
延迟加载主要能解决mybatis的N+1问题,什么是N+1问题其实叫1+N更为合理,以上面的业务例子来说就是假设一次查询出来10000个用户,那么还需要针对这10000个用户使用子查询getPermitsByUserId获取每个用户的权限列表,需要10000次查询,总共10001次,真实情况下你可能并不需要每个子查询的结果,这样就浪费数据库连接资源了。如果使用延迟加载的话就相当于不用进行这10000次查询,因为它是等到你真正使用的时候才会调用子查询获取结果。
加载全部内容