缓存的概念
缓存是介于应用程序和永久性数据存储源(如硬盘上的文件或者数据库)之间,其作用是降低应用程序直接读写永久性数据存储源的频率,从而提高应用的运行性能。
当客户端第一次访问数据库时,数据库吧响应结果传递给客户端,客户端将结果保存到(缓存)本地内存中,当下一次如果是是同样的请求,直接从缓存去取,降低了与数据库访问的频率,极大的提高了系统的性能
1、一级缓存
在mybatis中默认开启的是一级缓存,作用范围:一次会话,一级缓存是相对于sqlSession而言的,当执行的sql是同一条时,会使用同一个sqlSession对象调用一个mapper方法,往往会只执行一次sql,使用SelSession第一次查询后,MyBatis会将其放在缓存中,以后再查询的时候,如果没有声明需要刷新,并且缓存没有超时的情况下,SqlSession都会取出当前缓存的数据,而不会再次发送SQL到数据库。

1.1、一级缓存的生命周期
a、MyBatis在开启一个数据库会话时,会 创建一个新的SqlSession对象,SqlSession对象中会有一个新的Executor对象。Executor对象中持有一个新的PerpetualCache对象;当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉。
b、如果SqlSession调用了close()方法,会释放掉一级缓存PerpetualCache对象,一级缓存将不可用。
c、如果SqlSession调用了clearCache(),会清空PerpetualCache对象中的数据,但是该对象仍可使用。
d、SqlSession中执行了任何一个update操作(update()、delete()、insert()) ,都会清空PerpetualCache对象的数据,但是该对象可以继续使用
1.2、判断某两次查询是同一查询
在mybatis提供了以下条件,可以知道是同一查询
a、传入的statementId
b、查询时要求的结果集中的结果范围
c、 这次查询所产生的最终要传递给JDBC java.sql.Preparedstatement的Sql语句字符串(boundSql.getSql() )
d、 传递给java.sql.Statement要设置的参数值
@Test
public void query2() throws IOException {
SqlSession session = DbUtils.getInstace().openSession();
//通过Java动态代理自动提供了UserMapper的实现类
EmpMapper mapper = session.getMapper(EmpMapper.class);
// 第一次查询,从数据库中查询的数据会保存在一级缓存中
// key:
List<Emp> list = mapper.query();
for (Emp emp : list) {
System.out.println(emp.getId()+","+emp.getName());
}
System.out.println("----------");
// 先查看缓存中是否有该数据,如果没有就从数据库中查询
Emp emp = mapper.queryById(1);
System.out.println(emp.getId()+","+emp.getName());
System.out.println("----------");
// 之前查询的有,直接从缓存中获取
emp = mapper.queryById(1);
System.out.println(emp.getId()+","+emp.getName());
session.close();
}
测试结果

二级缓存
二级缓存的作用级别是application,可以提高对数据库查询的效率,提高系统的性能

sqlSessionFactory层面上的二级缓存是默认不开启的,如果要开启需要配置,在实现二级缓存的时候,mybatis需要我们返回的pojo对象要序列化,即实现Serializable接口,配置很简单,在映射文件中开启就好
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
<!--
eviction:代表的是缓存回收策略,目前MyBatis提供以下策略
(1) LRU,最近最少使用的,移除最长时间不用的对象
(2) FIFO,先进先出(类似于队列),按对象进入缓存的顺序来移除它们
(3) SOFT,软引用,移除基于垃圾回收器状态和软引用规则的对象
(4) WEAK,弱引用,更积极的移除基于垃圾收集器状态和弱引用规则的对象。这里采用的是LRU,
移除最长时间不用的对形象
flushInterval:刷新间隔时间,单位为毫秒,这里配置的是100秒刷新,如果你不配置它,那么当
SQL被执行的时候才会去刷新缓存。
size:引用数目,一个正整数,代表缓存最多可以存储多少个对象,不宜设置过大。设置过大会导致内存溢出。
这里配置的是1024个对象
readOnly:只读,意味着缓存数据只能读取而不能修改,这样设置的好处是我们可以快速读取缓存,缺点是我们没有
办法修改缓存,他的默认值是false,不允许我们修改
-->
配置二级缓存的效果:
1、映射语句文件中的所有select语句将会被缓存。
2、映射语句文件中的所欲insert、update和delete语句会刷新缓存。
3、缓存会使用默认的Least Recently Used(LRU,最近最少使用的)算法来收回。
4、根据时间表,比如No Flush Interval,(CNFI没有刷新间隔),缓存不会以任何时间顺序来刷新。
5、缓存会存储列表集合或对象(无论查询方法返回什么)的1024个引用
6、缓存会被视为是read/write(可读/可写)的缓存,意味着对象检索不是共享的,而且可以安全的被调用者修改,不干扰其他调用者或线程所做的潜在修改。
导入相关依赖
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>1.5.0</version>
</dependency>
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.1.0</version>
</dependency>
实现serializable接口的POJO类
package com.zhouym.pojo;
import java.io.Serializable;
public class User implements Serializable{
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
private Integer age;
private String address;
private String hobby;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", age=" + age + ", address=" + address + ", hobby=" + hobby + "]";
}
}
结果

我们在实际开发中,使用mybatis自带的缓存很少,都选择使用的是第三方的缓存技术,例如:EhCache,redis等等
221

被折叠的 条评论
为什么被折叠?



