一 MyBatis延迟加载
1.1 延迟加载
就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载。 实际开发过程中很多时候我们并不需要总是在加载用户信息时就一定要加载他的订单信息。此时就是我们所说的延迟加载。
* 优点:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表 速度要快。
* 缺点:因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时 间,所以可能造成用户等待时间变长,造成用户体验下降。
* 在多表中:
一对多,多对多:通常情况下采用延迟加载
一对一(多对一):通常情况下采用立即加载
* 注意:延迟加载是基于嵌套查询来实现的
1.2 局部延迟加载
在association和collection标签中都有一个fetchType属性,通过修改它的值,可以修改局部的加载策略。
<collection property="orderList" ofType="order" column="id" select="com.lagou.dao.OrderMapper.findByUid" fetchType="lazy">
</collection>
1.3 设置触发延迟加载的方法
大家在配置了延迟加载策略后,发现即使没有调用关联对象的任何方法,但是在你调用当前对象的equals、clone、hashCode、toString方法时也会触发关联对象的查询。
我们可以在配置文件中使用lazyLoadTriggerMethods配置项覆盖掉上面四个方法。
<settings> <!--所有方法都会延迟加载-->
<setting name="lazyLoadTriggerMethods" value="toString()"/>
</settings>
1.4 全局延迟加载
在Mybatis的核心配置文件中可以使用setting标签修改全局的加载策略。
<settings> <!--开启全局延迟加载功能-->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
局部的加载策略优先级高于全局的加载策略
<!--
fetchType="lazy" 懒加载策略
fetchType="eager" 立即加载策略 -->
<association property="user" column="uid" javaType="user" select="com.lagou.dao.UserMapper.findById" fetchType="eager">
</association>
二 MyBatis缓存
为什么使用缓存?
一句话概括:经常查询一些不经常发生变化的数据,使用缓存来提高查询效率。
2.1 一级缓存
- 一级缓存是SqlSession级别的缓存,是默认开启的
- 因为一级缓存的存在,导致第二次查询id为1的记录时,并没有发出sql语句从数据库中查询数据,而是从一 级缓存中查询。
- 一级缓存是SqlSession范围的缓存,执行SqlSession的C(增加)U(更新)D(删除)操作,或者调用 clearCache()、commit()、close()方法,都会清空缓存。
2.2 清除缓存
//调用sqlSession清除缓存的方法 sqlSession.clearCache();
<!-- 每次查询时,都会清除缓存 -->
< select flushCache="true"></select>
2.3 二级缓存
- 二级缓存是namspace级别(跨sqlSession)的缓存,是默认不开启的
- 二级缓存的开启需要进行配置,实现二级缓存的时候,MyBatis要求返回的POJO必须是可序列化的。也就是要求实现Serializable接口,配置方法很简单,只需要在映射XML文件配置 就可以开启二级缓存了。
- 当sqlsession.close或.commit时数据才会从一级缓存刷新到二级缓存。
- 二级缓存是mapper映射级别的缓存,多个SqlSession去操作同一个Mapper映射的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。
- **注意问题(脏读)**所谓的二级缓存存在脏读问题,就是在多表查询时,更新了子表数据。
<settings>
<!--因为cacheEnabled的取值默认就为true,所以这一步可以省略不配置。 为true代表开启二级缓存;为false代表不开启二级缓存。 -->
<setting name="cacheEnabled" value="true"/>
</settings>
2.4 小结
1. mybatis的缓存,都不需要我们手动存储和获取数据。mybatis自动维护的。
2. mybatis开启了二级缓存后,那么查询顺序:二级缓存--》一级缓存--》数据库
2. 注意:mybatis的二级缓存会存在脏读问题,需要使用第三方的缓存技术解决问题。
三 MyBatis注解
3.1 MyBatis常用注解
* @Insert:实现新增,代替了
* @Delete:实现删除,代替了
* @Update:实现更新,代替了
* @Select:实现查询,代替了
* @Result:实现结果集封装,代替了
* @Results:可以与@Result 一起使用,封装多个结果集,代替了
* @One:实现一对一结果集封装,代替了
* @Many:实现一对多结果集封装,代替了
3.2 MyBatis注解的增删改查【重点】
public interface UserMapper {
/*
查询用户
*/
@Select("select * from user")
public List<User> findAll();
/*
添加用户
*/
@Insert("insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})")
public void save(User user);
/*
更新用户
*/
@Update("update user set username = #{username},birthday=#{birthday} where id = #{id}")
public void update(User user);
/*
删除用户
*/
@Delete("delete from user where id = #{id}")
public void delete(Integer id);
/*
根据id查询用户
*/
@Select("select * from user where id = #{uid}")
public User findById(Integer uid);
}
编写核心配置文件
3.3 使用注解实现复杂映射开发
public interface UserMapper {
/*
查询所有用户,及关联的订单信息
*/
@Select("select * from user")
@Results({
@Result(property = "id",column = "id",id = true),
@Result(property = "username",column = "username"),
@Result(property = "birthday",column = "birthday"),
@Result(property = "sex",column = "sex"),
@Result(property = "address",column = "address"),
@Result(property = "ordersList",javaType = List.class,column = "id",many = @Many(select = "com.lagou.mapper.OrderMapper.findOrderByUid",fetchType = FetchType.LAZY))
})
public List<User> findAllWithOrder();
/*
查询所有用户及关联的角色信息
*/
@Select("select * from user")
@Results({
@Result(property = "id",column = "id",id = true),
@Result(property = "username",column = "username"),
@Result(property = "birthday",column = "birthday"),
@Result(property = "sex",column = "sex"),
@Result(property = "address",column = "address"),
@Result(property = "roleList",javaType = List.class,column = "id",many = @Many(select = "com.lagou.mapper.RoleMapper.findAllByUid")),
})
public List<User> findAllWithRole();
}
public interface OrderMapper {
/*
查询所有订单,同时查询订单所属的用户信息
*/
@Select("select * from orders")
@Results({ // 代替的就是resultMap标签 id标签 result标签
@Result(property = "id",column = "id",id = true),
@Result(property = "ordertime",column = "ordertime"),
@Result(property = "total",column = "total"),
@Result(property = "uid",column = "uid"),
@Result(property = "user",javaType = User.class,column = "uid",one = @One(select = "com.lagou.mapper.UserMapper.findById",fetchType = FetchType.EAGER))
})
public List<Orders> findAllWithUser();
/*
根据传递过来的用户id,查询该用户所具有的订单信息
*/
@Select("select * from orders where uid = #{uid}")
public List<Orders> findOrderByUid(Integer uid);
}
3.4 基于注解的二级缓存
配置SqlMapConfig.xml文件开启二级缓存的支持
<settings>
<!--因为cacheEnabled的取值默认就为true,所以这一步可以省略不配置。 为true代表开启二级缓存;为false代表不开启二级缓存。 -->
<setting name="cacheEnabled" value="true"/>
</settings>
在Mapper接口中使用注解配置二级缓存
@CacheNamespace
public interface UserMapper {...}
**3.5 **注解延迟加载
不管是一对一还是一对多 ,在注解配置中都有fetchType的属性
* fetchType = FetchType.LAZY 表示懒加载
* fetchType = FetchType.EAGER 表示立即加载
* fetchType = FetchType.DEFAULT 表示使用全局配置
**3.6 **小结
* 注解开发和xml配置优劣分析
1.注解开发和xml配置相比,从开发效率来说,注解编写更简单,效率更高。
2.从可维护性来说,注解如果要修改,必须修改源码,会导致维护成本增加。xml维护性更强。