一级缓存
概念
其实就是将查询出来的数据备份一份,再次需要该数据时,直接从备份数据中取出来,省去了再次查询数据库的时间。
创建数据库连接后,会使用到sqlsession对象,调用一个select语句后,返回的结果会存储到一个map中,再次调用该select时,会从map中获取到该数据,不会去从数据库查询。
当调用update、delete、insert时,缓存中的数据会被清除。
实现
同一个sqlsession两次select
public class UserMapperTest {
public SqlSession sqlSession;
public SqlSessionFactory sqlSessionFactory;
public UserMapper userMapper;
@Before
public void setUp() throws Exception {
String resource = "mybatis_config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
this.sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
this.sqlSession = sqlSessionFactory.openSession(true);
this.userMapper = sqlSession.getMapper(UserMapper.class);
}
@Test
public void testQueryUserByTableName() {
User user = this.userMapper.queryUserByName("静静");
System.out.println(user);
User user2 = this.userMapper.queryUserByName("静静");
System.out.println(user2);
}
}
输出
2020-05-28 22:19:23,231 [main] [dao.UserMapper.queryUserByName]-[DEBUG] ==> Preparing: select * from tb_user where name = ?
2020-05-28 22:19:23,251 [main] [dao.UserMapper.queryUserByName]-[DEBUG] ==> Parameters: 静静(String)
2020-05-28 22:19:23,268 [main] [dao.UserMapper.queryUserByName]-[DEBUG] <== Total: 1
User{id='1', userName='evan', password='123456', name='静静', age=16, sex=1, birthday='1990-09-01', created='2020-03-28 04:52:01', updated='2020-03-29 08:31:04'}
User{id='1', userName='evan', password='123456', name='静静', age=16, sex=1, birthday='1990-09-01', created='2020-03-28 04:52:01', updated='2020-03-29 08:31:04'}
同一个sqlsession中update另一张表
@Test
public void testQueryUserByTableName() {
User user = this.userMapper.queryUserByName("静静");
System.out.println(user);
//update另一张表
Book book = new Book();
book.setId(1);
book.setPrice(BigDecimal.valueOf(2));
BookMapper mapper = sqlSession.getMapper(BookMapper.class);
mapper.updateByPrimaryKeySelective(book);
User user2 = this.userMapper.queryUserByName("静静");
System.out.println(user2);
}
输出
2020-05-28 22:50:10,796 [main] [dao.UserMapper.queryUserByName]-[DEBUG] ==> Preparing: select * from tb_user where name = ?
2020-05-28 22:50:10,820 [main] [dao.UserMapper.queryUserByName]-[DEBUG] ==> Parameters: 静静(String)
2020-05-28 22:50:10,837 [main] [dao.UserMapper.queryUserByName]-[DEBUG] <== Total: 1
User{id='1', userName='evan', password='123456', name='静静', age=16, sex=1, birthday='1990-09-01', created='2020-03-28 04:52:01', updated='2020-03-29 08:31:04'}
2020-05-28 22:50:10,861 [main] [dao.BookMapper.updateByPrimaryKeySelective]-[DEBUG] ==> Preparing: update book SET price = ? where id = ?
2020-05-28 22:50:10,861 [main] [dao.BookMapper.updateByPrimaryKeySelective]-[DEBUG] ==> Parameters: 2(BigDecimal), 1(Integer)
2020-05-28 22:50:10,868 [main] [dao.BookMapper.updateByPrimaryKeySelective]-[DEBUG] <== Updates: 1
2020-05-28 22:50:10,868 [main] [dao.UserMapper.queryUserByName]-[DEBUG] ==> Preparing: select * from tb_user where name = ?
2020-05-28 22:50:10,869 [main] [dao.UserMapper.queryUserByName]-[DEBUG] ==> Parameters: 静静(String)
2020-05-28 22:50:10,873 [main] [dao.UserMapper.queryUserByName]-[DEBUG] <== Total: 1
User{id='1', userName='evan', password='123456', name='静静', age=16, sex=1, birthday='1990-09-01', created='2020-03-28 04:52:01', updated='2020-03-29 08:31:04'}
调用clearCache效果是一样的
@Test
public void testQueryUserByTableName() {
User user = this.userMapper.queryUserByName("静静");
System.out.println(user);
sqlSession.clearCache();
User user2 = this.userMapper.queryUserByName("静静");
System.out.println(user2);
}
输出
2020-05-28 22:57:18,422 [main] [dao.UserMapper.queryUserByName]-[DEBUG] ==> Preparing: select * from tb_user where name = ?
2020-05-28 22:57:18,443 [main] [dao.UserMapper.queryUserByName]-[DEBUG] ==> Parameters: 静静(String)
2020-05-28 22:57:18,461 [main] [dao.UserMapper.queryUserByName]-[DEBUG] <== Total: 1
User{id='1', userName='evan', password='123456', name='静静', age=16, sex=1, birthday='1990-09-01', created='2020-03-28 04:52:01', updated='2020-03-29 08:31:04'}
2020-05-28 22:57:18,463 [main] [dao.UserMapper.queryUserByName]-[DEBUG] ==> Preparing: select * from tb_user where name = ?
2020-05-28 22:57:18,463 [main] [dao.UserMapper.queryUserByName]-[DEBUG] ==> Parameters: 静静(String)
2020-05-28 22:57:18,466 [main] [dao.UserMapper.queryUserByName]-[DEBUG] <== Total: 1
User{id='1', userName='evan', password='123456', name='静静', age=16, sex=1, birthday='1990-09-01', created='2020-03-28 04:52:01', updated='2020-03-29 08:31:04'}
原理
- 在同一个sqlsession中,调用insert、update、delete其实都是调用了sqlSession.clearCache();
- 缓存存在了哪里(待更新)
应用场景
-
将sqlsession变为单例,在一些不经常更新内容的查询时,使用。
-
开启一个事物。
二级缓存
概念
作用范围是sqlSessionFactory,在一级缓存的基础上,不同的sqlSession调用同样的mapper中方法时,会从二级缓存中取出数据,当输出“Cache Hit Ratio”,说明是从二级缓存获取数据。前提是需要将bean对象序列化,因为二级缓存是将数据存储在磁盘上。
实现
在配置文件中打开缓存
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
在bean对应的xml中增加标签
<mapper namespace="dao.UserMapper">
<cache/>
</mapper>
代码
@Test
public void testSecondCache() {
this.userMapper.queryUserByName("静静");
sqlSession.commit();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
UserMapper userMapperr2 = sqlSession2.getMapper(UserMapper.class);
userMapperr2.queryUserByName("静静");
}
//序列化
public class User implements Serializable{
}
输出
2020-06-02 00:46:54,876 [main] [dao.UserMapper.queryUserByName]-[DEBUG] ==> Preparing: select * from tb_user where name = ?
2020-06-02 00:46:54,897 [main] [dao.UserMapper.queryUserByName]-[DEBUG] ==> Parameters: 静静(String)
2020-06-02 00:46:54,916 [main] [dao.UserMapper.queryUserByName]-[DEBUG] <== Total: 1
2020-06-02 00:46:54,923 [main] [dao.UserMapper]-[DEBUG] Cache Hit Ratio [dao.UserMapper]: 0.5
注意
- 必须调用sqlSession.commit()方法,二级缓存才会生效,否则第二次查询时,调用的是一级缓存。