Mybatis入门学习(九、缓存)
缓存
缓存,就是优化数据库性能的一个机制,如果每次发送请求,都要访问数据库,中间的时间以及性能损伤有点大,如果你每次数据都保存在客户端,第二次用的时候,直接获取就很方便了
缓存分类
- 一级缓存(SQLSession级别)
- 二级缓存(SQLSessionFactory级别)
下面用示意图解释:
一级缓存:
二级缓存:
一级缓存
-
程序默认是使用一级缓存的,但是有以**意事项:
-
如果执行增删改的话会刷新缓存,也就是缓存中的数据会不存在
-
下面通过看代码进一步了解
JoinUserDao joinUserDao=sqlSession.getMapper(JoinUserDao.class); User user=joinUserDao.findById(2); System.out.println(user); user=joinUserDao.findById(2); System.out.println(user);
-
这里我执行了两次查询操作,都是查询的ID=2的信息,
-
那么接下来看控制台信息
控制台只发送了一次sql语句,很明显就是第二次数据就是从我们的缓存中获取的
缓存刷新
那么接下来:我们看看如果提交事务以及增删改会不会刷新
JoinUserDao joinUserDao=sqlSession.getMapper(JoinUserDao.class);
User user=joinUserDao.findById(2);
System.out.println(user);
sqlSession.commit();
user=joinUserDao.findById(2);
System.out.println(user);
这里我们只是单纯的加了一句提交事务,我们看结果
很明显没有被刷新,那么接下来看我们新增一条数据
JoinUserDao joinUserDao=sqlSession.getMapper(JoinUserDao.class);
User user=joinUserDao.findById(2);
System.out.println(user);
User user2=new User("800", "qsd", "123");
joinUserDao.add(user2);
sqlSession.commit();
user=joinUserDao.findById(2);
System.out.println(user);
然后我们看看结果
部分总结:
- 很明显看出,程序是默认使用一级缓存的
- 以及缓存的作用于仅仅是SQLSession,所以如果新创建一个SQLSession,缓存也是不存在的
- 执行提交事务的时候,不会刷新,但是增删改的时候会刷新
二级缓存
- 二级缓存需要设置
- 二级缓存需要关闭一级缓存才能存进去
- 增删改也会刷新二级缓存
- 实体类必须要序列化,因为二级缓存一般不是在本地,需要用序列化才能发送数据
二级缓存设置:
<setting name="cacheEnabled" value="true"/>
<!-- 在Mapper文件中设置-->
<cache></cache>
<!-- 实体类实现序列化-->
public class User implements Serializable{}
二级缓存测试
JoinUserDao joinUserDao=sqlSession.getMapper(JoinUserDao.class);
User user=joinUserDao.findById(2);
System.out.println(user);
sqlSession.commit();
sqlSession.close();
SqlSession sqlSession1=sessionFactory.openSession();
JoinUserDao joinUserDao1=sqlSession1.getMapper(JoinUserDao.class);
User user1=joinUserDao1.findById(2);
System.out.println(user1);
- 这里先关闭了sqlSession,把一级缓存刷入二级缓存
- 然而后面从新开启链接,就实现了缓存
- 下面看结果
二级缓存刷新
JoinUserDao joinUserDao=sqlSession.getMapper(JoinUserDao.class);
User user=joinUserDao.findById(2);
System.out.println(user);
User user2=new User("800", "qsd", "123");
joinUserDao.add(user2);
sqlSession.commit();
sqlSession.close();
SqlSession sqlSession1=sessionFactory.openSession();
JoinUserDao joinUserDao1=sqlSession1.getMapper(JoinUserDao.class);
User user1=joinUserDao1.findById(2);
System.out.println(user1);
-
这里和刚刚一样的,也是加了一个新增属性进去
-
然后我们看结果
-
这里我们需要注意一下这个测试顺序
JoinUserDao joinUserDao=sqlSession.getMapper(JoinUserDao.class); SqlSession sqlSession1=sessionFactory.openSession(); JoinUserDao joinUserDao1=sqlSession1.getMapper(JoinUserDao.class); User user=joinUserDao.findById(2); System.out.println(user); sqlSession.commit(); sqlSession.close(); User user2=new User("800", "qsd", "123"); joinUserDao.add(user2); User user1=joinUserDao1.findById(2); System.out.println(user1);
-
如果你顺序是这样写的话就会出错
-
因为你都关闭了事务了,新增是加不进去的
关闭缓存刷新
<insert id="add" parameterType="domain.User" flushCache="false">
insert into tb_user (id,username,password) values(#{id},#{username},#{password})
</insert>
-
我们看到了flushCache属性,可以设置为新增的时候不刷新缓存,默认是true(刷新)
-
下面看下测试代码
JoinUserDao joinUserDao=sqlSession.getMapper(JoinUserDao.class); SqlSession sqlSession1=sessionFactory.openSession(); JoinUserDao joinUserDao1=sqlSession1.getMapper(JoinUserDao.class); User user=joinUserDao.findById(2); System.out.println(user); User user2=new User("800", "qsd", "123"); joinUserDao.add(user2); sqlSession.commit(); user=joinUserDao.findById(2); System.out.println(user); sqlSession.close(); User user1=joinUserDao1.findById(2); System.out.println(user1);
-
这个代码和之前的一样的,只是我们测试了一级缓存以及二级缓存看是否刷新
-
下面看结果
很清楚的看见,缓存都没有被刷新,都被保留下来了
禁用二级缓存
<select id="findById" parameterType="int" resultMap="UserMap" useCache="false">
select * from tb_user u,tb_banji b where u.id=b.uid and u.username=b.username and u.id=#{id}
</select>
-
useCache=“false” 这个属性就是禁用二级缓存,但是一级缓存保留
-
接下来看下测试代码
JoinUserDao joinUserDao=sqlSession.getMapper(JoinUserDao.class); SqlSession sqlSession1=sessionFactory.openSession(); JoinUserDao joinUserDao1=sqlSession1.getMapper(JoinUserDao.class); User user=joinUserDao.findById(2); System.out.println(user); user=joinUserDao.findById(2); System.out.println(user); sqlSession.close(); User user1=joinUserDao1.findById(2); System.out.println(user1);
-
我们来看下结果,就可以知道
-
可以明显看出,禁用的是二级缓存,然而一级缓存还是保留了的
总结
- 一级缓存是基于SQLSession而二级缓存是基于SQLSEssionFactory
- 二级缓存在不同的SQLSession可以实现数据共享
- 查询的结果默认是一级缓存,通过配置可以刷入二级缓存中
- 配置二级缓存条件如下
- 启用二级缓存
- Mapper文件支持
- 实体类实现序列化
- 关闭一级缓存
- 禁用缓存是:userCache
- 刷新缓存是:flushCache
- 清空缓存是:sqlSession.clearCache();
- 缓存的应用场景:
- 实时性要求不高,更多的是查询业务多
- 有一定的局限性,一但增删改就会影响数据