zoukankan      html  css  js  c++  java
  • mybatis 缓存

    一级缓存

    相同的SQL语句,会优先命中一级缓存,同一个Sqlsession中共享

    一级缓存配置

    • SESSION:默认,当前session有效
    • STATEMENT:只对当前satement有效,每次都查询数据库
    <setting name="localCacheScope" value="STATEMENT"/>
    

    设置缓存级别为STATEMENT

    		SqlSession sqlSession = sqlSessionFactory.openSession();
    		DeviceMapper deviceMapper = sqlSession.getMapper(DeviceMapper.class);
    		System.out.println("deviceMapper读取数据:"+ deviceMapper.getDeviceById(1));
    		System.out.println("deviceMapper读取数据:"+ deviceMapper.getDeviceById(1)); // 不走一级缓存
    		sqlSession.close();
    

    总结

    • 一级缓存只在当前SqlSession中有效
    • 解决一级缓存分布式脏数据问题:设置缓存级别为satement,每次都查询数据库
    • 一级缓存使用HashMap存储缓存数据,当增删改时清除缓存数据

    一级缓存失效情况

    • sqlSession不同
    • sqlSession相同,两次查询之间执行了增删改操作(这次增删改可能对当前数据有影响)
    • sqlSession相同,手动清除了一级缓存(缓存清空)

    二级缓存

    数据的查询执行的流程就是 二级缓存 -> 一级缓存 -> 数据库

    开启二级缓存

    mybatis-config.xml

    		<!-- 开启二级缓存 -->
    		<setting name="cacheEnabled" value="true"/>
    

    mapper.xml

    	<mapper namespace="com.hd.mapper.DeviceMapper">
    	    <update id="update" parameterType="Device">
    	    	update tb_device set device_name = #{device_name} where device_id = #{device_id} limit 1 
    	    </update>
    	    <cache/> <!--开启此mapper的缓存-->
    	</mapper>
    

    测试

    • 提交事务后二级缓存生效
    	        SqlSession session1 = sqlSessionFactory.openSession();
    		SqlSession session2 = sqlSessionFactory.openSession();
    		
    		DeviceMapper deviceMapper1 = session1.getMapper(DeviceMapper.class);
    		DeviceMapper deviceMapper2 = session2.getMapper(DeviceMapper.class);
    		
    		System.out.println("deviceMapper1读取数据:"+deviceMapper1.getDeviceById(1));
     		session1.commit();  // 不提交事务,二级缓存无效,提交事务后,相同查询才会从缓存中获取
    		System.out.println("deviceMapper2读取数据:"+deviceMapper2.getDeviceById(1));
    		
    		session1.close();
    		session2.close();
    

    缓存刷新

    • 增删改操作一样会清除二级缓存
    	        SqlSession session1 = sqlSessionFactory.openSession();
    		SqlSession session2 = sqlSessionFactory.openSession();
    		SqlSession session3 = sqlSessionFactory.openSession();
    		
    		DeviceMapper deviceMapper1 = session1.getMapper(DeviceMapper.class);
    		DeviceMapper deviceMapper2 = session2.getMapper(DeviceMapper.class);
    		DeviceMapper deviceMapper3 = session3.getMapper(DeviceMapper.class);
    		
    		System.out.println("deviceMapper1读取数据:"+deviceMapper1.getDeviceById(1));
    		session1.commit(); // session1提交了事务,deviceMapper2走缓存数据
    		System.out.println("deviceMapper2读取数据:"+deviceMapper2.getDeviceById(1));
    		
    		Device device = new Device();
    		device.setDevice_id(1);
    		device.setDevice_name("test111");
    		deviceMapper3.update(device);
    		session3.commit();  // 更新提交后缓存被刷新,相同的查询走数据库
    		System.out.println("deviceMapper2读取数据:"+deviceMapper2.getDeviceById(1));
    		
    		session1.close();
    		session2.close();
    		session3.close();
    

    二级缓存跨namespace

    设置mapper

    	<mapper namespace="com.hd.mapper.UserMapper">
    		<select id="findRoleByName" parameterType="String" resultType="Role">
    			select r.* from tb_role r inner join  tb_user u on r.role_id = u.role where u.name = #{name};
    		</select>
    		<cache-ref namespace="com.how2java.mapper.RoleMapper"/>  <!--让UserMapper引用RoleMapper命名空间-->
    	</mapper>
    
    	<mapper namespace="com.hd.mapper.RoleMapper">
    		<select id="findAllRole" resultType="com.how2java.pojo.Role">
    			select r.role_name, r.role_desc, r.create_time from tb_role r
    		</select>
    		
    		<update id="update" parameterType="com.how2java.pojo.Role">
    	    	update tb_role set role_name = #{role_name} where role_id = #{role_id} limit 1 
    	    </update>
    	    <cache></cache> <!--开启缓存-->
    	</mapper>
    

    通过用户查询角色名称

    SqlSession session1 = sqlSessionFactory.openSession();
    		SqlSession session2 = sqlSessionFactory.openSession();
    		SqlSession session3 = sqlSessionFactory.openSession();
    		
    		UserMapper userMapper1 = session1.getMapper(UserMapper.class);
    		UserMapper userMapper2 = session2.getMapper(UserMapper.class);
    		RoleMapper roleMapper = session3.getMapper(RoleMapper.class);
    		
    		System.out.println("usermapper1读取数据:"+userMapper1.findRoleByName("testuser"));
    		session1.close();
    		// userMapper2走了二级缓存
    		System.out.println("usermapper2读取数据:"+userMapper2.findRoleByName("testuser"));
    		Role role = new Role();
    		role.setRole_id(3);
    		role.setRole_name("test_modify");
    		roleMapper.update(role);
    		session3.commit();
    		// 缓存刷新,userMapper2查询了数据库
    		System.out.println("usermapper2读取数据:"+userMapper2.findRoleByName("testuser"));
    		
    		session2.close();
    		session3.close();
    

    总结

    • 二级缓存实现了跨sqlsession的缓存,不同mapper之间共享
    • 多表操作时,不建议使用二级缓存,容易产生脏数据

    参考
    https://tech.meituan.com/2018/01/19/mybatis-cache.html

  • 相关阅读:
    Oracle和MySQL的对比
    mysql的默认隔离级别
    mysql数据库中锁机制的详细介绍
    什么电影是好电影
    周记 2019.4.8~4.14
    周记 2019.3.25~2019.3.31
    IntelliJ Idea 使用笔记
    笔记
    kafka总结
    Spring boot
  • 原文地址:https://www.cnblogs.com/xiongyungang/p/14012279.html
Copyright © 2011-2022 走看看