延迟加载

  1. 就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载。
  • 优点:
    先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。
  • 缺点:
    因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降。
  • 在多表中:
    一对多,多对多:通常情况下采用延迟加载
    一对一(多对一):通常情况下采用立即加载
  • 注意:
    延迟加载是基于嵌套查询来实现的

局部延迟加载

  1. <!-- 开启一对多 延迟加载 -->
  2. <resultMap id="userMap" type="user">
  3. <id column="id" property="id"></id>
  4. <result column="username" property="username"></result>
  5. <result column="password" property="password"></result>
  6. <result column="birthday" property="birthday"></result>
  7. <!--
  8. fetchType="lazy" 懒加载策略
  9. fetchType="eager" 立即加载策略
  10. -->
  11. <collection property="orderList" ofType="order" column="id"
  12. select="com.lagou.dao.OrderMapper.findByUid" fetchType="lazy">
  13. </collection>
  14. </resultMap>
  15. <select id="findAll" resultMap="userMap">
  16. SELECT * FROM `user`
  17. </select>

注意这里使用了toString方法。 在你调用当前对象的 equals、clone、hashCode、toString方法时也会触发关联对象的查询。
我们可以在配置文件中使用lazyLoadTriggerMethods配置项覆盖掉上面四个方法。

  1. <settings>
  2. <!--所有方法都会延迟加载-->
  3. <setting name="lazyLoadTriggerMethods" value="toString()"/>
  4. </settings>

全局延迟加载

  1. <settings>
  2. <!--开启全局延迟加载功能-->
  3. <setting name="lazyLoadingEnabled" value="true"/>
  4. </settings>

注意局部延迟加载属性优先级要高于全局延迟加载。所以如果你在局部配置eager,全局配置lazy,那就是eager起效果。

缓存

一级缓存

一级缓存是SqlSession级别的缓存,是默认开启的
所以在参数和SQL完全一样的情况下,我们使用同一个SqlSession对象调用一个Mapper方法,往往只执行一次SQL,因为使用SelSession第一次查询后,MyBatis会将其放在缓存中,以后再查询的时候,如果没有声明需要刷新,并且缓存没有超时的情况下,SqlSession都会取出当前缓存的数据,而不会再次发送SQL到数据库。

具体地说,sqlSession里有一个map结构。这个map结构会存储sql语句+sql语句参数+其他乱七八糟参数 对应的查询结果。
每次执行查询之前,会先访问缓存。

一级缓存是SqlSession范围的缓存,执行SqlSession的C(增加)U(更新)D(删除)操作,或者调用clearCache()、commit()、close()方法,都会清空缓存。不清空的话很可能会出现脏读问题。

当然也可以在每次查询之后都清空缓存,方法是

  1. <!-- 每次查询时,都会清除缓存 -->
  2. < select flushCache="true"></select>

二级缓存

二级缓存是namspace级别(跨sqlSession)的缓存,是默认不开启的
二级缓存的开启需要进行配置,实现二级缓存的时候,MyBatis要求返回的Entity必须是可序列化的。 也就是要求实现Serializable接口,配置方法很简单,只需要在映射XML文件配置 就可以开启二级缓存了。
mybatis开启了二级缓存后,查询顺序是:二级缓存—》一级缓存—》数据库
image.png

核心配置文件

  1. <settings>
  2. <!--
  3. 因为cacheEnabled的取值默认就为true,所以这一步可以省略不配置。
  4. 为true代表开启二级缓存;为false代表不开启二级缓存。
  5. -->
  6. <setting name="cacheEnabled" value="true"/>
  7. </settings>

映射配置文件

  1. <mapper namespace="com.lagou.dao.UserMapper">
  2. <!--当前映射文件开启二级缓存-->
  3. <cache></cache>
  4. <!--
  5. <select>标签中设置useCache=”true”代表当前这个statement要使用二级缓存。
  6. 如果不使用二级缓存可以设置为false
  7. 注意:
  8. 针对每次查询都需要最新的数据sql,要设置成useCache="false",禁用二级缓存。
  9. -->
  10. <select id="findById" parameterType="int" resultType="user" useCache="true">
  11. SELECT * FROM `user` where id = #{id}
  12. </select>
  13. </mapper>

