缓存(mybatis)

1.什么是查询缓存:

mybaitis也提供了查询缓存,用于减少数据库访问次数,提高了数据库的性能而存在的一种机制。有一级、二级缓存。



一级缓存:操作数据库时,会操作会话SqlSession对象,在会话对象中有个内存(数据结构HashMap),用于存储缓存数据。

不同的SqlSession他们之间的缓存数据区域是互补影响的。

二级缓存:Mapper级别的缓存,多个SqlSession去操作同一个Mapper的SQL语句。多个SQLSession操作数据库所得到数据会存储在二级缓存区域,可以共用二级缓存,二级缓存是跨SqlSession的。




一级缓存:

第一次发起查询用户id为1的用户信息,先去缓存中找是否有id为1的用户信息,如果没有,会到数据库中查询出来,并存储到一级缓存中。

如果在第一次查询和第二次查询中间有操作事务操作,一级缓存里的数据被自动清空。如果不清除,第二次查询到的还是第一次的数据。为了让缓存中永远存储最新的查询数据,也就是为了避免脏数据。

第二次发起查询用户id为1的用户信息,先去缓存中找是否有id为1的用户信息,查到有,会直接返回出来。


缓存的作用:如果缓存中有需要查询的数据,就不需要去数据库中查找,减少对数据库的访问。


一级缓存测试:

mybaitis和hibernate一样默认开启一级缓存,无须配置。

按照上面一级缓存原理去进行测试。


/**
	 * 首先说明一点,一级缓存就是SqlSession级别的缓存
	 * 一级缓存工作原理:第一次查询的时候,会先去sqlSessionX的缓存查询数据是否存在,
	 * 不存在去数据库查,查到放入sqlSessionX缓存。第二次查同一个ID的数据时,还是先去sqlSessionX缓存找,找到就返回出来。
	 */
	public static void testcache1(){
		
		SqlSession sqlSessionX =  MybaitisUtil.getSQLSession();
	        UserMapper userMapper = sqlSessionX.getMapper(UserMapper.class);	
	        User user1 = userMapper.selectByuid(1);
	        System.out.println(user1);
		User user2 = userMapper.selectByuid(2);//其他ID
		System.out.println(user2);
		User user3 = userMapper.selectByuid(1);
		System.out.println(user3);
                Mybatis.close(sqlSessionX);//关闭之后,再次创建依然是先去session找,肯定没有,去数据库查找数据。

 }

打印结果:


public static void testcache1(){
		
	    SqlSession sqlSessionX =  MybaitisUtil.getSQLSession();
	    UserMapper userMapper = sqlSessionX.getMapper(UserMapper.class);	
	    User user1 = userMapper.selectByuid(1);
	    System.out.println(user1);
	    
	    //进行事务操作
	    user1.setUsername("zhangsan");
	    userMapper.updateuser(user1);
	    sqlSessionX.commit(); //提交事务后,在缓存中的数据会被自动清除。所以,下面的查询会再次去数据库查询。
	    
	    User user2 = userMapper.selectByuid(1);
	    System.out.println(user2);
		

            Mybatis.close(sqlSessionX);

}
打印结果:



在spring和mybaitis的开发中,事务控制在Service层,一个Service包括了多个mapper的调用,

 Service{

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

//第一次调用mapper.findbyId(1);

//第二次调用mapper.findbyId(1);//从一级缓存读取,

//方法结束,SqlSession关闭。


}


如果是执行多次service调用查询相同用户信息,不会搞这个一级缓存,因为SqlSession方法结束,SqlSession就关闭,一级缓存当然就清空!所以,需要使用二级缓存(mapper级别的缓存)。





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

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

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

二级缓存和一级缓存的区别,二级缓存的范围大,多个sqlsession可以共享一个UserMapper的二级缓存区域。

UserMapper有一个二级缓存区域(按照namespace分)其他也有自己的缓存区域。

每一个namespace的mapper都有一个二级缓存区域,两个mapper的namespace如果相同,那么查询到的数据就会放在同一个二级缓存中。

mybatis的二级缓存的准备工作:

