mybatis缓存管理

缓存的作用

mybatis缓存机制用于提高数据库性能,减轻数据压力。

缓存作用域

一级缓存是sqlsession级别的,就是每个sqlsession里都有一个HashMap来存储数据,当然不同对象每个缓存区域也不一样,所以一级缓存是不相互影响的。

二级缓存是mapper级别的的,也就是每个sqlsession都可以访问同一个mapper,这里不是说二级缓存只有一个,也是每个mapper中有一个,就比如UserMapper,TestMapper,当然前提是这两个mapper的namespace是不样的(一般每个mapper都是不一样的),因为真正区别二级缓存的是namespace,也就是每个namespace对应一个独一无二的二级缓存,这里二级缓存的存储也就是HashMap。

《mybatis缓存管理》

mybatis缓存机制

首先一级缓存默认是开启的,一级缓存是sqllsession级别的缓存,sqlsession对象中有一个数据结构HashMap用于存储缓存数据, 不同的sqlsession之间的一级缓存不相互影响的。

二级缓存也是默认开启的,对于每个sqlsession如果查询的是同一个mapper(namespace)都可以从同一个二级缓存中读取。

mybatis缓存特性

当用户进行查询的时候,mybatis提供缓存机制可以将数据存储下来,一遍之后在次查询的时候可以直接从缓存中读取,而不用再次查询数据库,mybatis存储方式HashMap,一级缓存对应的是mapper中的sql的id为key来存储缓存数据,首先当发起请求查询数据库的时候会先产看二级缓存是否开启,如果开启会从二级缓存中查看,如果没有开启会先从mybatis一级中的缓存(HashMap)中去查询,如果不存在那么将会执行sql语句,再将数据存入缓存。当执行更新,删除,插入的时候缓存中的数据将会被清空,清空的目的也就是为了避免从缓存中的读取脏数据,也就是保证缓存中的数据都是最新的数据。

一级缓存代码测试

代码环境是一个spring,mybatis的环境
测试代码1

@Test
	public void OneCacheTest(){
	    ApplicationContext ac = new FileSystemXmlApplicationContext("classpath:spring-context-dao.xml"); 
		SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) ac.getBean("sqlSessionFactory");
		SqlSession sqlSession = sqlSessionFactory.openSession();
		userMapper mapper = sqlSession.getMapper(userMapper.class);
		User user1 = mapper.finduserbyusername("3");
		System.out.println(user1);
		User user2 = mapper.finduserbyusername("3");
		sqlSession.close();
		System.out.println(user2);
	}

结果

20:01:30,003 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger debug:139 -> ==>  Preparing: select username,password,permission from user where username=?; 
20:01:30,050 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger debug:139 -> ==> Parameters: 3(String)
20:01:30,072 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger debug:139 -> <==      Total: 1
20:01:30,072 DEBUG org.springframework.jdbc.datasource.DataSourceUtils doReleaseConnection:327 -> Returning JDBC Connection to DataSource
User [username=3, password=3, permission=]
20:26:34,557 DEBUG org.springframework.jdbc.datasource.DataSourceUtils doReleaseConnection:327 -> Returning JDBC Connection to DataSource
User [username=3, password=3, permission=]

都上结果可以看出这发出了一条sql,第二次没发出sql语句,而是直接从缓存中读取了数据,就是因为这里是同一个sqlsession发起的。

测试代码2

@Test
	public void OneCacheTest(){
	    ApplicationContext ac = new FileSystemXmlApplicationContext("classpath:spring-context-dao.xml"); 
		SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) ac.getBean("sqlSessionFactory");
		SqlSession sqlSession = sqlSessionFactory.openSession();
		userMapper mapper = sqlSession.getMapper(userMapper.class);
		User user1 = mapper.finduserbyusername("3");
		System.out.println(user1);
		mapper.updateuser(new User("3", "3", ""));
		User user2 = mapper.finduserbyusername("3");
		sqlSession.close();
		System.out.println(user2);
	}

结果

20:29:50,018 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger debug:139 -> ==>  Preparing: select username,password,permission from user where username=?; 
20:29:50,061 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger debug:139 -> ==> Parameters: 3(String)
20:29:50,082 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger debug:139 -> <==      Total: 1
User [username=3, password=3, permission=]
20:29:50,083 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger debug:139 -> ==>  Preparing: update user set password = ?, permission = ? where username = ? 
20:29:50,084 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger debug:139 -> ==> Parameters: 3(String), (String), 3(String)
20:29:50,126 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger debug:139 -> <==    Updates: 1
20:29:50,127 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger debug:139 -> ==>  Preparing: select username,password,permission from user where username=?; 
20:29:50,128 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger debug:139 -> ==> Parameters: 3(String)
20:29:50,131 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger debug:139 -> <==      Total: 1
20:29:50,133 DEBUG org.springframework.jdbc.datasource.DataSourceUtils doReleaseConnection:327 -> Returning JDBC Connection to DataSource
User [username=3, password=3, permission=]

