• mybatis缓存


    正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持。
    1. 一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空。
    2. 二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。
    3. 对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。 

    一级缓存


    MyBatis的一级缓存指的是在一个Session域内,session未关闭的时候执行的查询会根据SQL为key被缓存(跟mysql缓存一样,修改任何参数的值都会导致缓存失效)

    1. 默认开启
    2. 必须同一个session,如果session对象已经close()过了就不能用了
    3. 查询条件必须一致
    4. 执行过session.cleanCache();会清理缓存
    5. 执行过增删改操作(这些操作都会清理缓存)

    案例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));
        }
    }

    输入日志

    DEBUG - Openning JDBC Connection
    DEBUG - Created connection 10044878.
    DEBUG - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@9945ce]
    DEBUG - ==> Preparing: SELECT * FROM user WHERE id = ?
    DEBUG - ==> Parameters: 1(Integer)
    1|test1|19|beijing
    1|test1|19|beijing
    DEBUG - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@9945ce]
    DEBUG - ==> Preparing: SELECT * FROM user WHERE id = ?
    DEBUG - ==> Parameters: 2(Integer)
    2|test2|18|guangzhou
    DEBUG - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@9945ce]
    DEBUG - ==> Preparing: SELECT * FROM user WHERE id = ?
    DEBUG - ==> Parameters: 1(Integer)
    1|test1|19|beijing
    DEBUG - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@9945ce]
    DEBUG - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@9945ce]
    DEBUG - Returned connection 10044878 to pool.
    DEBUG - Openning JDBC Connection
    DEBUG - Checked out connection 10044878 from pool.
    DEBUG - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@9945ce]
    DEBUG - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@9945ce]
    DEBUG - ==> Preparing: SELECT * FROM user WHERE id = ?
    DEBUG - ==> Parameters: 1(Integer)

    看以看出来,当参数不变的时候只进行了一次查询,参数变更以后,则需要重新进行查询,而清空缓存以后,参数相同的查询过的SQL也需要重新查询。

    案例2.跟Spring集成的时候(使用mybatis-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);
        }
    }
    DEBUG - Creating a new SqlSession
    DEBUG - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1e389b8] was not registered for synchronization because synchronization is not active
    DEBUG - Fetching JDBC Connection from DataSource
    DEBUG - JDBC Connection [jdbc:mysql://127.0.0.1:3306/mybatistest?characterEncoding=utf8, UserName=root@localhost, MySQL-AB JDBC Driver] will not be managed by Spring
    DEBUG - ooo Using Connection [jdbc:mysql://127.0.0.1:3306/mybatistest?characterEncoding=utf8, UserName=root@localhost, MySQL-AB JDBC Driver]
    DEBUG - ==> Preparing: SELECT * FROM user WHERE id = ?
    DEBUG - ==> Parameters: 1(Integer)
    DEBUG - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1e389b8]
    DEBUG - Returning JDBC Connection to DataSource
    DEBUG - Creating a new SqlSession
    DEBUG - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@169da74] was not registered for synchronization because synchronization is not active
    DEBUG - Fetching JDBC Connection from DataSource
    DEBUG - JDBC Connection [jdbc:mysql://127.0.0.1:3306/mybatistest?characterEncoding=utf8, UserName=root@localhost, MySQL-AB JDBC Driver] will not be managed by Spring
    DEBUG - ooo Using Connection [jdbc:mysql://127.0.0.1:3306/mybatistest?characterEncoding=utf8, UserName=root@localhost, MySQL-AB JDBC Driver]
    DEBUG - ==> Preparing: SELECT * FROM user WHERE id = ?
    DEBUG - ==> Parameters: 1(Integer)
    DEBUG - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@169da74]
    DEBUG - Returning JDBC Connection to DataSource

    这里执行了2次sql查询,看似我们使用了同一个sqlSession,但是实际上因为我们的dao继承了SqlSessionDaoSupport,而SqlSessionDaoSupport内部sqlSession的实现是使用用动态代理实现的,这个动态代理sqlSessionProxy使用一个模板方法封装了select()等操作,每一次select()查询都会自动先执行openSession(),执行完close()以后调用close()方法,相当于生成了一个新的session实例,所以我们无需手动的去关闭这个session()(关于这一点见下面mybatis的官方文档),当然也无法使用mybatis的一级缓存,也就是说mybatis的一级缓存在spring中是没有作用的.

    二级缓存


    二级缓存就是global caching,它超出session范围之外,可以被所有sqlSession共享,它的实现机制和mysql的缓存一样,开启它只需要在mybatis的配置文件开启settings里的。

    1. 默认不开启

    2. 全局开关配置

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD  Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <settings>
            <!--  默认是true,如果它配成false,其余各个Mapper XML文件配成支持cache也没用 -->
            <setting name="cacheEnabled" value="true"/>
        </settings>
    </configuration>

     3. 各个Mapper XML文件,默认是不采用cache。在配置文件加一行就可以支持cache

    <mapper namespace="com.test">
        <!-- 
            eviction="FIFO"  回收策略为先进先出,(LRU,最近最少使用的算法)
            flushInterval="300000"   自动刷新时间5分钟
            size="16"  最多缓存16个引用对象
            readOnly="true"  只读
         -->
        <cache eviction="FIFO" flushInterval="300000" size="16" readOnly="true" />
        <select id=""></select>
    </mapper>

     4. Mapper XML文件配置支持cache后,该文件中所有的Mapper statement就支持了。此时要个别sql不需要缓存的话,需要进行配置

    <!-- useCache="false" 配置后则没有缓存-->
    <select id="check" parameterType="string" resultType="int" useCache="false">
    </select>

    案例

    @RequestMapping("/getUser")
        public String getUser(Model model) {
            User user = userDao.selectUserById(1);
            model.addAttribute(user);
            return "index";
        }  
    }

    当我们访问两次 /getUser 这个url,查看日志输出

    DEBUG - Creating a new SqlSession
    DEBUG - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@659812] was not registered for synchronization because synchronization is not active
    DEBUG - Cache Hit Ratio [dao.userdao]: 0.0
    DEBUG - Fetching JDBC Connection from DataSource
    DEBUG - JDBC Connection [jdbc:mysql://127.0.0.1:3306/mybatistest?characterEncoding=utf8, UserName=root@localhost, MySQL-AB JDBC Driver] will not be managed by Spring
    DEBUG - ooo Using Connection [jdbc:mysql://127.0.0.1:3306/mybatistest?characterEncoding=utf8, UserName=root@localhost, MySQL-AB JDBC Driver]
    DEBUG - ==> Preparing: SELECT * FROM user WHERE id = ?
    DEBUG - ==> Parameters: 1(Integer)
    DEBUG - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@659812]
    DEBUG - Returning JDBC Connection to DataSource
    DEBUG - Invoking afterPropertiesSet() on bean with name 'index'
    DEBUG - Rendering view [org.springframework.web.servlet.view.JstlView: name 'index'; URL [/index.jsp]] in DispatcherServlet with name 'dispatcher'
    DEBUG - Added model object 'org.springframework.validation.BindingResult.user' of type [org.springframework.validation.BeanPropertyBindingResult] to request in view with name 'index'
    DEBUG - Added model object 'user' of type [bean.User] to request in view with name 'index'
    DEBUG - Forwarding to resource [/index.jsp] in InternalResourceView 'index'
    DEBUG - Successfully completed request
    DEBUG - Returning cached instance of singleton bean 'sqlSessionFactory'
    DEBUG - DispatcherServlet with name 'dispatcher' processing GET request for [/user/getUser]
    DEBUG - Looking up handler method for path /user/getUser
    DEBUG - Returning handler method [public java.lang.String controller.UserController.getUser(org.springframework.ui.Model)]
    DEBUG - Returning cached instance of singleton bean 'userController'
    DEBUG - Last-Modified value for [/user/getUser] is: -1
    DEBUG - Creating a new SqlSession
    DEBUG - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@539a92] was not registered for synchronization because synchronization is not active
    DEBUG - Cache Hit Ratio [dao.userdao]: 0.5
    DEBUG - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@539a92]
    DEBUG - Rendering view [org.springframework.web.servlet.view.JstlView: name 'index'; URL [/index.jsp]] in DispatcherServlet with name 'dispatcher'
    DEBUG - Added model object 'org.springframework.validation.BindingResult.user' of type [org.springframework.validation.BeanPropertyBindingResult] to request in view with name 'index'
    DEBUG - Added model object 'user' of type [bean.User] to request in view with name 'index'
    DEBUG - Forwarding to resource [/index.jsp] in InternalResourceView 'index'
    DEBUG - Successfully completed request

    可以看出第二次访问同一个url的时候相同的查询 hit cache了,这就是global cache的作用

    总结


    一级,二级缓存意义都不是很大

    面对一定规模的数据量,内置的cache方式就派不上用场了

    数据缓存在内存中,是增加的应用的压力

    一般缓存采用Memcached、redis等

     

     


  • 相关阅读:
    C++预备知识
    C++求最小公倍数
    c++编写函数,递归删除字符串中的子串,求删除次数
    ERROR 1452 : Cannot add or update a child row: a foreign key constraint fails
    django快速搭建blog
    北邮 北理 人大经验
    C、C++、Java语言中异常处理机制浅析
    学习git部署
    各种符号的使用情况说明以及区别
    【转】通过fio工具,测试SATA,SAS,SSD 读写性能
  • 原文地址:https://www.cnblogs.com/qin-derella/p/6128792.html
Copyright © 2020-2023  润新知