MyBatis Review——查询缓存

一,查询缓存简介

        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,一级缓存的应用

   正式开发,是将mybatis和spring进行整合开发,事务控制在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中,如果有其它insert、update、delete操作数据后需要刷新缓存,如果不执行刷新缓存会出现脏读。

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

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

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

时间: 2024-10-28 00:52:22

MyBatis Review——查询缓存的相关文章

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

查询缓存 1.什么是查询缓存 mybatis提供查询缓存,用于减轻数据压力,提高数据库性能. mybaits提供一级缓存,和二级缓存. 缓存模式图如图 一级缓存是SqlSession级别的缓存.在操作数据库时需要构造 sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据.不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的. 二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSessio

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

二级缓存原理 1.原理 首先看图 首先开启mybatis的二级缓存. sqlSession1去查询用户id为1的用户信息,查询到用户信息会将查询数据存储到二级缓存中. 如果SqlSession3去执行相同 mapper下sql,执行commit提交,清空该 mapper下的二级缓存区域的数据. sqlSession2去查询用户id为1的用户信息,去缓存中找是否存在数据,如果存在直接从缓存中取出数据. 二级缓存与一级缓存区别,二级缓存的范围更大,多个sqlSession可以共享一个UserMapp

mybatis缓存和hibernate缓存的理解问题和区别。类缓存和查询缓存的理解和区别

问题描述 mybatis缓存和hibernate缓存的理解问题和区别.类缓存和查询缓存的理解和区别 Hibernate的一级缓存的目的是为了方便管理实体类的状态(临时状态.持久化状态.游离状态.删除状态).Hibernate的目的二级缓存是为了减少sql语句.那么mybatis的一级缓存和二级缓存的目的是为了什么? Hibernate的二级缓存通常使用ehcache,通常配置的是实体类,所以ehcache里面配置实体类是属于类缓存吗? 类缓存到底在什么地方优化?怎样减少sql语句? 查询缓存到底

mybatis 高级映射和spring整合之查询缓存(5)

mybatis 高级映射和spring整合之查询缓存(5) 2.0 查询缓存 2.0.1 什么是查询缓存 mybatis提供缓存,用于减轻数据压力,提高数据库性能. mybatis提供一级缓存和二级缓存. 一级缓存是SqlSession级别的缓存: 在操作数据库时需要购造sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据. 不同的sqlSession之间的缓存数据区域(HashMap)是互不影响的. 二级缓存是mapper级别的缓存: 多个sqlSession区操

MyBatis的一级缓存和二级缓存 以及 mybatis和ehcache缓存框架整合

查询缓存 缓存的意义 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题. 基本由此图可以看出,我们在每一层都需要相应的缓存. mybatis持久层缓存 mybatis提供一级缓存和二级缓存 mybatis一级缓存是一个SqlSession级别,sqlsession只能访问自己的一级缓存的数据,二级缓存是跨sqlSession,是mapper级别的缓存,对于mapper级别的缓存不同的sql

Mysql 第十日 字符集,XA事务,查询缓存

字符集和校对 客户端和服务器设置要要保持一致. 校对规则主要是mysql用来比较字符串,比如按照大小写敏感,或者是二进制. 分别对应了cs,ci(不敏感),bin三个对应项 可以指定校对规则对字段排序,但是这样可能会不使用原来的索引. 分布式事务 XA事务需要一个事务协调器来保证所有的事务参与者都完成了准备工作(第一阶段). 都准备好,则提交所有事务(第二阶段). Mysql不能扮演这个协调者,只能是参与节点. 内部XA 平衡多个存储引擎, 以及存储引擎和写二进制日志之间. 如果打开了写二进制日

MySQL 4.1.0 中文参考手册 --- 6.9 MySQL 查询缓存

mysql|参考|参考手册|缓存|中文 MySQL 4.1.0 中文参考手册 --- 犬犬(心帆)翻译 MySQL Reference Manual for version 4.1.0-alpha. 6.9 MySQL 查询缓存 从 MySQL 4.0.1 开始,MySQL server 有一个重要的特征:Query Cache. 当在使用中,查询缓存会存储一个 SELECT 查询的文本与被传送到客户端的相应结果.如果之后接收到一个同样的查询,服务器将从查询缓存中检索结果,而不是再次分析和执行这

【HIBERNATE框架开发之九】HIBERNATE 性能优化笔记!(遍历、一级/二级/查询/缓存、乐观悲观锁等优化算法)

本站文章均为 李华明Himi 原创,转载务必在明显处注明:  转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/hibernate/825.html 1.   循环分页或者循环进行部分读取处理数据的时候,使用 session.clear() ;   2.    对应1+N(N+1)问题使用如下解决方式: 1): 使用createCriteria进行查询(join fetch) 2):HQL -> join fetch 3): 使用@fetch设置LAZ

MySQL查询缓存 --《高性能MySQL》读书笔记

        Query Cache(QC)         缓存完整的Select结果,当查询命中该缓存,MySQL会立刻返回结果,跳过解析.优化和执行阶段. 1.如何判断缓存命中         缓存存放在一个引用表中,通过哈希值引用.哈希值包括查询本身.待查数据库.客户端协议版本等可能影响返回结果的信息. 注: 当表被lock tables锁住时,仍可以通过查询缓存返回数据. 任何字符不同(包括空格.注释)都会导致缓存的不命中. 不会被缓存:①查询语句包含不确定数据(如函数now().c