SSM系列4 Mybatis緩存策略與分頁組件PageHelper

繼上一篇筆記 SSM系列3 Mybatis快速上手,今天學習了一下Mybatis的分頁組件與緩存策略,直接上乾貨

Mybatis的緩存策略

Mybatis緩存策略有兩級緩存:
一級緩存:默認開啓,緩存範圍爲一次SqlSession會話,session關閉,該緩存即清空
二級緩存:手動開啓,緩存範圍爲mapper的namespace中,比一級緩存範圍大,生存時間長
一級緩存無論何種操作,進行了commit之後都會被清空
二級緩存的commit的操作,只有在寫操作commit之後纔會被清空,查詢後的commit操作不會清空緩存

一級緩存

代碼演示:

/*緩存測試*/
@Test
public void testFindById(){
    SqlSession session = null;
    try {
        session = sessionFactory.openSession();
        Goods goods = session.selectOne("goods.findById",739);
        System.out.println("session1-對象1:"+goods);
        Goods goods2 = session.selectOne("goods.findById",739);
        System.out.println("session1-對象2:"+goods2);
    }catch (Exception e){
        e.printStackTrace();
    }finally {
        if(session != null){
            session.close();
        }
    }
    try {
        session = sessionFactory.openSession();
        Goods goods = session.selectOne("goods.findById",739);
        System.out.println("session2-對象1:"+goods);
    }catch (Exception e){
        e.printStackTrace();
    }finally {
        if(session != null){
            session.close();
        }
    }
}

我們看如下結果,在同一個session中,進行兩次查詢,但是隻去數據庫查詢了一次,並且兩次接收到的對象是同一個對象,在第二個session中查詢同一條數據,又去數據庫查詢了一次,這說明一級緩存的作用域是一個session會話週期
在這裏插入圖片描述

commit 清空緩存測試

/*緩存測試*/
@Test
public void testFindById(){
    SqlSession session = null;
    try {
        session = sessionFactory.openSession();
        Goods goods = session.selectOne("goods.findById",739);
        System.out.println("session1-對象1:"+goods);
        session.commit();//清空緩存
        Goods goods2 = session.selectOne("goods.findById",739);
        System.out.println("session1-對象2:"+goods2);
    }catch (Exception e){
        e.printStackTrace();
    }finally {
        if(session != null){
            session.close();
        }
    }
}

看下圖結果,去數據庫進行了兩次查詢,並且對象也不一樣,所以commit清空緩存的成立的
在這裏插入圖片描述

禁用緩存

一級緩存可以使用flushCache禁用,用法是在相關的mapper.xml的Sql標籤後面加上flushCache=“true”
flushCache:強制清空緩存,並且該Sql執行後無論得到什麼結果都不會對其進行緩存

<select id="findById" parameterType="Integer" resultType="com.zhangyx.mybatis.entity.Goods" flushCache="true">
   select * from t_goods where goods_id = #{value }
</select>

繼續用剛纔的測試代碼測試,結果如下,下面我也不說太多了,自己看代碼,看結果
在這裏插入圖片描述

二級緩存

二級緩存開啓就需要一些配置了
mybatis-config.xml裏settings裏增加setting項,開啓二級緩存

<!--開啓二級緩存-->
<setting name="cacheEnabled" value="true"/>

相應的mapper.xml我這裏是goods.xml裏增加cache標籤

<!--
    cache:標籤用於配置二級緩存策略
    eviction:是緩存的清除策略,當緩存對象數量達到上限後,自動觸發對應策略對緩存對象進行清除
        1.LRU:最近最少使用的,移除最長時間沒有被使用的對象
        2.FIFO:先進先出,按對象進入緩存的順序進行移除
        3.SOFT:軟引用:移除基於JVM垃圾收集器狀態和軟引用規則來移除對象
        4.WEAK:弱引用:更積極的移除基於JVM垃圾收集器狀態和弱引用的對象
    flushInterval:間隔多長時間自動清空緩存,單位毫秒,600000毫秒=10分鐘
    size:緩存存儲上限,用於保存對象或集合(一個集合=一個對象)的數量上限
    readOnly:
        true:返回只讀緩存,每次從緩存取出的是緩存對象本身,執行效率高
        false:每次取出的是緩存對象的副本,每一次取出的對象都是不同的,安全性高
    -->
<cache eviction="LRU" flushInterval="6000000" size="512" readOnly="true"/>

測試

記得把flushCache選項去掉,這個在二級緩存裏也是起作用的

/*緩存測試*/
@Test
public void testFindById(){
    SqlSession session = null;
    try {
        session = sessionFactory.openSession();
        Goods goods = session.selectOne("goods.findById",739);
        System.out.println("session1-對象1:"+goods);
    }catch (Exception e){
        e.printStackTrace();
    }finally {
        if(session != null){
            session.close();
        }
    }
    try {
        session = sessionFactory.openSession();
        Goods goods = session.selectOne("goods.findById",739);
        System.out.println("session2-對象1:"+goods);
    }catch (Exception e){
        e.printStackTrace();
    }finally {
        if(session != null){
            session.close();
        }
    }
}

結果:第二次也沒有去數據庫進行查詢,直接將第一次查詢的緩存對象取出來了
在這裏插入圖片描述

緩存清空策略

