Mybatis的一级缓存与二级缓存
1. 缓存的概念
缓存的概念
- 在内存中临时存储数据,速度快,可以减少数据库的访问次数。
- 经常需要查询,不经常修改的数据,不是特别重要的数据都适合于存储到缓存中。
2. MyBatis的一级缓存
MyBatis的一级缓存也是SqlSession的缓存。
SqlSession对象中维护了一个Map集合,用于存储相互的缓存数据。
查询的时候,先从SqlSession的缓存中查找,如果有,直接返回。如果没有,查询数据库。
证明一级缓存的存在,通过用户id查询2次,查看结果。
测试代码:
@Testpublic void findById() {User user1 = mapper.findById(1);System.out.println(user1);User user2 = mapper.findById(1);System.out.println(user2);}
结果:
此时我们发现,这里只有一条sql查询语句,说明第一次是通过数据库查询到的信息,而第二次没有查询数据库,直接就显示了信息,说明信息是从缓存获得的
再直观一点:清理session的缓存再进行信息查询
测试代码:
@Testpublic void findById() {User user1 = mapper.findById(1);System.out.println(user1);//清理掉之前缓存的数据session.clearCache();User user2 = mapper.findById(1);System.out.println(user2);}
结果:
显而易见,缓存消失,查询了两次数据库
5.一级缓存的原理分析
1.一级缓存底层使用的是Map集合,key存储的是执行的SQL语句,value存放的是查询的对象
2.BaseExecutor类的152行源码地方先查询缓存,再查询数据库
3.一级缓存的生命周期和SlSession的生命周期相同,SalSession对象关闭,一级缓存也会关闭。
1.session.clearCache()调用该方法可以清空缓存
2.调用调用SalSession的update、insert、delete、commit和close等方法的时候也会清
空缓存。
3. MyBatis的二级缓存
1.二级缓存是全局缓存,范围跨越多个SqlSession,可以再不同的Mapper之间共享
2.应用启动时创建,应用关闭时销毁
3.缓存对象必须实现Serializable接口
2.1二级缓存的配置步骤:
1.全局启用二级缓存(Mybatis总配置文件里)
<settings><setting name="cacheEnabled" value="true"/> <!-- 必须设置为 true -->
</settings>
2.在Mapper中声明缓存
2.2测试代码
import com.qcby.entity.User;
import com.qcby.mapper.AccountMapper;
import com.qcby.mapper.UserMapper;
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 org.junit.After;
import org.junit.Before;
import org.junit.Test;import java.io.IOException;
import java.io.InputStream;
import java.util.List;public class UserTest {private InputStream in;private SqlSessionFactory factory;@Beforepublic void init() throws Exception {// 加载配置文件in = Resources.getResourceAsStream("SqlMap.xml");// 创建工厂对象factory = new SqlSessionFactoryBuilder().build(in);System.out.println("执行开始");}@Afterpublic void destory() throws IOException {in.close();System.out.println("执行结束");}
// @Test
// public void findOneToMany() {
// List<User> users = mapper.findOneToMany();
// for (User user : users) {
// System.out.println(user);
// }
// }@Testpublic void findById() {SqlSession session = factory.openSession();UserMapper mapper = session.getMapper(UserMapper.class);User user1 = mapper.findById(1);System.out.println(user1);session.close();SqlSession session2 = factory.openSession();UserMapper mapper1 = session2.getMapper(UserMapper.class);User user2 = mapper1.findById(1);System.out.println(user2);session.close();}
}
两次查询获取到的不是同一个对象,说明是第个信息是从二级缓存中获取的
4.二级缓存工作流程
第一次查询 (
user1
):查询数据库获取数据
将结果存入一级缓存(SqlSession级别)
当
session.close()
时,一级缓存内容会序列化后存入二级缓存(SqlSessionFactory级别)
第二次查询 (
user2
):新Session首先检查自己的一级缓存 → 没有(因为是新Session)
检查二级缓存 → 找到缓存数据
将缓存数据反序列化后创建新对象返回
不会访问数据库(这就是为什么对象不同但数据相同)
感谢您的观看