mybati的一级缓存作用域为session,当执行opensession()后,结果和sql会被存入缓存中,如果下次执行的sql(参数 语句)相同就直接从缓存当中拿取,而不再执行sql从数据库查询
mybatis中一级缓存是默认开启的,并且是一直开启的且无法关闭
关闭掉当前的session对象可以达到强制清除缓存的效果
案例演示:
新建一个基本的MyBatis项目
Uesr类:
public class User {
//account的实体封装属性
private String name;
private Integer id;
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id=" + id +
", money=" + money +
'}';
}
private Float money;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Float getMoney() {
return money;
}
public void setMoney(Float money) {
this.money = money;
}
}
UserMapper类(暂时提供一个方法):
public interface UserMapper {
/**
* 根据id查询
*/
public User findAllById(Integer id);
}
TestMybatis测试类:
@Test
public void findAllById() throws IOException {
SqlSession session = MybatisUtil.openSession();
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.findAllById(11);
System.out.println(user);
}
注意这里的MybatisUtil类是单独的把session对象提取出来了
MybatisUtil类:
public class MybatisUtil {
public static SqlSession openSession() throws IOException {
InputStream in = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
SqlSession session = factory.openSession();
return session;
}
}
在测试类中测试一级缓存
不清除session
@Test
public void findAllById() throws IOException {
SqlSession session = MybatisUtil.openSession();
UserMapper mapper = session.getMapper(UserMapper.class);
//第一次查询
User user = mapper.findAllById(11);
System.out.println(user);
//进行第二次查询
User user1 = mapper.findAllById(11);
System.out.println(user1);
}
可以发现两次查询只使用了一次sql语句,使用同一个查询到的结果
控制台输出:
//sql语句
DEBUG [main] - ==> Preparing: select * from account where id = ?
DEBUG [main] - ==> Parameters: 11(Integer)
DEBUG [main] - <== Total: 1
User{name='ccc', id=11, money=1000.0}
User{name='ccc', id=11, money=1000.0}
强制清除掉session
@Test
public void findAllById() throws IOException {
SqlSession session = MybatisUtil.openSession();
UserMapper mapper = session.getMapper(UserMapper.class);
//第一次查询
User user = mapper.findAllById(11);
System.out.println(user);
//清除缓存
session.clearCache();
System.out.println("清除缓存成功");
//进行第二次查询
User user1 = mapper.findAllById(11);
System.out.println(user1);
}
控制台日志打印两次查询使用了两个sql语句
//第一次查询使用的sql
DEBUG [main] - ==> Preparing: select * from account where id = ?
DEBUG [main] - ==> Parameters: 11(Integer)
DEBUG [main] - <== Total: 1
User{name='ccc', id=11, money=1000.0}
清除缓存成功
//第二次查询使用的sql
DEBUG [main] - ==> Preparing: select * from account where id = ?
DEBUG [main] - ==> Parameters: 11(Integer)
DEBUG [main] - <== Total: 1
User{name='ccc', id=11, money=1000.0}
注意: 执行update、insert、delete的时候,会清空缓存;
当然这在逻辑中是绝对正确的,如果你在执行更新,添加 ,删除的时候还保存着上一次的数据和sql的话那么下一次就永远是上一次的结果,且只会是第一次的结果
在类中测试:
@Test
public void findAllById() throws IOException {
SqlSession session = MybatisUtil.openSession();
UserMapper mapper = session.getMapper(UserMapper.class);
System.out.println(mapper.findAllById(15));
User user = new User();
user.setMoney(20000F);
//执行update方法
mapper.updateUser(user);
//提交事务
session.commit();
//第二次查询
System.out.println(mapper.findAllById(15));
}
通过前面的案例我们知道执行的sql相同只会执行一次sql而现在的控制台日志打印执行了两次sql说明执行的update方法清除掉了缓存
控制台日志打印:
//第一次查询
DEBUG [main] - ==> Preparing: select * from account where id = ?
DEBUG [main] - ==> Parameters: 15(Integer)
DEBUG [main] - <== Total: 1
User{name='lk阿b', id=15, money=10000.0}
//执行update方法
DEBUG [main] - ==> Preparing: update account SET money=? where id=?
DEBUG [main] - ==> Parameters: 20000.0(Float), null
DEBUG [main] - <== Updates: 0
DEBUG [main] - Committing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1c93084c]
//第二次查询
DEBUG [main] - ==> Preparing: select * from account where id = ?
DEBUG [main] - ==> Parameters: 15(Integer)
DEBUG [main] - <== Total: 1
User{name='lk阿b', id=15, money=10000.0}
mybatis 的二级缓存的作用域是一个mapper的namespace ,同一个namespace中查询sql可以从缓存中命中。
开启mybatis的二级缓存需要在mapper标签中添加标签以开启二级缓存
在UserMapper.xml配置文件中添加开启二级缓存的标签
<cache>cache>
在MybatisTest测试类中添加testCache()测试方法
@Test
public void testCache() throws IOException {
//第一次查询
SqlSession session = MybatisUtil.openSession();
UserMapper mapper = session.getMapper(UserMapper.class);
System.out.println(mapper.findAllById(15));
//关闭session对话,相当于清除session的一级缓存
session.close();
//第二次
SqlSession session1 = MybatisUtil.openSession();
UserMapper mapper1 = session1.getMapper(UserMapper.class);
System.out.println(mapper1.findAllById(15));
}
运行testCache()方法会报java.io.NotSerializableException错误
原因是:二级缓存 必须要让缓存对象实现序列化接口;由于User类没有实现序列化接口,所以出现反序列异常;
那么我们让User类实现序列化接口Serializable就可以了;
public class User implements Serializable {
//序列化id
private static final long serialVersionUID = -7143822134269505369L;
关闭二级缓存可以在sqlMapConfig.xml中全局配置
<configuration>
<properties resource="jdbc.properties"/>
<settings>
<setting name="cacheEnabled" value="false"/>
settings>