1、mybatis-config.xml 添加:<setting name="cacheEnabled" value="true"/>

2、Usermapper.xml 添加:<cache/>

3、pojo需要序列化。

测试代码:

/**
     * 二级缓存测试:
     * 二级缓存是mapper级别的缓存,创建三个usermapper对象,
     * 第一个usermapper去二级缓存查看数据,没有找到去数据库查找,将数据存储在二级缓存内,第二个usermapper首先会去二级缓存,找到将值返回。
     * 如果中间有事务操作,会清空缓存。
     */
public static void testcache2(){
		
		SqlSession sqlSession1 = MybaitisUtil.getSQLSession();
		SqlSession sqlSession2 = MybaitisUtil.getSQLSession();
		SqlSession sqlSession3 = MybaitisUtil.getSQLSession();
		SqlSession sqlSession4 = MybaitisUtil.getSQLSession();
		
	        UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
	        System.out.println(userMapper1.selectByuid(1));
	        sqlSession1.close();
	    
	        UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
	        System.out.println(userMapper2.selectByuid(1));
	        sqlSession2.close();
	    
	    //事务操作
	    UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class);
	    User user = userMapper3.selectByuid(1);
	    user.setUsername("李四");
	    userMapper3.updateuser(user);
	    sqlSession3.commit();//整个UsernMapper缓存被清空
	    sqlSession3.close();
	    
	    UserMapper userMapper4 = sqlSession4.getMapper(UserMapper.class);
	    System.out.println(userMapper4.selectByuid(1));
	    sqlSession4.close();
	    
		
		
	}
打印结果:




每次查询如果需要最新数据,需要禁用二级缓存:在mapper.xml上可以添加useCache="false"。

  <!--查询需要: 输入的映射参数类型parameterType=int,输出映射参数类型resultType=User 是最终查询结果的数据类型-->
  <select id="selectByuid" parameterType="int" resultType="user" useCache="false"> <!-- useCache="false" 禁用二级缓存 -->
     select * from user where id=#{id}  
  </select>

public static void testcache2(){
		
		SqlSession sqlSession1 = MybaitisUtil.getSQLSession();
		SqlSession sqlSession2 = MybaitisUtil.getSQLSession();
		SqlSession sqlSession3 = MybaitisUtil.getSQLSession();
		SqlSession sqlSession4 = MybaitisUtil.getSQLSession();
		
	    UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
	    System.out.println(userMapper1.selectByuid(1));
	    sqlSession1.close();
	    
	    UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
	    System.out.println(userMapper2.selectByuid(1));
	    sqlSession2.close();
	    
	    //事务操作
//	    UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class);
//	    User user = userMapper3.selectByuid(1);
//	    user.setUsername("李四");
//	    userMapper3.updateuser(user);
//	    sqlSession3.commit();
//	    sqlSession3.close();
	    
	    UserMapper userMapper4 = sqlSession4.getMapper(UserMapper.class);
	    System.out.println(userMapper4.selectByuid(1));
	    sqlSession4.close();
	    
		
	}

打印结果:




2.分布式缓存:

如图:现在又服务器1和服务器2。用户向服务器1请求数据查询,把缓存存储在服务器1,当用户请求到服务器2的时候,发现并没有缓存,这就是一个很尴尬的事情。

mybatis需要和其他框架整合,对缓存数据进行集中管理。





为了系统的性能提升,对缓存数据进行集中的管理,使用分布式缓存。


3.应用场景和局限性

对于访问多的查询请求且用户查询结果实时性不高,此时可以采用mybatis二级缓存技术降低数据库的访问量,业务场景:耗时较高的统计分析Sql,电话账单查询sql等等,

通过设置刷新间隔时间,由mybatis每隔一段时间自动清空缓存,根据数据变化频率设置缓存刷新间隔flushinterval,比如30分钟一小时24小时。

mybaitis二级缓存粒度的数据级别缓存实现不好,比如:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次都能查询最新的商品,此时就无法满足刷新当前商品信息,而不刷新其他商品,因为mybatis的二级缓存是以mapper位单位的,解决这种问题需要在业务层根据需求对数据库有针对性缓存。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值