天天看点

Mybatis强制查询问题

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。

每天努力一点,每天都在进步。