测试(注意此时的User类已经实现了Serializable接口)

  1. @Test
  2. public void testTwoCache() throws Exception {
  3. SqlSession sqlSession = MyBatisUtils.openSession();
  4. UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
  5. User user = userMapper.findById(41);
  6. System.out.println("第一次查询的用户:" + user);
  7. //SQLSession不关闭,数据就不会刷新到二级缓存里。
  8. sqlSession.close();
  9. SqlSession sqlSession1 = MyBatisUtils.openSession();
  10. UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
  11. User user1 = userMapper1.findById(41);
  12. System.out.println("第二次查询的用户:"+user1);
  13. sqlSession1.close();
  14. }

二级缓存涉及多表查询和更新会有脏读问题。
实际开发中,最好不要用二级缓存。

基于注解的开发

简单案例

  1. public interface UserMapper {
  2. @Select(value = "select * from user")
  3. List<User> findAll();
  4. @Insert(value = "insert into user(username, birthday, sex, address) values(#{username}, #{birthday}, #{sex}, #{address})")
  5. void save(User user);
  6. @Update(value = "update user set username = #{username}, birthday=#{birthday} where id = #{id}")
  7. void update(User user);
  8. @Delete(value = "delete from user where id = #{any}")
  9. void delete(int id);
  10. }

一对多查询案例

  1. public interface UserMapper {
  2. @Select(value = "select * from user")
  3. List<User> findAll();
  4. @Insert(value = "insert into user(username, birthday, sex, address) values(#{username}, #{birthday}, #{sex}, #{address})")
  5. void save(User user);
  6. @Update(value = "update user set username = #{username}, birthday=#{birthday} where id = #{id}")
  7. void update(User user);
  8. @Delete(value = "delete from user where id = #{any}")
  9. void delete(int id);
  10. @Select(value = "select * from user where id = #{uid}")
  11. User findById(int uid);
  12. @Select("select * from user")
  13. @Results({
  14. @Result(property = "id", column = "id", id = true),
  15. @Result(property = "username", column = "username"),
  16. @Result(property = "birthday", column = "birthday"),
  17. @Result(property = "sex", column = "sex"),
  18. @Result(property = "address", column = "address"),
  19. @Result(property = "ordersList", javaType = List.class, column = "id", many = @Many(select = "com.ning.mapper.OrderMapper.findOrderByUid", fetchType = FetchType.EAGER))
  20. })
  21. List<User> findAllWithOrder();
  22. }
  1. public interface OrderMapper {
  2. @Select(value = "select * from orders")
  3. @Results({
  4. @Result(property = "id", column = "id", id = true),
  5. @Result(property = "ordertime", column = "ordertime"),
  6. @Result(property = "total", column = "total"),
  7. @Result(property = "uid", column = "uid"),
  8. @Result(property = "user", javaType = User.class, column = "uid", one = @One(select = "com.ning.mapper.UserMapper.findById"))
  9. })
  10. List<Orders> findAllWithUser();
  11. @Select(value = "select * from orders where uid = #{uid}")
  12. List<Orders> findOrderByUid(int uid);
  13. }

多对多查询案例

  1. @Select("select * from user")
  2. @Results({
  3. @Result(property = "id", column = "id", id = true),
  4. @Result(property = "username", column = "username"),
  5. @Result(property = "birthday", column = "birthday"),
  6. @Result(property = "sex", column = "sex"),
  7. @Result(property = "address", column = "address"),
  8. @Result(property = "roleList", javaType = List.class, column = "id", many = @Many(select = "com.ning.mapper.RoleMapper.findRoleById", fetchType = FetchType.EAGER))
  9. })
  10. List<User> findAllWithRole();
  11. @Select("select * from sys_role r inner join sys_user_role ur on ur.roleid = r.id where ur.userid = #{id}")
  12. List<Role> findRoleById(int id);

二级缓存注解

  1. @CacheNamespace

在你想要开启二级缓存的mapper类上加这个注解

延迟加载

  1. fetchType = FetchType.LAZY 表示懒加载
  2. fetchType = FetchType.EAGER 表示立即加载
  3. fetchType = FetchType.DEFAULT 表示使用全局配置