这里和上面结果截然不同,这里发起的3条sql原因就是执行更新,删除,添加语句会清空缓存。

二级缓存的配置

二级缓存和一级缓存不一样,一级缓存是默认配置的,二级缓存可以根据自己情况了来配置。

pojo类需要实现序列化接口

public class User implements Serializable

mybatis配置文件的配置

<!-- 全局配置参数 -->
	<settings>
		<!-- 打开延迟加载开关 -->
		<setting name="lazyLoadingEnabled" value="true"/>
		<!-- 关闭积极加载,就是按需加载 -->
		<setting name="aggressiveLazyLoading" value="false"/>
		<!-- 开启二级缓存 -->
		<setting name="cacheEnabled" value="true"/>
	</settings>

这里二级缓存也是默认开启,也就是cacheEnabled默认true。

UserMapper文件配置

<cache/>

只用加这一个就可以使用了。

二级缓存测试代码

这里代码和上代码一样。

@Test
	public void OneCacheTest(){
	    ApplicationContext ac = new FileSystemXmlApplicationContext("classpath:spring-context-dao.xml"); 
		SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) ac.getBean("sqlSessionFactory");
		SqlSession sqlSession = sqlSessionFactory.openSession();
		userMapper mapper = sqlSession.getMapper(userMapper.class);
		User user1 = mapper.finduserbyusername("3");
		System.out.println(user1);
		//mapper.updateuser(new User("3", "3", ""));
		User user2 = mapper.finduserbyusername("3");
		sqlSession.close();
		System.out.println(user2);
	}

结果

20:46:35,738 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger debug:139 -> ==>  Preparing: select username,password,permission from user where username=?; 
20:46:35,787 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger debug:139 -> ==> Parameters: 3(String)
20:46:35,808 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger debug:139 -> <==      Total: 1
User [username=3, password=3, permission=]
20:46:35,809 DEBUG org.apache.ibatis.cache.decorators.LoggingCache getObject:62 -> Cache Hit Ratio [com.my.shiro.Dao.userMapper]: 0.0
20:46:35,813 DEBUG org.springframework.jdbc.datasource.DataSourceUtils doReleaseConnection:327 -> Returning JDBC Connection to DataSource
User [username=3, password=3, permission=]

这里也只执行一次sql,但是注意看多了一条cache hit ratio这里有一个命中率,也就表示二级缓存开启。

这里如果你想要某条语句不开启二级缓存,就比如果密码查询等等,这样不适合开启二级缓存配置。

<select id="finduserbyusername" resultMap="BaseResultMap" parameterType="java.lang.String" useCache="false">
		select <include refid="Base_Column_List"/>
	    from user
	    where username=#{username};
	</select>

这里也就是添加一个属性userCache设置false就是关闭这个sql语句二级缓存,设置代码就不贴上去,结果也差不多就是之前没有开启二级缓存的。

mybatis自身缓存的弊

由于mybatis不是一个专门做缓存处理,现在有一个十分明显的弊端就是,一般我们的网页就是分布式的发布,也就是最少使用两个服务器,如果使用两个服务器mybatis的缓存技术就无法在两个服务器通用就是,也就是两个服务器无法达到数据通用,比如我在一个服务器存储了我的信息,但是我转跳到另一个服务器那使用mybatis数据就是需要从新加载,这里就是一个非常大的问题。还有就是mybatis无法实现细粒度的缓存管理,当你查询大量数据的时候而且将数据存储到mybatis二级缓存中的时候,但是一旦队一个数据操作增加,删除,修改,这里二级缓存就全部清空,而mybatis无法实现对这里单个信息的修改,这里可以使用三级缓存,三级缓存需要自己实现。

mybatis与缓存框架整合

缓存框架这里使用ehcache作为例子,ehcache就是一个分布式框架。

mapper文件配置

<!-- 开启本mapper(namespace)的二级缓存 
  		type:指定cache接口的实现类型,mybatis默认的是PerpetualCache
  		如果要和ehcache整合只需要配置type为ehacache的实现类即可
  		-->
  	<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
  	

这里只需要配置cache的type就可以,这样就可以将缓存数据交给ehcache管理。

ehcache配置文件

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
  updateCheck="false">
	<!--diskStore:缓存数据持久化的目录 地址  -->
	<diskStore path="c:\temp\lhd"/>
	<defaultCache 
		maxElementsInMemory="1000" 
		maxElementsOnDisk="10000000" 
		eternal="false" 
		overflowToDisk="false" 
		diskPersistent="false" 
		timeToIdleSeconds="120" 
		timeToLiveSeconds="120" 
		diskExpiryThreadIntervalSeconds="120" 
		memoryStoreEvictionPolicy="LRU">
	</defaultCache>
</ehcache>

这里就是一些缓存策略。

    原文作者:xnopw
    原文地址: https://blog.csdn.net/ksj_j/article/details/55004053
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