MyBatis Review——查询缓存

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
云数据库 RDS PostgreSQL,高可用系列 2核4GB
简介: 一,查询缓存简介        mybatis提供查询缓存,用于减轻数据压力,提高数据库性能。        mybaits提供一级缓存,和二级缓存。          一级缓存是SqlSession级别的缓存。


一,查询缓存简介


        mybatis提供查询缓存,用于减轻数据压力,提高数据库性能。


        mybaits提供一级缓存,和二级缓存。




          一级缓存是SqlSession级别的缓存。在操作数据库时候,需要构造sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域是互相不影响的。


         二级缓存是mapper级别的缓存,多个sqlSession去操作同一个mapper的sql语句,多个sqlSession可以共用二级缓存,二级缓存是跨sqlSession的。



二,一级缓存


 1,一级缓存的原理




步骤:


       1,第一次发起查询用户id为1的信息,先去缓存中查找是否存在id为1的信息,如果没有,发出sq语句,从数据库查询用户信息。得到用户信息,将用户信息存储到一级缓存中。


       2,如果sqlSession去执行commit操作(执行插入,更新,删除),清空sqlSession中的一级缓存,这样做的目的是为了让缓存中存储最新的信息,避免脏读。


      3,当第二次查询用户id为1的信息的时候,先去缓存中查找是否有id为1的用户信息,缓存中有,则直接从缓存中取数据,不再发出sql查询语句。



2,一级缓存的测试



   1,测试没有commit操作的时候,从缓存取得数据:


@Test
	public void testCache1() throws Exception {
		SqlSession sqlSession=sqlSessionFactory.openSession();
		//创建代理对象
		UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
		
		//第一次发起请求,查询id为1的用户
		User user1=userMapper.findUserById(1);
		System.out.println(user1.toString());
		
		//第二次发起请求,查询id为1的用户
		User user2=userMapper.findUserById(1);
		System.out.println(user2.toString());
		
		sqlSession.close();
	}

   debug信息:


DEBUG [main] - Cache Hit Ratio [cn.itcast.mybatis.mapper.UserMapper]: 0.0
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 819131219.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@30d2f353]
DEBUG [main] - ==>  Preparing: SELECT * FROM user where id=? 
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
cn.itcast.mybatis.po.User@68d9915
DEBUG [main] - Cache Hit Ratio [cn.itcast.mybatis.mapper.UserMapper]: 0.0
cn.itcast.mybatis.po.User@68d9915
DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@30d2f353]
DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@30d2f353]
DEBUG [main] - Returned connection 819131219 to pool.

   第一次查询id=1,发出一条sql语句,之后在第二次查询的时候,没有任何sql语句。



 2,测试存在commit操作的时候,缓存变化


@Test
	public void testCache1() throws Exception {
		SqlSession sqlSession=sqlSessionFactory.openSession();
		//创建代理对象
		UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
		
		//第一次发起请求,查询id为1的用户
		User user1=userMapper.findUserById(1);
		System.out.println(user1.toString());
		
		/*如果sqlSession去执行commit操作,(插入,删除,更新),清空sqlSession的
		  一级缓存,这样做的目的是为了让缓存中存储的是最新信息,避免脏读
		  */
		user1.setAddress("故宫");
		
		userMapper.updateUser(user1);
		sqlSession.commit();//清空缓存
		
		//第二次发起请求,查询id为1的用户
		User user2=userMapper.findUserById(1);
		System.out.println(user2.toString());
		
		sqlSession.close();
	}
	


deubg信息:



DEBUG [main] - Checking to see if class cn.itcast.mybatis.mapper.UserMapperTest matches criteria [is assignable to Object]
DEBUG [main] - Cache Hit Ratio [cn.itcast.mybatis.mapper.UserMapper]: 0.0
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 538784332.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@201d324c]
DEBUG [main] - ==>  Preparing: SELECT * FROM user where id=? 
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
cn.itcast.mybatis.po.User@3eb6e46
DEBUG [main] - ==>  Preparing: update user set username=?,birthday=?,sex=?,address=? where id=? 
DEBUG [main] - ==> Parameters: lhccccccccc(String), 2016-05-21 00:00:00.0(Timestamp), 1(String), 故宫(String), 1(Integer)
DEBUG [main] - <==    Updates: 1
DEBUG [main] - Committing JDBC Connection [com.mysql.jdbc.JDBC4Connection@201d324c]
DEBUG [main] - Cache Hit Ratio [cn.itcast.mybatis.mapper.UserMapper]: 0.0
DEBUG [main] - ==>  Preparing: SELECT * FROM user where id=? 
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
cn.itcast.mybatis.po.User@4e30cbae
DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@201d324c]
DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@201d324c]
DEBUG [main] - Returned connection 538784332 to pool.

 

  在update语句执行之后,当再次查询id=1的时候,又发出sql语句。



