Mybatis强制查询缓存问题
1、对于经常用Mybatis框架的开发人员来说,都知道Mybatis进行数据库查询时的一个特性:
Mybatis连续执行两次相同的查询,Mybatis是不会去数据库中查询,而是直接从sqlsession中取,返回的对象也是同一个对象。简单来说就是不会再发出sql查询而是使用缓存的数据。这对于经常使用查询的系统无疑是一个非常好的特性,对于大量数据查询来说就是节约大量资源,降低开发成本。
但是我们有时候有特殊需要,那些数据一定要进行查询再能得到的,否则就会得到数据不一致的情况,这时候我们如何处理?
2、解决方案:
若是想要每次查询都返回新的对象,只需在xml文件select标签里添加属性 flushCache="true"。
3、MyBatis的缓存机制(分为一级缓存和二级缓存)
3.1一级缓存:
MyBatis的一级缓存指的是在一个Session域内,session为关闭的时候执行的查询会根据SQL为key,数据为value被缓存。
1)单独使用MyBatis而不继承Spring,使用原生的MyBatis的SqlSessionFactory来构造sqlSession查询,是可以使用以及缓存的,示例代码如下
public class Test {
public static void main(String[] args) throws IOException {
String config = "mybatis-config.xml";
InputStream is = Resources.getResourceAsStream(config);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = factory.openSession();
System.out.println(session.selectOne("selectUserByID", 1));
// 同一个session的相同sql查询,将会使用一级缓存
System.out.println(session.selectOne("selectUserByID", 1));
// 参数改变,需要重新查询
System.out.println(session.selectOne("selectUserByID", 2));
// 清空缓存后需要重新查询
session.clearCache();
System.out.println(session.selectOne("selectUserByID", 1));
// session close以后,仍然使用同一个db connection
session.close();
session = factory.openSession();
System.out.println(session.selectOne("selectUserByID", 1));
}
}
当参数不变的时候只进行了一次查询,参数变更以后,则需要重新进行查询,而清空缓存以后,参数相同的查询过的SQL也需要重新查询。
2) 和Spring集成的时候
@Repository
public class UserDao extends SqlSessionDaoSupport {
public User selectUserById(int id) {
SqlSession session = getSqlSession();
session.selectOne("dao.userdao.selectUserByID", id);
// 由于session的实现是SqlSessionTemplate的动态代理实现
// 它已经在代理类内执行了session.close(),所以无需手动关闭session
return session.selectOne("dao.userdao.selectUserByID", id);
}
}
这里执行了2次sql查询,看似我们使用了同一个sqlSession,但是实际上因为我们的dao继承了SqlSessionDaoSupport,而SqlSessionDaoSupport内部sqlSession的实现是使用用动态代理实现的,这个动态代理sqlSessionProxy使用一个模板方法封装了select()等操作,每一次select()查询都会自动先执行openSession(),执行完close()以后调用close()方法,相当于生成了一个新的session实例,所以
我们无需手动的去关闭这个session(),当然也无法使用mybatis的一级缓存,也就是说mybatis的一级缓存在spring中是没有作用的。
3.2二级缓存
二级缓存就是global caching,它超出session范围之外,可以被所有sqlSession共享,它的实现机制和mysql的缓存一样,开启它只需要在mybatis的配置文件开启settings里的。
<setting name="cacheEnabled" value="true"/>以及在相应的Mapper文件里开启。
<mapper namespace="dao.userdao"> ... select statement ... <!-- Cache 配置 --> <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true" /> </mapper>需要注意的是global caching的作用域是针对Mapper的Namespace而言的,也就是说只在有在这个Namespace内的查询才能共享这个cache。
每天努力一点,每天都在进步。