1.一级缓存
Mybatis的一级缓存是指SqlSession。一级缓存的作用域是一个SqlSession。Mybatis默认开启一级缓存。
在同一个SqlSession中,执行相同的查询SQL,第一次会去查询数据库,并写到缓存中;
第二次直接从缓存中取。当执行SQL时两次查询中间发生了增删改操作,则SqlSession的缓存清空。
2.一级缓存demo
这里根据sqlSessionFactory获取sqlsession,再用两个相同的条件用同一个sqlsession进行查询。
@Autowired
private SqlSessionFactory sessionFactory;
@Test
public void contextLoads() {
SqlSession sqlSession1 = sessionFactory.openSession();
UserDao userMapper1 = sqlSession1.getMapper(UserDao.class);
User user = userMapper1.loadById(1l);
User user2 = userMapper1.loadById(1l);
sqlSession1.close();
}
这里可以看到输出日志,只进行了一次数据查询。
JDBC Connection [HikariProxyConnection@384283650 wrapping com.mysql.jdbc.JDBC4Connection@534c6767] will not be managed by Spring
==> Preparing: SELECT * FROM user WHERE id = ?
==> Parameters: 1(Long)
<== Columns: id, name
<== Row: 1, 张三
<== Total: 1
11:29:15.468 [Thread-2] INFO o.s.w.c.s.GenericWebApplicationContext - Closing org.springframework.web.context.support.GenericWebApplicationContext@5b799640: startup date [Sun Sep 16 11:29:10 CST 2018]; root of context hierarchy
这里依然还是同一个sqlsession,首先先执行查询,其次在做修改操作,再执行查询操作。
@Autowired
private SqlSessionFactory sessionFactory;
@Test
public void contextLoads() {
SqlSession sqlSession1 = sessionFactory.openSession();
UserDao userMapper1 = sqlSession1.getMapper(UserDao.class);
//第一次查询,发出sql语句,并将查询的结果放入缓存中
User user = userMapper1.loadById(1l);
//第二步进行了一次更新操作,sqlSession.commit()
user.setName("李四");
userMapper1.update(user);
sqlSession1.commit();
//第二次查询,由于是同一个sqlSession.commit(),会清空缓存信息
//则此次查询也会发出 sql 语句,并将查询的结果放入缓存中
User user2 = userMapper1.loadById(1l);
//第三次查询,从缓存中获取
User user3 = userMapper1.loadById(1l);
sqlSession1.close();
}
这里可以看到输出日志,因为数据更新,缓存会被清除。
JDBC Connection [HikariProxyConnection@698437724 wrapping com.mysql.jdbc.JDBC4Connection@24db6ce] will not be managed by Spring
==> Preparing: SELECT * FROM user WHERE id = ?
==> Parameters: 1(Long)
<== Columns: id, name
<== Row: 1, 李四
<== Total: 1
==> Preparing: UPDATE user SET name=? WHERE id=?
==> Parameters: 李四(String), 1(Long)
<== Updates: 1
==> Preparing: SELECT * FROM user WHERE id = ?
==> Parameters: 1(Long)
<== Columns: id, name
<== Row: 1, 李四
<== Total: 1
11:38:06.010 [Thread-2] INFO o.s.w.c.s.GenericWebApplicationContext - Closing org.springframework.web.context.support.GenericWebApplicationContext@5b799640: startup date [Sun Sep 16 11:38:00 CST 2018]; root of context hierarchy
1.二级缓存
Mybatis的二级缓存是指mapper映射文件。二级缓存的作用域是同一个namespace下的mapper映射文件内容,
多个SqlSession共享。Mybatis需要手动设置启动二级缓存。
在同一个namespace下的mapper文件中,执行相同的查询SQL,第一次会去查询数据库,并写到缓存中;
第二次直接从缓存中取。当执行SQL时两次查询中间发生了增删改操作,则二级缓存清空。
2.一级缓存demo
和一级缓存默认开启不一样,二级缓存需要我们手动开启首先在全局配置文件 mybatis-configuration.xml 文件中加入如下代码
<!--开启二级缓存 -->
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
其次在 UserMapper.xml 文件中开启缓存
<!-- 开启二级缓存 -->
<cache></cache>
开启了二级缓存后,还需要将要缓存的pojo实现Serializable接口,
为了将缓存数据取出执行反序列化操作,因为二级缓存数据存储介质多种多样,不一定只存在内存中,
有可能存在硬盘中,如果我们要再取这个缓存的话,就需要反序列化了。
@Data
public class User implements Serializable {
private static final long serialVersionUID = 7592001409898062289L;
private Long id;
private String name;
}
这里用两个不同sqlsession,执行数据查询
@Autowired
private SqlSessionFactory sessionFactory;
@Test
public void contextLoads() {
SqlSession sqlSession1 = sessionFactory.openSession();
SqlSession sqlSession2 = sessionFactory.openSession();
UserDao userMapper1 = sqlSession1.getMapper(UserDao.class);
UserDao userMapper2 = sqlSession2.getMapper(UserDao.class);
//第一次查询,发出sql语句,并将查询的结果放入缓存中
User user1 = userMapper1.loadById(1l);
//第一次查询完后关闭sqlSession
sqlSession1.close();
User user2 = userMapper2.loadById(1l);
sqlSession2.close();
}
可以看出上面两个不同的sqlSession,第一个关闭了,第二次查询依然不发出sql查询语句
JDBC Connection [HikariProxyConnection@1004390006 wrapping com.mysql.jdbc.JDBC4Connection@29a1505c] will not be managed by Spring
==> Preparing: SELECT * FROM user WHERE id = ?
==> Parameters: 1(Long)
<== Columns: id, name
<== Row: 1, 李四
<== Total: 1
Cache Hit Ratio [com.mljr.movies.dao.UserDao]: 0.5
12:15:58.284 [Thread-2] INFO o.s.w.c.s.GenericWebApplicationContext - Closing org.springframework.web.context.support.GenericWebApplicationContext@5b799640: startup date [Sun Sep 16 12:15:52 CST 2018]; root of context hierarchy
这里执行更新操作,二级缓存数据清空
@Autowired
private SqlSessionFactory sessionFactory;
@Test
public void contextLoads() {
SqlSession sqlSession1 = sessionFactory.openSession();
SqlSession sqlSession2 = sessionFactory.openSession();
SqlSession sqlSession3 = sessionFactory.openSession();
SqlSession sqlSession4 = sessionFactory.openSession();
UserDao userMapper1 = sqlSession1.getMapper(UserDao.class);
UserDao userMapper2 = sqlSession2.getMapper(UserDao.class);
UserDao userMapper3 = sqlSession3.getMapper(UserDao.class);
UserDao userMapper4 = sqlSession4.getMapper(UserDao.class);
//第一次查询,发出sql语句,并将查询的结果放入缓存中
User user1 = userMapper1.loadById(1l);
//第一次查询完后关闭sqlSession
sqlSession1.close();
//执行更新操作,清空缓存
user1.setName("王二");
userMapper2.update(user1);
sqlSession2.commit();
sqlSession2.close();
//第二次查询,发出sql语句,并将查询的结果放入缓存中
User user3 = userMapper3.loadById(1l);
sqlSession3.close();
//第三次查询用缓存获取
User user4 = userMapper4.loadById(1l);
sqlSession4.close();
}
这里可以看到控制台情况,第一次查询输出sql,放入缓存;第二次更新操作,清空缓存;第三次查询因为缓存清空获取不到,所以再次输出sql;第四次查询,从缓存中获取。
JDBC Connection [HikariProxyConnection@1739653374 wrapping com.mysql.jdbc.JDBC4Connection@44b18fe4] will not be managed by Spring
==> Preparing: SELECT * FROM user WHERE id = ?
==> Parameters: 1(Long)
<== Columns: id, name
<== Row: 1, 王二
<== Total: 1
JDBC Connection [HikariProxyConnection@688722159 wrapping com.mysql.jdbc.JDBC4Connection@44b18fe4] will not be managed by Spring
==> Preparing: UPDATE user SET name=? WHERE id=?
==> Parameters: 王二(String), 1(Long)
<== Updates: 1
Cache Hit Ratio [com.mljr.movies.dao.UserDao]: 0.0
JDBC Connection [HikariProxyConnection@1682828548 wrapping com.mysql.jdbc.JDBC4Connection@44b18fe4] will not be managed by Spring
==> Preparing: SELECT * FROM user WHERE id = ?
==> Parameters: 1(Long)
<== Columns: id, name
<== Row: 1, 王二
<== Total: 1
Cache Hit Ratio [com.mljr.movies.dao.UserDao]: 0.3333333333333333
12:24:33.618 [Thread-2] INFO o.s.w.c.s.GenericWebApplicationContext - Closing org.springframework.web.context.support.GenericWebApplicationContext@5b799640: startup date [Sun Sep 16 12:24:28 CST 2018]; root of context hierarchy
mybatis中还可以配置userCache和flushCache等配置项
userCache是用来设置是否禁用二级缓存的,
在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,
默认情况是true,即该sql使用二级缓存。
<!-- 根据id查询 -->
<select id="loadById" resultMap="userResultMap" useCache="false">
SELECT * FROM user WHERE id =
#{id}
</select>
设置statement配置中的flushCache=”true” 属性,默认情况下为true,
即刷新缓存,如果改成false则不会刷新。使用缓存时如果手动修改数据库表中的查询数据会出现脏读。
<!-- 根据id查询 -->
<select id="loadById" resultMap="userResultMap" flushCache="false">
SELECT * FROM user WHERE id =
#{id}
</select>