MyBatis Review——查询缓存

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
云数据库 RDS MySQL Serverless,价值2615元额度,1个月
简介: 一,查询缓存简介        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 表示刷新缓存,这样可以避免数据库脏读。








相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
20天前
|
XML Java 数据库连接
mybatis中在xml文件中通用查询结果列如何使用
mybatis中在xml文件中通用查询结果列如何使用
20 0
|
3月前
|
SQL 缓存 关系型数据库
MySQL技能完整学习列表6、查询优化——3、查询缓存——4、SQL优化技巧
MySQL技能完整学习列表6、查询优化——3、查询缓存——4、SQL优化技巧
65 0
|
2月前
|
Java 关系型数据库 数据库连接
MyBatis Plus 解决大数据量查询慢问题
MyBatis Plus 解决大数据量查询慢问题
|
27天前
|
缓存 关系型数据库 MySQL
MySQL 查询优化:提速查询效率的13大秘籍(索引设计、查询优化、缓存策略、子查询优化以及定期表分析和优化)(中)
MySQL 查询优化:提速查询效率的13大秘籍(索引设计、查询优化、缓存策略、子查询优化以及定期表分析和优化)(中)
|
18天前
|
XML 缓存 Java
MyBatis二级缓存解密:深入探究缓存机制与应用场景
MyBatis二级缓存解密:深入探究缓存机制与应用场景
55 2
MyBatis二级缓存解密:深入探究缓存机制与应用场景
|
2月前
|
SQL Java 数据库连接
Mybatis查询的时候BigDecimal类型的值查询失效的解决办法
Mybatis查询的时候BigDecimal类型的值查询失效的解决办法
|
2月前
|
存储 缓存 Java
什么!?实战项目竟然撞到阿里面试的原题!???关于MyBatis Plus的缓存机制
什么!?实战项目竟然撞到阿里面试的原题!???关于MyBatis Plus的缓存机制
|
2月前
|
缓存 Java 数据库连接
MyBatis Plus的“幻查” 规范到底要怎样使用哪几个查询函数 为什么会出现幻查?还有幻删为什么会删不掉
MyBatis Plus的“幻查” 规范到底要怎样使用哪几个查询函数 为什么会出现幻查?还有幻删为什么会删不掉
|
2月前
|
缓存 Java 数据库连接
mybatis 数据库缓存的原理
MyBatis 是一个流行的 Java 持久层框架,它封装了 JDBC,使数据库交互变得更简单、直观。MyBatis 支持两级缓存:一级缓存(Local Cache)和二级缓存(Global Cache),通过这两级缓存可以有效地减少数据库的访问次数,提高应用性能。
282 1