緩存的作用
mybatis緩存機制用於提高數據庫性能,減輕數據壓力。
緩存作用域
一級緩存是sqlsession級別的,就是每個sqlsession裏都有一個HashMap來存儲數據,當然不同對象每個緩存區域也不一樣,所以一級緩存是不相互影響的。
二級緩存是mapper級別的的,也就是每個sqlsession都可以訪問同一個mapper,這裏不是說二級緩存只有一個,也是每個mapper中有一個,就比如UserMapper,TestMapper,當然前提是這兩個mapper的namespace是不樣的(一般每個mapper都是不一樣的),因爲真正區別二級緩存的是namespace,也就是每個namespace對應一個獨一無二的二級緩存,這裏二級緩存的存儲也就是HashMap。
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>
這裏就是一些緩存策略。