• 【MyBatis框架】查询缓存-二级缓存原理


    二级缓存原理

    1.原理

    首先看图


    首先开启mybatis的二级缓存。

    sqlSession1去查询用户id为1的用户信息,查询到用户信息会将查询数据存储到二级缓存中。

    如果SqlSession3去执行相同 mapper下sql,执行commit提交,清空该 mapper下的二级缓存区域的数据。

    sqlSession2去查询用户id为1的用户信息,去缓存中找是否存在数据,如果存在直接从缓存中取出数据。

    二级缓存与一级缓存区别,二级缓存的范围更大,多个sqlSession可以共享一个UserMapper的二级缓存区域。
    UserMapper有一个二级缓存区域(按namespace分) ,其它mapper也有自己的二级缓存区域(按namespace分)。
    每一个namespace的mapper都有一个二缓存区域,两个mapper的namespace如果相同,这两个mapper执行sql查询到数据将存在相同 的二级缓存区域中。

    2.开启二级缓存

    mybaits的二级缓存是mapper范围级别,除了在SqlMapConfig.xml设置二级缓存的总开关,还要在具体的mapper.xml中开启二级缓存。

    在核心配置文件SqlMapConfig.xml中加入

    [html] view plain copy
     
    1. <setting name="cacheEnabled" value="true"/>  

    描述允许值 默认值
    cacheEnabled 对在此配置文件下的所有cache 进行全局性开/关设置。true false true

    在UserMapper.xml中开启二缓存,UserMapper.xml下的sql执行完成会存储到它的缓存区域(HashMap)。

    <!-- 开启本Mapper的namespace下的二级缓存 -->
        <cache/>

    3.调用pojo类实现序列化接口

    [java] view plain copy
     
    1. public class User implements Serializable{  
    2.     private int id;  
    3.     private String username;// 用户姓名  
    4.     private String sex;// 性别  
    5.     private Date birthday;// 生日  
    6.     private String address;// 地址  
    7.     //...  
    8. }  

    为了将缓存数据取出执行反序列化操作,因为二级缓存数据存储介质多种多样(内存、硬盘、服务器),不一样在内存。

    4.测试方法
    先测试二级缓存的存在

    [java] view plain copy
     
    1. //测试二级缓存  
    2. @Test  
    3. public void testCache2() throws Exception{  
    4.     SqlSession sqlSession1 = sqlSessionFactory.openSession();  
    5.     SqlSession sqlSession2 = sqlSessionFactory.openSession();  
    6.     SqlSession sqlSession3 = sqlSessionFactory.openSession();  
    7.       
    8.     UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);//创建代理对象  
    9.     //下边查询使用一个SqlSession  
    10.     //第一次发起请求,查询id为1的用户  
    11.     User user1 = userMapper1.findUserById(1);  
    12.     System.out.println(user1.getUsername());  
    13.     //不关闭SqlSession无法写进二级缓存区域中  
    14.     sqlSession1.close();  
    15.       
    16.     UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);//创建代理对象  
    17.     //第二次发起请求,查询id为1的用户  
    18.     User user2 = userMapper2.findUserById(1);  
    19.     System.out.println(user2.getUsername());  
    20.     sqlSession2.close();  
    21.       
    22.       
    23. }  

    测试结果和输出日志:

    [plain] view plain copy
     
    1. DEBUG [main] - Cache Hit Ratio [cn.edu.hpu.mybatis.mapper.UserMapper]: 0.0  
    2. DEBUG [main] - Opening JDBC Connection  
    3. DEBUG [main] - Created connection 26255574.  
    4. DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.Connection@190a0d6]  
    5. DEBUG [main] - ==>  Preparing: SELECT * FROM USER WHERE id=?   
    6. DEBUG [main] - ==> Parameters: 1(Integer)  
    7. DEBUG [main] - <==      Total: 1  
    8. 张三  
    9. DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.Connection@190a0d6]  
    10. DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.Connection@190a0d6]  
    11. DEBUG [main] - Returned connection 26255574 to pool.  
    12. DEBUG [main] - Cache Hit Ratio [cn.edu.hpu.mybatis.mapper.UserMapper]: 0.5  
    13. 张三  


    我们可以发现,日志输出中有一句我们之前没有见过,是:
    Cache Hit Ratio [cn.edu.hpu.mybatis.mapper.UserMapper]: 0.0
    这句的意思是缓存命中率为0.0,说明第一次是在缓存中找,可是没找到
    DEBUG [main] - Cache Hit Ratio [cn.edu.hpu.mybatis.mapper.UserMapper]: 0.5
    这句的意思是缓存命中率为0.5,说明第一次是在缓存中找,可是没找到,第二次找到了。

    这个测试证明了二级缓存的存在

    下面证明第三方sqlSession执行增删改会清空缓存的事实:

    [java] view plain copy
     
    1. //测试二级缓存  
    2. @Test  
    3. public void testCache2() throws Exception{  
    4.     SqlSession sqlSession1 = sqlSessionFactory.openSession();  
    5.     SqlSession sqlSession2 = sqlSessionFactory.openSession();  
    6.     SqlSession sqlSession3 = sqlSessionFactory.openSession();  
    7.       
    8.     UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);//创建代理对象  
    9.     //下边查询使用一个SqlSession  
    10.     //第一次发起请求,查询id为1的用户  
    11.     User user1 = userMapper1.findUserById(1);  
    12.     System.out.println(user1.getUsername());  
    13.     //不关闭SqlSession无法写进二级缓存区域中  
    14.     sqlSession1.close();  
    15.       
    16.     UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class);//创建代理对象  
    17.     User user=userMapper3.findUserById(1);  
    18.     user.setUsername("张明明");  
    19.     userMapper3.updateUser(user);  
    20.     //执行提交,清空UserMapper二级缓存  
    21.     sqlSession3.commit();  
    22.     sqlSession3.close();  
    23.       
    24.     UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);//创建代理对象  
    25.     //第二次发起请求,查询id为1的用户  
    26.     User user2 = userMapper2.findUserById(1);  
    27.     System.out.println(user2.getUsername());  
    28.     sqlSession2.close();  
    29.       
    30.       
    31. }  


    输出结果和日志信息:

    [plain] view plain copy
     
    1. DEBUG [main] - Cache Hit Ratio [cn.edu.hpu.mybatis.mapper.UserMapper]: 0.0  
    2. DEBUG [main] - Opening JDBC Connection  
    3. DEBUG [main] - Created connection 189219.  
    4. DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.Connection@2e323]  
    5. DEBUG [main] - ==>  Preparing: SELECT * FROM USER WHERE id=?   
    6. DEBUG [main] - ==> Parameters: 1(Integer)  
    7. DEBUG [main] - <==      Total: 1  
    8. 张三  
    9. DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.Connection@2e323]  
    10. DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.Connection@2e323]  
    11. DEBUG [main] - Returned connection 189219 to pool.  
    12. DEBUG [main] - Cache Hit Ratio [cn.edu.hpu.mybatis.mapper.UserMapper]: 0.5  
    13. DEBUG [main] - Opening JDBC Connection  
    14. DEBUG [main] - Checked out connection 189219 from pool.  
    15. DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.Connection@2e323]  
    16. DEBUG [main] - ==>  Preparing: update user set username=?,birthday=?,sex=?,address=? where id=?   
    17. DEBUG [main] - ==> Parameters: 张明明(String), 2015-06-07(Date), 男(String), 河南焦作(String), 1(Integer)  
    18. DEBUG [main] - <==    Updates: 1  
    19. DEBUG [main] - Committing JDBC Connection [com.mysql.jdbc.Connection@2e323]  
    20. DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.Connection@2e323]  
    21. DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.Connection@2e323]  
    22. DEBUG [main] - Returned connection 189219 to pool.  
    23. DEBUG [main] - Cache Hit Ratio [cn.edu.hpu.mybatis.mapper.UserMapper]: 0.3333333333333333  
    24. DEBUG [main] - Opening JDBC Connection  
    25. DEBUG [main] - Checked out connection 189219 from pool.  
    26. DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.Connection@2e323]  
    27. DEBUG [main] - ==>  Preparing: SELECT * FROM USER WHERE id=?   
    28. DEBUG [main] - ==> Parameters: 1(Integer)  
    29. DEBUG [main] - <==      Total: 1  
    30. 张明明  
    31. DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.Connection@2e323]  
    32. DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.Connection@2e323]  
    33. DEBUG [main] - Returned connection 189219 to pool.  

    发现第二次再去查1号用户的时候,又再一次查询了数据库,查到了最新的数据"张明明"。

    二级缓存远远没有那么简单,他还有一些配置的参数。

    5.useCache配置

    在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认情况是true,即该sql使用二级缓存。

    [html] view plain copy
     
    1. <select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">  


    总结:针对每次查询都需要最新的数据sql,要设置成useCache=false,禁用二级缓存。

    6.刷新缓存(就是清空缓存)
    在mapper的同一个namespace中,如果有其它insert、update、delete操作数据后需要刷新缓存,如果不执行刷新缓存会出现脏读。

     设置statement配置中的flushCache="true" 属性,默认情况下为true即刷新缓存,如果改成false则不会刷新。使用缓存时如果手动修改数据库表中的查询数据会出现脏读。
    如下:

    [html] view plain copy
     
    1. <insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" flushCache="true">  

    总结:一般下执行完commit操作都需要刷新缓存,flushCache=true表示刷新缓存,这样可以避免数据库脏读。

    出处:http://blog.csdn.net/acmman/article/details/46793289

  • 相关阅读:
    两种类型插件系统
    ArcEngine序列化IFeatureRenderer对象
    [WorldWind学习]14.ConfigurationLoader类
    [WorldWind学习]15.模型加载
    AE应用程序开发的思考
    [C++摘抄]void*
    XML文件读写学习
    EA正向工程
    Word2010利用公式编辑器实现公式“显示”“居中”公式编号右对齐
    [Qt]Hello Qt !
  • 原文地址:https://www.cnblogs.com/zhaozhenyi/p/6443145.html
Copyright © 2020-2023  润新知