mybatis缓存分为一级缓存(针对一个sql会话)和二级缓存(针对不同的sql会话)
一级缓存默认开启,基于SqlSession级别的缓存,每一个SqlSession之间时相互独立的,当SqlSession执行:关闭、更新(增删改)、清空缓存操作时,会清空缓存。
MyBatis 对缓存提供支持,在默认没有配置的情况下,只开启一级缓存,一级缓存只对同一个SqlSession;只有在查询参数和SQL完全一样的情况下,使用同一个SqlSession对象调用同一个Mapper方法,只会执行一次SQL;在第一次查询后,MyBatis会将其查询结果放入缓存,如果没有声明刷新缓存或者缓存没有超时时,sqlSession会直接取出当前缓存的数据,而不会再次发送Sql到数据库。
①只执行了一次sql查询:
②清理缓存之后,两次sql查询:
一级缓存不能跨会话,不同会话之间对于相同的数据可能有不一样的缓存;在有多个会话或者分布式环境下,会存在脏数据的问题,要解决这个问题,需要使用二级缓存。
MyBatis的二级缓存是Application级别的缓存(对应namespace),可以提高对数据库查询的效率,以提高应用的性能。
SqlSessionFactory 层面上的二级缓存默认不开启,开启二级缓存需要进行相应的配置;实现二级缓存时,MyBatis要求返回的POJO必须是可序列化的,就是要实现Serializable接口。
配置二级缓存后:
①映射语句文件中所有的select语句将被缓存;
②映射语句文件中的insert,update和delete语句会刷新缓存;
③缓存会使用默认的Least Recently Used(LRU,最近最少使用)算法回收;
④根据时间表,如 No Flush Interval(NFI 没有刷新间隔),缓存不会以任何时间顺序来刷新;
⑤缓存会存储列表集合或对象(无论查询方法返回什么)的1024个引用;
⑥缓存会被视为是read/write的缓存,表示对象检索不是共享的,而且可以安全的被调用者修改,不干扰其他调用者或线程所做的潜在修改。
①实体对象实现序列化:
@Data
public class Goods implements Serializable {
private Integer goodsId;
private String goodsName;
private Double price;
private Date produceDate;
private String address;
private Category category;
}
②在主配置文件中设置启用二级缓存:
③在需要使用缓存的mapper文件中配置cache标签,默认对当前mapper所有的查询方法生效;
evication:缓存回收策略
①LRU,最近最少使用的,删除最长时间不用的;
②FIFO,先进先出,按对象进入缓存的顺序来移除他们;
③SOFT,软引用,移除基于垃圾回收器状态和软引用规则的对象;
④WEAK,弱引用,更积极的移除基于垃圾回收器状态和弱引用规则的对象。
flushInterval:刷新间隔时间,单位为毫秒,不配置就是当sql被执行时才刷新
size:引用数目,一个正整数,代表缓存最多可以存储多少个对象,设置过大会导致内存溢出
readonly:只读,可以快速的读取缓存,但没办法修改缓存,默认为false。
④在某个查询方法上可以通过useCache单独配置是否启用缓存,默认启用
二级缓存是用来解决一级缓存不能跨会话共享的问题,范围是 namespace 级别的,可以被多个 SqlSession 共享(是同一个接口的相同方法);配置了二级缓存之后,在执行select查询的时候,MyBatis会先从二级缓存中取数据,其次才是一级缓存,故 查询顺序是:二级缓存---->一级缓存 ----> 数据库
注:二级缓存不能和延迟加载一起使用。
除了 xml 配置映射对象外,也可以通过注解配置。
简单注解有:
@Insert @Update @Delete @Select
public interface ClassInfoMapper {
@Select("select * from class")
List studentList();
@Insert("insert into class(name) value (#{name})")
int insert(Class c);
@Update("update class set name = #{name} where id = #{id}")
int update(Class c);
@Delete("delete from class where id = #{id}")
int delete(Integer id);
}
public interface StudentMapper {
@Select("select * from stu")
@Results(
@Result(
property = "classInfo",
column = "clsId",
one = @One(select = "com.mapper.ClassInfoMapper.classList")
))
List studentList();
}
public interface ClassInfoMapper {
@Select("select * from classinfo where class_id = #{id}")
List classList();
}