一級緩存清空策略上面已經說過了,利用commit,與flushCache可以清空緩存
二級緩存不一樣嘍,可以利用flushCache="true"清空緩存,useCache="false"禁用緩存
flushCache剛纔已經說過了,這裏不再說了,大家可以自己測試,這裏說一下useCache="false"禁用緩存,跟flushCache一樣,在Sql相關標籤上加上即可

<select id="findById" parameterType="Integer" resultType="com.zhangyx.mybatis.entity.Goods" useCache="false">
        select * from t_goods where goods_id = #{value }
</select>

由於一級緩存的存在,這裏測試需要放在兩個session會話裏

/*緩存測試*/
@Test
public void testFindById(){
    SqlSession session = null;
    try {
        session = sessionFactory.openSession();
        Goods goods = session.selectOne("goods.findById",739);
        System.out.println("session1-對象1:"+goods);
    }catch (Exception e){
        e.printStackTrace();
    }finally {
        if(session != null){
            session.close();
        }
    }
    try {
        session = sessionFactory.openSession();
        Goods goods = session.selectOne("goods.findById",739);
        System.out.println("session2-對象1:"+goods);
    }catch (Exception e){
        e.printStackTrace();
    }finally {
        if(session != null){
            session.close();
        }
    }
}

兩次查詢,兩個對象
在這裏插入圖片描述

寫操作緩存策略

寫操作都沒有緩存,因爲寫操作上面的flushCache默認是開啓的,就以更新爲例看一下

@Test
public void testUpdate(){
    SqlSession session = null;
    //openSession創建一個新的Sqlsession對象,Sqlsession提供了增刪改查的方法調用
    try {
        session = sessionFactory.openSession();
        Goods goods = session.selectOne("goods.findById",2675);
        System.out.println(goods);
        goods.setTitle("數據更新測試");
        goods.setSubTitle("數據更新測試第二標題");
        goods.setCategoryId(1);
        goods.setCurrentPrice(1000f);
        goods.setDiscount(2f);
        goods.setIsFreeDelivery(1);
        goods.setOriginalCost(20f);
        session.update("goods.update", goods);
//            session.commit();//清隊緩存干擾去掉
    }catch (Exception e){
        e.printStackTrace();
        session.rollback();
    }finally {
        if(session != null){
            //將Connection歸還到連接池供其他Session重用
            session.close();
        }
    }
    try {
        session = sessionFactory.openSession();
        Goods goods1 = session.selectOne("goods.findById",2675);
        System.out.println(goods1);
    }catch (Exception e){
        e.printStackTrace();
    }finally {
        if(session != null){
            session.close();
        }
    }
}

在這裏插入圖片描述

使用分頁插件粗略步驟

其實官網有詳細教程:https://pagehelper.github.io/docs/howtouse/
1.引入PageHelper與jsqlparser核心jar包
2.mybatis-config.xml增加有關PageHelper的Plugin配置
3.代碼中查詢數據庫代碼的上方直接使用PageHelper.startPage()自動分頁

pom.xml引入Mybatis分頁組件PageHelper

<!--Mybatis自動分頁 https://pagehelper.github.io/docs/howtouse/ -->
<dependency>
	<groupId>com.github.pagehelper</groupId>
	<artifactId>pagehelper</artifactId>
	<version>5.1.4</version>
</dependency>
<!--Mybatis自動分頁所需的sql解析器-->
<dependency>
	<groupId>com.github.jsqlparser</groupId>
	<artifactId>jsqlparser</artifactId>
	<version>0.9.5</version>
</dependency>

mybatis-config.xml增加plugin配置

<plugins>
	<plugin interceptor="com.github.pagehelper.PageInterceptor">
    	<!--使用的是哪個數據庫,不寫也沒有關係,會根據jdbc驅動自動判斷-->
    	<property name="helperDialect" value="mysql"/>
	    <!--分頁合理化,開啓後,如果查的是第0頁則會自動查第一頁,
    	如果查的頁面數超過總頁數,則會去查最後一頁-->
    	<property name="reasonable" value="true"/>
    </plugin>
</plugins>

測試

@Test
public void testFindAll(){
    SqlSession session = null;
    //openSession創建一個新的Sqlsession對象,Sqlsession提供了增刪改查的方法調用
    try {
        session = sessionFactory.openSession();
        //selectList用於查詢多條數據
        //表.xml裏對應的namespace.sqlId
        //分頁組件,直接在查詢代碼上方加入PageHelper.startPage()即可
        PageHelper.startPage(0,10);
        List<Goods> list = session.selectList("goods.findAll");
        for (Goods goods : list){
            System.out.println(goods.getTitle());
        }
    }catch (Exception e){
        e.printStackTrace();
    }finally {
        if(session != null){
            //將Connection歸還到連接池供其他Session重用
            session.close();
        }
    }
}

運行結果
在這裏插入圖片描述

如果分頁插件裏指定的跟自己使用的數據庫不一樣,比如說指定了oracle,但是我們使用的是mysql會發生什麼情況呢
我們看到,雖然指定的數據庫錯了,但是分頁組件還是按照oracle的形式把要其所用的sql語句組裝了起來,只不過組裝的是oracle可以用的分頁語句

在這裏插入圖片描述
Mybatis告一段落,但是在實際項目開發中,sqlSessionFactory不是這樣使用的,需要配置到xml文件裏的,會在我後面的筆記:Spring SpringMVC Mybatis FreeMarker 整合裏作記錄

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章