首页 > 编程知识 正文

mybatis一级缓存 二级缓存,mybatis一级缓存与二级缓存

时间:2023-05-03 07:31:10 阅读:281715 作者:2218

一:本文将涉及到的如下几方面的知识点 mybatis基本增删改查Java序列化和反序列化JDBC和sqlsession基本理论spring事务管理二:mybatis查询缓存基本介绍 缓存:将相同查询条件的sql语句执行一遍后所得到的结果存在内存或者某种缓存介质当中,当下次遇到一模一样的查询sql时候不在执行sql与数据库交互,而是直接从缓存中获取结果,减少服务器的压力;mybatis的查询缓存又分为一级缓存和二级缓存,一级缓存的作用范围为同一个sqlsession,而二级缓存的作用范围为同一个namespace和mapper;这是接下来的篇幅重点介绍的;三:mybatis缓存详细介绍

     1:一级缓存

       一级缓存是mybatis默认就帮我们开启的,我们不需要多做配置,但是我们得知道其中原理,否则我们也不知道怎么使用,也不知道我们到底有没有一级缓存。

       上面第二部分说过一级缓存的作用域是同一个sqlsession,sqlsession的作用就是建立和数据库的会话,我们对数据库表的增删改查都是通过sqlsession去执行指定的sql完成的,而sqlsession和数据库的连接并不是永久连接的,也一定要杜绝这种永久连接;所以就有了sqlsession的创建和关闭,sqlsession默认执行完一段的sql片段后就会close掉sqlsession,即销毁sqlsession;而下一次对数据库的操作的又会重新建立会话关系,即建立新的sqlsession,所以这就和前一次的执行sql的sqlsession属于不同的SQL session了,也就这两个sqlsession就不存在一级缓存关系了;代码分析如下:

public CourseDto getCourse(String courseId) { log.info("测试mybatis默认开启的一级缓存"); log.info("第一次查询"); Course course = courseDao.getSqlSession().selectOne("listCourseByAutoMapping", courseId); log.info("第二次查询"); Course course1 = courseDao.getSqlSession().selectOne("listCourseByAutoMapping", courseId); CourseDto courseDto = mapper.map(course, CourseDto.class); return courseDto;}

       我们说过一级缓存不需要任何配置,mybatis默认开启的,所以这里直接写service,没有其他额外配置;代码内容是对同一个sql代码片段连续调用两次,控制台日志打印如下:

                                                                           图1-1:未正确使用一级缓存

 

                                                                               图1-2:未正确使用一级缓存

       由两张图可以看出上面的代码执行了两次与数据库的会话,因为每次都新建了sqlsession,不在一级缓存的作用域内,而且每次执行的sql也都帮我们打印出来了,所以说程序并没有用到我们的一级缓存;那么如何将一级缓存利用起来呢?这就需要用到我们的spring事务管理;现在的代码如下:

@Transactional(propagation = Propagation.REQUIRES_NEW)//开启spring的申明事务@Overridepublic CourseDto getCourse(String courseId) { log.info("测试mybatis默认开启的一级缓存"); log.info("第一次查询"); Course course = courseDao.getSqlSession().selectOne("listCourseByAutoMapping", courseId); log.info("第二次查询"); Course course1 = courseDao.getSqlSession().selectOne("listCourseByAutoMapping", courseId); log.info("第二次执行查询完毕"); CourseDto courseDto = mapper.map(course, CourseDto.class); return courseDto;}

    执行结果如下图:

                                                                            图2:正确使用一级缓存结果

      可以看到开启spring事务之后,同样的业务代码,在这里sql片段只打印一遍,而且在执行第二次查询的时候没有在重新创建sqlsession,所以是同一个sqlsession,说明第二次查询的数据是从缓存中获取的,所以证明这里是一级缓存起了作用;关于spring事务不知如何使用的,可以参看我的另一篇文章(https://blog.csdn.net/llf_1241352445/article/details/79831031);而关于spring事务管理的service只会一个创建sqlsession,这是因为事务管理下的sql执行方式是BATCH,只会与数据库交互一次,一次执行完所有的sql,所以只会创建一个sqlsession;

       2:二级缓存

       二级缓存是基于namespace和mapper的作用域起作用的,不是依赖于SQL session,所以这里,我们需要对mybatis的配置修改,开启二级缓存设施,而且需要在我们的namespace下开启缓存,具体如下

     在mybatis-config.xml文件中的<settings>标签配置开启缓存,代码如下:

      <!--开启缓存,此时配置的是mybatis的二级缓存-->

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

    单单配置这个还是不够的,还需要在我们的mapper的xml文件下开启缓存,即加入该标签:

<!--namespace必须加上此标签才会开启二级缓存--> <cache />

然后可以开始试着运行我们的代码如下:   

@Overridepublic CourseDto getCourse(String courseId) { log.info("测试mybatis默认开启的二级缓存"); Course course = courseDao.getSqlSession().selectOne("listCourseByAutoMapping", courseId); log.info("第一次查询结果:{}",course.toString()); Course course1 = courseDao.getSqlSession().selectOne("listCourseByAutoMapping", courseId); log.info("第二次执行查询完毕:{}",course1.toString()); CourseDto courseDto = mapper.map(course, CourseDto.class); return courseDto;}

执行结果如下:

                                                                             图三:序列化异常

 

        执行结果报序列化异常,那是因为我们映射的pojo对象未实现序列化接口,说明我们从缓存数据中读取数据需要进行反序列化,这是因 为mybatis的二级缓存的缓存介质有多种多样,而并不一定是在内存中,所以需要我们对pojo对象进行序列化,只要实现序列化接口即可,而对于序列化和反序列化不清楚的读者可以参看我的另外一篇文章(https://blog.csdn.net/llf_1241352445/article/details/81135882),pojo序列化的就不截图了,直接看我们的正确执行结果,如下图:

                                                                              图四:二级缓存效果

 

可以看到,第一次查询有打印sql,而第二次查询没有打印sql,而且还有正确的返回数据,而上面的代码也没有开启spring事务

,说明不存在mybatis的一级缓存,唯一能起作用的就是二级缓存了;

       3:拓展延申

       对于同一个service被同一个请求分多次调用,则所有的这些调用之间的一级缓存和二级缓存个事什么情况呢?

      一级缓存是基于sqlsession的,当一次请求结束之后,意味着session执行结束,所以sqlsession也就关闭了,所以缓存也就清空了,因此,对于多次的请求,肯定不存在一级缓存;

     二级缓存是对于namespace和mapper的,只要相同的查询sql,都会优先从缓存区域查找,所以对于多次请求,对于二级缓存是没有影响的。这个大家可以去自己验证下,只要连续发两次的请求验证sql的打印次数就可以得到结论;

 

 

 

 

 

 

 

 

 

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。