3,一级缓存的应用


   正式开发,是将mybatisspring进行整合开发,事务控制在service中。

 

   一个service方法中包括 很多mapper方法调用。

 

service{

//开始执行时,开启事务,创建SqlSession对象

//第一次调用mapper的方法findUserById(1)

//第二次调用mapper的方法findUserById(1),从一级缓存中取数据

//方法结束,sqlSession关闭

}

 

      如果是执行两次service调用查询相同 的用户信息,不走一级缓存,因为session方法结束,sqlSession就关闭,一级缓存就清空。




三,二级缓存


    1,原理


                       


   使用二级缓存步骤:


      首先开启mybatis的二级缓存:


              


     sqlSession1去查询id=1的用户信息,发出sql语句,查询到的结果会被放入二级缓存。

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

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


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


  2,开启二级缓存

     

    开启了settings中的全局二级缓存配置后,如果某个mapper要开启二级缓存,需要在mapper的xml中加入:


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


     pojo类实现序列化接口:


     


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



  3,测试代码

             

@Test
	public void testCache2() throws Exception {
		SqlSession sqlSession1=sqlSessionFactory.openSession();
		SqlSession sqlSession2=sqlSessionFactory.openSession();
		SqlSession sqlSession3=sqlSessionFactory.openSession();
		
		//创建代理对象
		UserMapper userMapper1=sqlSession1.getMapper(UserMapper.class);
		UserMapper userMapper2=sqlSession2.getMapper(UserMapper.class);
		UserMapper userMapper3=sqlSession2.getMapper(UserMapper.class);
		//第一次发起请求,查询id为1的用户
		User user1=userMapper1.findUserById(1);
		System.out.println(user1.toString());

		//这里执行关闭操作,将sqlSession中数据写入二级缓存中去
		sqlSession1.close();
		
		
		//第二次发起请求,查询id为1的用户
		User user2=userMapper2.findUserById(1);
		System.out.println(user2.toString());
		
		sqlSession2.close();
		
	}

输出信息:


DEBUG [main] - Cache Hit Ratio [cn.itcast.mybatis.mapper.UserMapper]: 0.0
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 1602614455.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@5f85f4b7]
DEBUG [main] - ==>  Preparing: SELECT * FROM user where id=? 
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
cn.itcast.mybatis.po.User@1a6778eb
DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@5f85f4b7]
DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@5f85f4b7]
DEBUG [main] - Returned connection 1602614455 to pool.
DEBUG [main] - Cache Hit Ratio [cn.itcast.mybatis.mapper.UserMapper]: 0.5
cn.itcast.mybatis.po.User@7b781fdd

   只有第一次发出了sql语句,第二次并没有去查询。


   加入带有commit操作的代码:


@Test
	public void testCache2() throws Exception {
		SqlSession sqlSession1=sqlSessionFactory.openSession();
		SqlSession sqlSession2=sqlSessionFactory.openSession();
		SqlSession sqlSession3=sqlSessionFactory.openSession();
		
		//创建代理对象
		UserMapper userMapper1=sqlSession1.getMapper(UserMapper.class);
		UserMapper userMapper2=sqlSession2.getMapper(UserMapper.class);
		UserMapper userMapper3=sqlSession2.getMapper(UserMapper.class);
		//第一次发起请求,查询id为1的用户
		User user1=userMapper1.findUserById(1);
		System.out.println(user1.toString());

		//这里执行关闭操作,将sqlSession中数据写入二级缓存中去
		sqlSession1.close();
		
		/*使用sqlSession3执行commit操作*/
		User user=userMapper3.findUserById(1);
		user.setAddress("(>﹏<");
		userMapper3.updateUser(user);
		//执行提交清空二级缓存
		sqlSession3.commit();
		sqlSession3.close();
		
		
		//第二次发起请求,查询id为1的用户
		User user2=userMapper2.findUserById(1);
		System.out.println(user2.toString());
		
		sqlSession2.close();
		
	}


输出信息:


DEBUG [main] - Cache Hit Ratio [cn.itcast.mybatis.mapper.UserMapper]: 0.0
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 447056233.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@1aa58969]
DEBUG [main] - ==>  Preparing: SELECT * FROM user where id=? 
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
cn.itcast.mybatis.po.User@c355f75
DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@1aa58969]
DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@1aa58969]
DEBUG [main] - Returned connection 447056233 to pool.
DEBUG [main] - Cache Hit Ratio [cn.itcast.mybatis.mapper.UserMapper]: 0.5
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Checked out connection 447056233 from pool.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@1aa58969]
DEBUG [main] - ==>  Preparing: update user set username=?,birthday=?,sex=?,address=? where id=? 
DEBUG [main] - ==> Parameters: lhccccccccc(String), 2016-05-21 00:00:00.0(Timestamp), 1(String), (>﹏<(String), 1(Integer)
DEBUG [main] - <==    Updates: 1
DEBUG [main] - ==>  Preparing: SELECT * FROM user where id=? 
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
cn.itcast.mybatis.po.User@320e64a7
DEBUG [main] - Rolling back JDBC Connection [com.mysql.jdbc.JDBC4Connection@1aa58969
DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@1aa58969]
DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@1aa58969]
DEBUG [main] - Returned connection 447056233 to pool.

   代码中加入了需要commit的更改操作,二级缓存被更新,查询时候需要重新发出sql语句。


