目录
1.什么是缓存
缓存就是数据交换的缓冲区,当某一硬件要读取数据时,会首先从缓存中查找需要的数据,如果找到了则直接执行,找不到的话则从内存中找。由于缓存的运行速度比内存快得多,故缓存的作用就是帮助硬件更快地运行。
例如 mysql数据库中的数据存在表内也就是在磁盘上。 查询时程序IO读取磁盘的数据,添加时io向磁盘添加数据。
经常查询并且不经常改变的,数据的正确与否对最终结果影响不大的; 这些数据适合放在缓存中。经常改变的数据;数据的正确与否对最终结果影响很大的;---数据安全性要求不高。例如:商品的库存,银行的汇率,股市的牌价; 这些数据不适合放在缓存区。
2.mybatis的缓存
MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。
mybatis支持两种缓存:
(1)一级缓存----基于SqlSession级别的缓存,底层就是一个hashmap。默认一级缓存是开启的,不能关闭。同一个sqlsession中执行相同的sql查询(相同的sql和参数),第一次会去查询数据库并写到缓存中,第二次从一级缓存中取。当执行SQL时候两次查询中间发生了增删改的操作,则SQLSession的缓存会被清空,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
(2)二级缓存--基于SqlSessionFactory级别的缓存,它可以做到多个SqlSession共享数据。默认它是关闭。需要手动开启。 要启用全局的二级缓存,需要在你的 SQL 映射文件中添加一行语句。
2.1一级缓存
一级缓存基于sqlSession完成的一级缓存,第一次查询编号=2的用户信息--缓存不能命中,则向数据库查询发送sql语句、把查询的结果放入缓存中。当sqlSession不关闭时,不需要再在数据库调数据,而是在缓存中直接调取。下面是测试类及控制台显示只调取一次sql语句。
@Test
public void testSession(){
User user = userMapper.getUser(2);
User user1 = userMapper.getUser(2);
}
2022-06-06 19:07:21,399 [main] DEBUG [com.qy151wd.mapper.UserMapper.getUser] - ==> Preparing: select * from tb_user where id=?
2022-06-06 19:07:21,448 [main] DEBUG [com.qy151wd.mapper.UserMapper.getUser] - ==> Parameters: 2(Integer)
2022-06-06 19:07:21,494 [main] DEBUG [com.qy151wd.mapper.UserMapper.getUser] - <== Total: 1
当一个sqlSession关闭时,开启另一个sqlSession语句会重新进行数据库数据调取,会出现两条调取数据库的信息。
@Test
public void testSession(){
User user = userMapper.getUser(2);
User user1 = userMapper.getUser(2);
sqlSession.close();
SqlSession sqlSession1=sqlSessionFactory.openSession();
UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
mapper1.getUser(2);
}
2022-06-06 21:03:16,530 [main] DEBUG [com.qy151wd.mapper.UserMapper.getUser] - ==> Preparing: select * from tb_user where id=?
2022-06-06 21:03:16,576 [main] DEBUG [com.qy151wd.mapper.UserMapper.getUser] - ==> Parameters: 2(Integer)
2022-06-06 21:03:16,618 [main] DEBUG [com.qy151wd.mapper.UserMapper.getUser] - <== Total: 1
2022-06-06 21:03:16,623 [main] DEBUG [com.qy151wd.mapper.UserMapper.getUser] - ==> Preparing: select * from tb_user where id=?
2022-06-06 21:03:16,624 [main] DEBUG [com.qy151wd.mapper.UserMapper.getUser] - ==> Parameters: 2(Integer)
2022-06-06 21:03:16,628 [main] DEBUG [com.qy151wd.mapper.UserMapper.getUser] - <== Total: 1
2.2 二级缓存
2.2.1 开启二级缓存
<settings>
<!--开启二级缓存(conf.xml内)-->
<setting name="cacheEnabled" value="true"/>
</settings>
2.2.2 在映射文件中使用二级缓存
<!--使用二级缓存 这里面的所有查询都使用了二级缓存(对应mapper.xml内)-->
<cache/>
<!--部分开启二级缓存,此处不使用二级缓存-->
<select id="getUser" parameterType="int" resultType="com.qy151wd.entity.User" useCache="false">
select * from tb_user where id=#{id}
</select>
2.2.3 实体一定要实现序列化接口
2.2.4 二级缓存测试
如果开启了二级缓存,那么在关闭sqlsession后(close),才会把该sqlsession一级缓存中的数据添加到namespace的二级缓存中。所查询的结果会放入一级缓存和二级缓存,若二级缓存能命中,则直接从二级缓存中调取数据,若不能命中,会到一级缓存中去查看是否命中,若能则直接调取数据,若不能则进入数据库调取。查询顺序是二级缓存、一级缓存、数据库。
@Test
public void testSessionSecond(){
User user = userMapper.getUser(2);
User user1 = userMapper.getUser(2);
sqlSession.close();
SqlSession sqlSession1=sqlSessionFactory.openSession();
UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
mapper1.getUser(2);
}
2022-06-06 19:51:17,391 [main] DEBUG [com.qy151wd.mapper.UserMapper] - Cache Hit Ratio [com.qy151wd.mapper.UserMapper]: 0.0
2022-06-06 19:51:18,516 [main] DEBUG [com.qy151wd.mapper.UserMapper.getUser] - ==> Preparing: select * from tb_user where id=?
2022-06-06 19:51:18,564 [main] DEBUG [com.qy151wd.mapper.UserMapper.getUser] - ==> Parameters: 2(Integer)
2022-06-06 19:51:18,593 [main] DEBUG [com.qy151wd.mapper.UserMapper.getUser] - <== Total: 1
2022-06-06 19:51:18,597 [main] DEBUG [com.qy151wd.mapper.UserMapper] - Cache Hit Ratio [com.qy151wd.mapper.UserMapper]: 0.0
2022-06-06 19:51:18,604 [main] WARN [org.apache.ibatis.io.SerialFilterChecker] - As you are using functionality that deserializes object streams, it is recommended to define the JEP-290 serial filter. Please refer to https://docs.oracle.com/pls/topic/lookup?ctx=javase15&id=GUID-8296D8E8-2B93-4B9A-856E-0A65AF9B8C66
2022-06-06 19:51:18,607 [main] DEBUG [com.qy151wd.mapper.UserMapper] - Cache Hit Ratio [com.qy151wd.mapper.UserMapper]: 0.3333333333333333