Mybatis的一级和二级缓存的区别

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/fhf2424045058/article/details/84935633

Mybatis的一级缓存:

MyBatis的一级缓存指的是在一个Session域内,session关闭前执行的查询会根据SQL为key被缓存(跟mysql缓存一样,修改任何参数的值都会导致缓存失效),用来保存用户对数据库的操作信息(sql)和数据库返回的数据,如果下一次用户再执行相同的请求,那么直接从内存中读数数据而不是从数据库读取。

Mybatis的一级缓存的作用域是在同一个SqlSession中,而且一级缓存在spring中是没有作用的;‘

单独使用MyBatis而不继承Spring,使用原生的MyBatis的SqlSessionFactory来构造sqlSession查询

public class Test {
    public static void main(String[] args) throws IOException {
        String mybatisconfig= "mybatisconfig.xml";
        InputStream is = Resources.getResourceAsStream(config);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = factory.openSession();
        System.out.println(sqlSession .selectOne("selectUserByID", 1));
        // 同一个session的相同sql查询,将会使用一级缓存 
        System.out.println(sqlSession .selectOne("selectUserByID", 1));
        // 参数改变,需要重新查询
        System.out.println(sqlSession .selectOne("selectUserByID", 2));
        // 清空缓存后需要重新查询
        sqlSession .clearCache();
        System.out.println(sqlSession .selectOne("selectUserByID", 1));
        // sqlSession close以后,仍然使用同一个db connection
        sqlSession .close();
        sqlSession = factory.openSession();
        System.out.println(sqlSession .selectOne("selectUserByID", 1));
    }
}

执行后:当参数不变的时候只进行了一次查询,参数变更以后,则需要重新进行查询,而清空缓存以后,参数相同的查询过的SQL也需要重新查询,而且使用的数据库连接是同一个数据库连接,这里要得益于我们在mybatis config.xml里面的datasource设置

<environments default="development">
        <environment id="development">
            <transactionManager type="JDBC">

            </transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatistest?characterEncoding=utf8" />
                <property name="username" value="root" />
                <property name="password" value="root" />
            </dataSource>
        </environment>
    </environments>

注意:datasource使用的是POOLED,也就是使用了连接池,所以数据库连接可回收利用,当然这个environment属性在集成spring的时候是不需要的,因为我们需要另外配置datasource的bean.

跟Spring集成的时候(使用mybatis-spring),直接在dao里查询两次同样参数的sql

@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中是没有作用的,所以一旦系统 采用了SSM的框架时一级缓存是无法使用的,只能使用二级缓存

其中数据的生命周期有两个影响因素

1.commit操作

如果对sqlsession执行commit操作,也就意味着用户执行了update、delete等操作,那么数据库中的数据势必会发生变化,如果用户请求数据仍然使用之前内存中的数据,那么将读到脏数据。所以在执行sqlsession操作后,会清除保存数据的HashMap,用户在发起查询请求时就会重新读取数据并放入一级缓存中了。所以在commit之后mybatis对数据重新进行了查询。

2.关闭session

关闭sqlsession时,一般在mybatis集成spring时,会把SqlSessionFactory设置为单例注入到IOC容器中,不把sqlsession也设置为单例的原因是sqlsession是线程不安全的,所以不能为单例。那也就意味着其实是有关闭sqlsession的过程的。其实,对于每一个service中的sqlsession是不同的,这是通过mybatis-spring中的org.mybatis.spring.mapper.MapperScannerConfigurer创建sqlsession自动注入到service中的。
在第一次查询完后关闭sqlsession,然后创建新的sqlsession和mapper来重新执行一次查询操作说明关闭了sqlsession后的确把之前的缓存数据清空了,之后再执行同样的查询操作也会再访问一遍数据库。为了解决这个问题,需要使用二级缓存
而一级缓存的设计是每个sqlsession单独使用一个缓存空间,不同的sqlsession是不能互相访问数据的。当然,在sqlsession关闭后,其中数据自然被清空。

Mybatis的二级缓存:

二级缓存就是global caching,它超出session范围之外,可以被所有sqlSession共享,它的实现机制和mysql的缓存一样,开启它只需要在mybatis的配置文件开启settings里的.
需要注意的是global caching的作用域是针对Mapper的Namespace而言的,也就是说只在有在这个Namespace内的查询才能共享这个cache.例如上面的 dao.userdao namespace 。但并不是意味着同一个namespace创建的mapper可以互相读取缓存内容,

这里的原则是,如果开启了二级缓存,那么在关闭sqlsession后,会把该sqlsession一级缓存中的数据添加到namespace的二级缓存中。

开启二级缓存第一步:

打开二级缓存总开关:
打开总开关,只需要在mybatis总配置文件中加入一行设置

<setting name="cacheEnabled" value="true"/>

开启二级缓存第二步:

打开需要使用二级缓存的mapper的开关:
在需要开启二级缓存的mapper.xml中加入caceh标签

在UserMapper.xml中配置

 <!--开启mybatis的二级缓存  -->
     <cache eviction="FIFO"  flushInterval="60000" size="512" readOnly="true" />

开启二级缓存第三步:

让需要使用二级缓存的POJO类实现Serializable接口,如

public class User implements Serializable {

相关文章1
相关文章2

猜你喜欢

转载自blog.csdn.net/fhf2424045058/article/details/84935633