四,一些其他配置


1,禁用二级缓存


<select id="findUserById" parameterType="int"
		resultType="cn.itcast.mybatis.po.User" useCache="false">
		SELECT * FROM user where id=#{value}
	</select>

    在某个statement中设置usecache="false"会禁用当前二级缓存,即每次都会发出sql去查询新数据。默认情况是true.



2,刷新缓存(清空)


    在mapper的同一个namespace中,如果有其它insertupdatedelete操作数据后需要刷新缓存,如果不执行刷新缓存会出现脏读。


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


<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" flushCache="true">

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








相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
目录
相关文章
|
2月前
|
SQL 缓存 监控
MySQL缓存机制:查询缓存与缓冲池优化
MySQL缓存机制是提升数据库性能的关键。本文深入解析了MySQL的缓存体系,包括已弃用的查询缓存和核心的InnoDB缓冲池,帮助理解缓存优化原理。通过合理配置,可显著提升数据库性能,甚至达到10倍以上的效果。
|
4月前
|
存储 缓存 NoSQL
mybatisplus一二级缓存
MyBatis-Plus 继承并优化了 MyBatis 的一级与二级缓存机制。一级缓存默认开启,作用于 SqlSession,适用于单次会话内的重复查询;二级缓存需手动开启,跨 SqlSession 共享,适合提升多用户并发性能。支持集成 Redis 等外部存储,增强缓存能力。
|
2月前
|
存储 缓存 NoSQL
Redis专题-实战篇二-商户查询缓存
本文介绍了缓存的基本概念、应用场景及实现方式,涵盖Redis缓存设计、缓存更新策略、缓存穿透问题及其解决方案。重点讲解了缓存空对象与布隆过滤器的使用,并通过代码示例演示了商铺查询的缓存优化实践。
189 1
Redis专题-实战篇二-商户查询缓存
|
4月前
|
SQL XML Java
MyBatis Mapper中使用limit参数的查询问题
总结而言,MyBatis中使用 `limit`参数的查询可以高度定制并且灵活,基于方法签名和XML映射文件的组合来达成多样化的查询需求。通过参数化查询和动态SQL,MyBatis可以有效地处理各种复杂情境下的数据库操作,并且将SQL语句的维护与业务代码的编写相分离,提升代码的可维护性和可阅读性。
458 13
|
6月前
|
缓存 数据挖掘 BI
|
6月前
|
缓存 Java 数据库连接
Mybatis一级缓存详解
Mybatis一级缓存为开发者提供跨数据库操作的一致性保证,有效减轻数据库负担,提高系统性能。在使用过程中,需要结合实际业务场景选择性地启用一级缓存,以充分发挥其优势。同时,开发者需注意其局限性,并做好事务和并发控制,以确保系统的稳定性和数据的一致性。
227 20
|
5月前
|
SQL Java 数据库
解决Java Spring Boot应用中MyBatis-Plus查询问题的策略。
保持技能更新是侦探的重要素质。定期回顾最佳实践和新技术。比如,定期查看MyBatis-Plus的更新和社区的最佳做法,这样才能不断提升查询效率和性能。
235 1
|
8月前
|
缓存 Java 数据库连接
Mybatis一级缓存、二级缓存详讲
本文介绍了MyBatis中的查询缓存机制,包括一级缓存和二级缓存。一级缓存基于同一个SqlSession对象,重复查询相同数据时可直接从缓存中获取,减少数据库访问。执行`commit`操作会清空SqlSession缓存。二级缓存作用于同一namespace下的Mapper对象,支持数据共享,需手动开启并实现序列化接口。二级缓存通过将数据存储到硬盘文件中实现持久化,为优化性能,通常在关闭Session时批量写入缓存。文章还说明了缓存的使用场景及注意事项。
301 7
Mybatis一级缓存、二级缓存详讲
|
8月前
|
缓存 NoSQL 关系型数据库
WordPress数据库查询缓存插件
这款插件通过将MySQL查询结果缓存至文件、Redis或Memcached,加速页面加载。它专为未登录用户优化,支持跨页面缓存,不影响其他功能,且可与其他缓存插件兼容。相比传统页面缓存,它仅缓存数据库查询结果,保留动态功能如阅读量更新。提供三种缓存方式选择,有效提升网站性能。
165 1
|
9月前
|
缓存 Java 数据库连接
十、MyBatis的缓存
十、MyBatis的缓存
194 6