MyBatis學習(6)
1、緩存
1.1、緩存的意義
將用戶經常查詢的數據放在緩存(內存)中,用戶去查詢數據就不用從磁盤上(關系型數據庫數據文件)查詢,從緩存中查詢,從而提高查詢效率,解決了高並發系統的性能問題
1.2、一級緩存
MyBatis的一級緩存的作用域是session,當openSession()後,如果執行相同的sql(相同語句和參數,MyBatis不執行sql,而是從緩存中命中並返回)
Mybatis執行查詢時首先去緩存區中命中,如果命中直接返回,沒有命中則執行sql,從數據庫中查詢
註意:mybatis和spring整合後進行mapper代理開發,不支持一級緩存,mybatis和spring整合,spring按照mapper的模板去生成mapper代理對象,模板中在最後統一關閉sqlsession
1.2.1、測試一級緩存
@Test
public void testCache()throws Exception{
User user = userMapper.selectUserById(8);
System.out.println(user);
User user2 = userMapper.selectUserById(8);
System.out.println(user2);
}
日誌文件
DEBUG - Opening JDBC Connection DEBUG - Created connection 1667925979. DEBUG - Setting autocommit to false on JDBC Connection [oracle.jdbc.driver.T4CConnection@636a87db] DEBUG - ==> Preparing: select userid,user_name as userName,age,pwd,sex,birthday from tb_user where userid = ? DEBUG - ==> Parameters: 8(Integer) DEBUG - <== Total: 1 User [userid=8, userName=hello, pwd=123456, age=18, sex=男, birthday=Tue Aug 14 10:19:19 CST 2018] User [userid=8, userName=hello, pwd=123456, age=18, sex=男, birthday=Tue Aug 14 10:19:19 CST 2018] DEBUG - Resetting autocommit to true on JDBC Connection [oracle.jdbc.driver.T4CConnection@636a87db] DEBUG - Closing JDBC Connection [oracle.jdbc.driver.T4CConnection@636a87db] DEBUG - Returned connection 1667925979 to pool.
發現只發出一條sql語句,第二次執行實際上是從緩存拿去這個數據
1.2.2、刷新緩存操作
sqlSession.clearCache();
@Test public void testCache()throws Exception{ User user = userMapper.selectUserById(8); System.out.println(user); //清除緩存 sqlSession.clearCache(); User user2 = userMapper.selectUserById(8); System.out.println(user2); }
日誌文件
DEBUG - Opening JDBC Connection
DEBUG - Created connection 823632238.
DEBUG - Setting autocommit to false on JDBC Connection [oracle.jdbc.driver.T4CConnection@3117a16e]
DEBUG - ==> Preparing: select userid,user_name as userName,age,pwd,sex,birthday from tb_user where userid = ?
DEBUG - ==> Parameters: 8(Integer)
DEBUG - <== Total: 1
User [userid=8, userName=hello, pwd=123456, age=18, sex=男, birthday=Tue Aug 14 10:19:19 CST 2018]
DEBUG - ==> Preparing: select userid,user_name as userName,age,pwd,sex,birthday from tb_user where userid = ?
DEBUG - ==> Parameters: 8(Integer)
DEBUG - <== Total: 1
User [userid=8, userName=hello, pwd=123456, age=18, sex=男, birthday=Tue Aug 14 10:19:19 CST 2018]
DEBUG - Resetting autocommit to true on JDBC Connection [oracle.jdbc.driver.T4CConnection@3117a16e]
DEBUG - Closing JDBC Connection [oracle.jdbc.driver.T4CConnection@3117a16e]
DEBUG - Returned connection 823632238 to pool.
執行了更新操作
@Test
public void testCache()throws Exception{
User user = userMapper.selectUserById(8);
System.out.println(user);
user.setUserName("李白");
userMapper.insertUser(user);
sqlSession.commit();
User user2 = userMapper.selectUserById(8);
System.out.println(user2);
}
日誌文件
DEBUG - Opening JDBC Connection
DEBUG - Created connection 1782252248.
DEBUG - Setting autocommit to false on JDBC Connection [oracle.jdbc.driver.T4CConnection@6a3b02d8]
DEBUG - ==> Preparing: select userid,user_name as userName,age,pwd,sex,birthday from tb_user where userid = ?
DEBUG - ==> Parameters: 8(Integer)
DEBUG - <== Total: 1
User [userid=8, userName=hello, pwd=123456, age=18, sex=男, birthday=Tue Aug 14 10:19:19 CST 2018]
DEBUG - ==> Preparing: insert into tb_user(userid,user_name,age,pwd,sex,birthday) values(seq_user.nextval,?,?,?,?,?)
DEBUG - ==> Parameters: 李白(String), 18(Integer), 123456(String), 男(String), 2018-08-14 10:19:19.0(Timestamp)
DEBUG - <== Updates: 1
DEBUG - Committing JDBC Connection [oracle.jdbc.driver.T4CConnection@6a3b02d8]
DEBUG - ==> Preparing: select userid,user_name as userName,age,pwd,sex,birthday from tb_user where userid = ?
DEBUG - ==> Parameters: 8(Integer)
DEBUG - <== Total: 1
User [userid=8, userName=hello, pwd=123456, age=18, sex=男, birthday=Tue Aug 14 10:19:19 CST 2018]
DEBUG - Resetting autocommit to true on JDBC Connection [oracle.jdbc.driver.T4CConnection@6a3b02d8]
DEBUG - Closing JDBC Connection [oracle.jdbc.driver.T4CConnection@6a3b02d8]
DEBUG - Returned connection 1782252248 to pool.
1.3、二級緩存
mybatis 的二級緩存的作用域是一個mapper的namespace ,同一個namespace中查詢sql可以從緩存中命中
每次查詢先看是否開啟二級緩存,如果開啟從二級緩存的數據結構中取緩存數據,
二級緩存的範圍是mapper級別(mapper同一個命名空間),mapper以命名空間為單位創建緩存數據結構,結構是map<key、value>。
如果從二級緩存沒有取到,再從一級緩存中找,如果一級緩存也沒有 ,從數據庫中查詢
1.3.1、二級緩存
mybatis二級緩存需要將查詢結果映射的pojo實現 java.io.serializable接口,如果不實現則拋出異常
二級緩存可以將內存的數據寫到磁盤,存在對象的序列化和反序列化,所以要實現java.io.serializable接口。
如果結果映射的pojo中還包括了pojo,都要實現java.io.serializable接口。
1.3.2、開啟二級緩存
開啟全局開關(mybatis-config.xml)
<settings>
<setting name="mapUnderscoreToCamelCase" value="false"/>
<!-- 二級緩存的全局開關 -->
<setting name="cacheEnabled" value="true"/>
</settings>
開啟局部開關
<mapper namespace="cn.org.kingdom.mapper.UserMapper">
<cache/>
...
</mapper>
1.3.3、測試二級緩存
@Test
public void testCache2()throws Exception{
User user = userMapper.selectUserById(8);
System.out.println(user);
sqlSession.close();
sqlSession = sqlSessionFactory.openSession();
userMapper = sqlSession.getMapper(UserMapper.class);
User user2 = userMapper.selectUserById(8);
System.out.println(user2);
}
日誌文件
DEBUG - Checking to see if class cn.org.kingdom.mapper.UserMapper matches criteria [is assignable to Object]
DEBUG - Cache Hit Ratio [cn.org.kingdom.mapper.UserMapper]: 0.0
DEBUG - Opening JDBC Connection
DEBUG - Created connection 221388699.
DEBUG - Setting autocommit to false on JDBC Connection [oracle.jdbc.driver.T4CConnection@d321f9b]
DEBUG - ==> Preparing: select userid,user_name as userName,age,pwd,sex,birthday from tb_user where userid = ?
DEBUG - ==> Parameters: 8(Integer)
DEBUG - <== Total: 1
User [userid=8, userName=hello, pwd=123456, age=18, sex=男, birthday=Tue Aug 14 10:19:19 CST 2018]
DEBUG - Resetting autocommit to true on JDBC Connection [oracle.jdbc.driver.T4CConnection@d321f9b]
DEBUG - Closing JDBC Connection [oracle.jdbc.driver.T4CConnection@d321f9b]
DEBUG - Returned connection 221388699 to pool.
DEBUG - Cache Hit Ratio [cn.org.kingdom.mapper.UserMapper]: 0.5
User [userid=8, userName=hello, pwd=123456, age=18, sex=男, birthday=Tue Aug 14 10:19:19 CST 2018]
1.3.4、刷新緩存
如果sqlsession操作commit操作,對二級緩存進行刷新(全局清空)。設置statement的flushCache是否刷新緩存,默認值是true。
測試類
@Test
public void testCache2()throws Exception{
//查詢
User user = userMapper.selectUserById(8);
System.out.println(user);
sqlSession.close();
//更新操作
user.setUserName("小喬");
SqlSession session2 = sqlSessionFactory.openSession();
UserMapper userMapper3 = session2.getMapper(UserMapper.class);
userMapper3.updateUser(user);
session2.commit();
//再次查詢
sqlSession = sqlSessionFactory.openSession();
userMapper = sqlSession.getMapper(UserMapper.class);
User user2 = userMapper.selectUserById(8);
System.out.println(user2);
}
mapper.xml中
<update id="updateUser" flushCache="false">
update tb_user set user_name=#{userName},age=#{age},pwd=#{pwd},sex=#{sex},birthday=#{birthday}
where userid=#{userid}
</update>
日誌
DEBUG - Created connection 876236253.
DEBUG - Setting autocommit to false on JDBC Connection [oracle.jdbc.driver.T4CConnection@343a4ddd]
DEBUG - ==> Preparing: select userid,user_name as userName,age,pwd,sex,birthday from tb_user where userid = ?
DEBUG - ==> Parameters: 8(Integer)
DEBUG - <== Total: 1
User [userid=8, userName=冰封戰神, pwd=123456, age=18, sex=男, birthday=Tue Aug 14 10:19:19 CST 2018]
DEBUG - Resetting autocommit to true on JDBC Connection [oracle.jdbc.driver.T4CConnection@343a4ddd]
DEBUG - Closing JDBC Connection [oracle.jdbc.driver.T4CConnection@343a4ddd]
DEBUG - Returned connection 876236253 to pool.
DEBUG - Opening JDBC Connection
DEBUG - Checked out connection 876236253 from pool.
DEBUG - Setting autocommit to false on JDBC Connection [oracle.jdbc.driver.T4CConnection@343a4ddd]
DEBUG - ==> Preparing: update tb_user set user_name=?,age=?,pwd=?,sex=?,birthday=? where userid=?
DEBUG - ==> Parameters: 小喬(String), 18(Integer), 123456(String), 男(String), 2018-08-14 10:19:19.0(Timestamp), 8(Integer)
DEBUG - <== Updates: 1
DEBUG - Committing JDBC Connection [oracle.jdbc.driver.T4CConnection@343a4ddd]
DEBUG - Cache Hit Ratio [cn.org.kingdom.mapper.UserMapper]: 0.5
User [userid=8, userName=冰封戰神, pwd=123456, age=18, sex=男, birthday=Tue Aug 14 10:19:19 CST 2018]
對於緩存使用,一般情況,我們要經常使用的數據,這些數據不會發生太大的變化,或者對用戶沒有什麽影響
1.3.5、緩存的高級設置
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
這個更高級的配置創建了一個 FIFO 緩存,並每隔 60 秒刷新,存數結果對象或列表的 512 個引用,而且返回的對象被認為是只讀的,因此在不同線程中的調用者之間修改它們會 導致沖突。
可用的收回策略有:
LRU
– 最近最少使用的:移除最長時間不被使用的對象。FIFO
– 先進先出:按對象進入緩存的順序來移除它們。SOFT
– 軟引用:移除基於垃圾回收器狀態和軟引用規則的對象。WEAK
– 弱引用:更積極地移除基於垃圾收集器狀態和弱引用規則的對象。
默認的是 LRU。
flushInterval(刷新間隔)可以被設置為任意的正整數,而且它們代表一個合理的毫秒 形式的時間段。默認情況是不設置,也就是沒有刷新間隔,緩存僅僅調用語句時刷新。
size(引用數目)可以被設置為任意正整數,要記住你緩存的對象數目和你運行環境的 可用內存資源數目。默認值是 1024。
readOnly(只讀)屬性可以被設置為 true 或 false。只讀的緩存會給所有調用者返回緩 存對象的相同實例。因此這些對象不能被修改。這提供了很重要的性能優勢。可讀寫的緩存 會返回緩存對象的拷貝(通過序列化) 。這會慢一些,但是安全,因此默認是 false。
最後歡迎關註我的網絡課堂:https://edu.51cto.com/sd/ef353
MyBatis學習(6)