一、前提知识
一级缓存默认开启, 二级缓存默认是不开启的.
一, 二级的作用范围
二、一级缓存
package com.softeem.wolf.utils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.Reader;
/**
* Created by 苍狼
* Time on 2021-12-20
*/
public class MybatisUtil {
/**
* 让sqlSessionFactory全局唯一, 可以将它变成static修饰的, 这样它就不属于某个对象, 而属于MybatisUtil类了
*/
private static SqlSessionFactory sqlSessionFactory = null;
static {
try{
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
//一旦成功创建了SqlSessionFactory对象, 代表Mybatis的环境已经被初始化了
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
} catch (IOException e){
e.printStackTrace();
//抛出异常, 让调用方知道初始化失败了
throw new ExceptionInInitializerError(e);
}
}
/**
* 创建连接
* @return
*/
public static SqlSession createSession(){
return sqlSessionFactory.openSession();
}
public static void closeSession(SqlSession sqlSession){
if (sqlSession != null) {
sqlSession.close();
}
}
}
测试类
@Test
public void test01(){
SqlSession sqlSession = null;
try{
sqlSession = MybatisUtil.createSession();
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
Student student = mapper.selectStudentById(1);
Student student1 = mapper.selectStudentById(1);
System.out.println(student);
System.out.println(student1);
System.out.println(student.hashCode());
System.out.println(student1.hashCode());
System.out.println(student==student1);
} catch (Exception e){
e.printStackTrace();
} finally {
MybatisUtil.closeSession(sqlSession);
}
}
运行结果
从这里可以看出一级缓存默认是开启的, 不需要再配置文件中开启, 还有就是一级缓存是作用在SqlSession类上.
测试类:
@Test
public void test05(){
SqlSession sqlSession1 = null;
SqlSession sqlSession2 = null;
try{
sqlSession1 = MybatisUtil.createSession();
sqlSession2 = MybatisUtil.createSession();
StudentDao mapper1 = sqlSession1.getMapper(StudentDao.class);
StudentDao mapper2 = sqlSession2.getMapper(StudentDao.class);
Student student1 = mapper1.selectStudentById(1);
Student student2 = mapper2.selectStudentById(1);
System.out.println(student1.hashCode());
System.out.println(student2.hashCode());
} catch (Exception e){
e.printStackTrace();
} finally {
MybatisUtil.closeSession(sqlSession1);
MybatisUtil.closeSession(sqlSession2);
}
}
运行结果:
三、二级缓存
1、xml 配置中开启 二级缓存
<settings>
<!-- 开启二级缓存(默认是开的,这里写出来是为了方便代码维护) -->
<setting name="cacheEnabled" value="true" />
</settings>
2、去mapper映射文件中使用二级缓存
<!-- 开启本mapper所在namespace的二级缓存 -->
<cache />
<cache eviction="LRU" flushInterval="60000" size="1024" readOnly="false"/>
@Test
public void test06(){
SqlSession sqlSession1 = null;
try{
sqlSession1 = MybatisUtil.createSession();
StudentDao mapper1 = sqlSession1.getMapper(StudentDao.class);
Student student1 = mapper1.selectStudentById(1);
Student student2 = mapper1.selectStudentById(1);
System.out.println(student1.hashCode());
System.out.println(student2.hashCode());
} catch (Exception e){
e.printStackTrace();
} finally {
MybatisUtil.closeSession(sqlSession1);
}
SqlSession sqlSession2 = null;
try{
sqlSession2 = MybatisUtil.createSession();
StudentDao mapper1 = sqlSession2.getMapper(StudentDao.class);
Student student1 = mapper1.selectStudentById(1);
Student student2 = mapper1.selectStudentById(1);
System.out.println(student1.hashCode());
System.out.println(student2.hashCode());
} catch (Exception e){
e.printStackTrace();
} finally {
MybatisUtil.closeSession(sqlSession1);
}
}
运行结果:
总结:
<cache eviction="LRU" flushInterval="60000" size="1024" readOnly="false"/>
- LRU(Least Recently Used 默认) – 最近最少使用:移除最长时间不被使用的对象。比较符合我们的预期的 ,因为缓存就是希望保留热点数据,淘汰非热点数据
- FIFO(First In First Out) – 先进先出:类似于队列,按对象进入缓存的顺序来移除它们。
- SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
- WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。比软引用更弱
- -false的情况,缓存的对象必须要实现序列化接口,这是因为拿到的缓存对象不是原本缓存的对 象 ,是因为在false的情况下,Mybatis对缓存的对象进行了拷贝,拷贝需要序列化,这样的情况,因为涉及到序列化的操作,所以效率会更慢一些,但是更安全.
- -true代表只读,就是拿到的缓存对象就是原本缓存的那个对象
清空缓存的方式
- 1、 session.clearCache( ) ;
- 2、 execute update(增删改) ;
- 3、 session.close( );
- 4、 xml配置 flushCache=“true” ;
- 5、 rollback;
- 6、 commit。
true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此返回的这些缓存对象自己没事不要去修改。一旦修改,就会影响下一个相同查询条件的查询结果。这提供了很重要的性能优势。
false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这些对象可以随意修改,不会影响后续相同查询条件的结果。这会慢一些,但是安全,因此默认是false。
测试一:
<cache eviction="LRU" flushInterval="60000" size="1024" readOnly="true"/>
@Test
public void test06(){
SqlSession sqlSession1 = null;
try{
sqlSession1 = MybatisUtil.createSession();
StudentDao mapper1 = sqlSession1.getMapper(StudentDao.class);
Student student1 = mapper1.selectStudentById(1);
Student student2 = mapper1.selectStudentById(1);
System.out.println(student1.hashCode());
System.out.println(student2.hashCode());
} catch (Exception e){
e.printStackTrace();
} finally {
MybatisUtil.closeSession(sqlSession1);
}
SqlSession sqlSession2 = null;
try{
sqlSession2 = MybatisUtil.createSession();
StudentDao mapper1 = sqlSession2.getMapper(StudentDao.class);
Student student1 = mapper1.selectStudentById(1);
System.out.println(student1);
student1.setStudentName("aaaa");
System.out.println(student1);
} catch (Exception e){
e.printStackTrace();
} finally {
MybatisUtil.closeSession(sqlSession1);
}
try{
StudentDao mapper1 = sqlSession2.getMapper(StudentDao.class);
Student student1 = mapper1.selectStudentById(1);
System.out.println(student1);
} catch (Exception e){
e.printStackTrace();
} finally {
MybatisUtil.closeSession(sqlSession1);
}
}
运行结果:
测试二:
<cache eviction="LRU" flushInterval="60000" size="1024" readOnly="false"/>
@Test
public void test06(){
SqlSession sqlSession1 = null;
try{
sqlSession1 = MybatisUtil.createSession();
StudentDao mapper1 = sqlSession1.getMapper(StudentDao.class);
Student student1 = mapper1.selectStudentById(1);
Student student2 = mapper1.selectStudentById(1);
System.out.println(student1.hashCode());
System.out.println(student2.hashCode());
} catch (Exception e){
e.printStackTrace();
} finally {
MybatisUtil.closeSession(sqlSession1);
}
SqlSession sqlSession2 = null;
try{
sqlSession2 = MybatisUtil.createSession();
StudentDao mapper1 = sqlSession2.getMapper(StudentDao.class);
Student student1 = mapper1.selectStudentById(1);
System.out.println(student1);
student1.setStudentName("aaaa");
System.out.println(student1);
} catch (Exception e){
e.printStackTrace();
} finally {
MybatisUtil.closeSession(sqlSession1);
}
try{
StudentDao mapper1 = sqlSession2.getMapper(StudentDao.class);
Student student1 = mapper1.selectStudentById(1);
System.out.println(student1);
} catch (Exception e){
e.printStackTrace();
} finally {
MybatisUtil.closeSession(sqlSession1);
}
}
运行结果:
总结:
- 当readOnly为false时,修改返回的缓存对象(的拷贝),不会修改缓存中的数据。
- 当readOnly为true时,修改返回的缓存对象(的相同实例),会修改缓存中的数据,影响下一次相同查询条件的查询结果。