28Mybatis_查詢緩存-二級緩存-二級緩存測試-


二級緩存原理:

 

首先開啟mybatis的二級緩存。

 

sqlSession1去查詢用戶id為1的用戶信息,查詢到用戶信息會將查詢數據存儲到二級緩存中。

 

如果SqlSession3去執行相同 mapper下sql,執行commit提交,清空該 mapper下的二級緩存區域的數據。

 

sqlSession2去查詢用戶id為1的用戶信息,去緩存中找是否存在數據,如果存在直接從緩存中取出數據。

 

二級緩存與一級緩存區別,二級緩存的范圍更大,多個sqlSession可以共享一個UserMapper的二級緩存區域。

UserMapper有一個二級緩存區域(按namespace分) ,其它mapper也有自己的二級緩存區域(按namespace分)。

每一個namespace的mapper都有一個二緩存區域,兩個mapper的namespace如果相同,這兩個mapper執行sql查詢到數據將存在相同 的二級緩存區域中。

 

 

 

准備工作:

 開啟二級緩存

 

mybaits的二級緩存是mapper范圍級別,除了在SqlMapConfig.xml設置二級緩存的總開關,還要在具體的mapper.xml中開啟二級緩存。

 

在核心配置文件SqlMapConfig.xml中加入

<setting name="cacheEnabled" value="true"/>

 

 

描述

允許值

默認值

cacheEnabled

對在此配置文件下的所有cache 進行全局性開/關設置。

true false

true

 

 

 

 

在UserMapper.xml中開啟二緩存,UserMapper.xml下的sql執行完成會存儲到它的緩存區域(HashMap)。

 

 

測試:

 

第一步:在ordersMapperCustom.xml中開啟二級緩存:

<mapper namespace="cn.itcast.mybatis.mapper.OrdersMapperCustom">
  <cache></cache>

 

 

 

 

第二步:編寫pojo類(要實現Serializable)必須要實現的:

為什么要實現Serializable接口呢:

為了將緩存數據取出執行反序列化操作,因為二級緩存數據存儲介質多種多樣,不一樣在內存。

package cn.itcast.mybatis.po;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

public class User implements Serializable {
private int id;//對應數據庫中主鍵
private String username;//對應數據庫中用戶的名稱
private Date birthday;//對應數據庫中的生日
private String sex;//性別
private String address;//地址
//一個用戶對應多個訂單表
private List<Orders> ordersList;
public List<Orders> getOrdersList() {
    return ordersList;
}
public void setOrdersList(List<Orders> ordersList) {
    this.ordersList = ordersList;
}
public int getId() {
    return id;
}
public void setId(int id) {
    this.id = id;
}
public String getUsername() {
    return username;
}
public void setUsername(String username) {
    this.username = username;
}
public Date getBirthday() {
    return birthday;
}
public void setBirthday(Date birthday) {
    this.birthday = birthday;
}
public String getSex() {
    return sex;
}
public void setSex(String sex) {
    this.sex = sex;
}
public String getAddress() {
    return address;
}
public void setAddress(String address) {
    this.address = address;
}

}

 

 

第三步;編寫測試代碼:

 

package cn.itcast.mybatis.test;

import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;

import cn.itcast.mybatis.mapper.OrdersMapperCustom;
import cn.itcast.mybatis.mapper.userMapper;
import cn.itcast.mybatis.po.Orders;
import cn.itcast.mybatis.po.User;
import cn.itcast.mybatis.po.UserCustom;
import cn.itcast.mybatis.po.UserQueryVo;

public class Mybatis_mappertest {
    
    private SqlSessionFactory sqlSessionFactory;
    @Before
    public void setup() throws IOException
    {   String resource="SqlMapConfig.xml";
        InputStream inputStream= Resources.getResourceAsStream(resource);
        //主要是生成SqlsessionFactory。
        this.sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
    }
    @Test
    public void testMaper()
    {
        SqlSession sqlSession1=null;
        SqlSession sqlSession2=null;
        sqlSession1=sqlSessionFactory.openSession();
        sqlSession2=sqlSessionFactory.openSession();
        //生成代理類
        OrdersMapperCustom orderMapper=sqlSession1.getMapper(OrdersMapperCustom.class);

         OrdersMapperCustom orderMapper2=sqlSession2.getMapper(OrdersMapperCustom.class);



User user
=orderMapper.finduserByid(1); //這個close必須要加,不然緩存存不進去。 sqlSession1.close(); User user2=orderMapper2.finduserByid(1); sqlSession2.close(); } }

 

運行結果:DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@5bae4145]
DEBUG [main] - ==>  Preparing: SELECT * FROM USER WHERE ID=?
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@5bae4145]
DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@5bae4145]
DEBUG [main] - Returned connection 1538146629 to pool.
DEBUG [main] - Cache Hit Ratio [cn.itcast.mybatis.mapper.OrdersMapperCustom]: 0.5

 

 

發現只有一條select語句,說明在執行第二條 User user2=orderMapper2.finduserByid(1)時,二級緩存發揮了作用。

 

 

我們注意到:

     

 //生成兩個sqlsession。因為二級緩,多個sqlSession可以共享一個UserMapper的二級緩存區域。UserMapper有一個二級緩存區域(按namespace分)      
SqlSession sqlSession1=null; SqlSession sqlSession2=null; sqlSession1=sqlSessionFactory.openSession(); sqlSession2=sqlSessionFactory.openSession(); //生成代理類 OrdersMapperCustom orderMapper=sqlSession1.getMapper(OrdersMapperCustom.class); OrdersMapperCustom orderMapper2=sqlSession2.getMapper(OrdersMapperCustom.class); User user=orderMapper.finduserByid(1); User user2=orderMapper2.finduserByid(1);

 

這里的orderMapper,orderMapper2是不同的sqlSession生成的。但是沒關系,二級緩存的作用范圍是1.跨sqlSession.  2.

每一個namespace的mapper都有一個二緩存區域,兩個mapper的namespace如果相同,這兩個mapper執行sql查詢到數據將存在相同 的二級緩存區域中。

 

 

 

 

--------------------------------------------------------------------------------------------------------------------------------------------------------------

 

清空緩存的操作:

// 二級緩存測試
    @Test
    public void testCache2() throws Exception {
        SqlSession sqlSession1 = sqlSessionFactory.openSession();
        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        SqlSession sqlSession3 = sqlSessionFactory.openSession();
        // 創建代理對象
        UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
        // 第一次發起請求,查詢id為1的用戶
        User user1 = userMapper1.findUserById(1);
        System.out.println(user1);
        
        //這里執行關閉操作,將sqlsession中的數據寫到二級緩存區域
        sqlSession1.close();
        
        
        //使用sqlSession3執行commit()操作
        UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class);
        User user  = userMapper3.findUserById(1);
        user.setUsername("張明明");
        userMapper3.updateUser(user);
        //執行提交,清空UserMapper下邊的二級緩存
        sqlSession3.commit();
        sqlSession3.close();
        
        

        UserMapper userMapper2 =    sqlSession2.getMapper(UserMapper.class);
        // 第二次發起請求,查詢id為1的用戶,因為前面的操作清除了緩存,所以這里的操作會重新從數據庫中去查詢。
        User user2 = userMapper2.findUserById(1);
        System.out.println(user2);

        sqlSession2.close();

    }

 

 

 

---------------------------------------------------------------------------------------------------------------------------------------------------------

有沒有這樣的一種情況,一個mapper.xml中,有些sql語句是要緩存功能的,但是有些sql語句我不想他具有緩存功能,需要每次都從數據庫中得到數據?可以

在statement中設置useCache=false可以禁用當前select語句的二級緩存,即每次查詢都會發出sql去查詢,默認情況是true,即該sql使用二級緩存。

<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">

總結:針對每次查詢都需要最新的數據sql,要設置成useCache=false,禁用二級緩存。

 

這樣的話這個mapper.xml中別的sql語句具有二級緩存的功能,這句sql語句就沒有了緩存功能,每次讀取數據時都要從數據庫中去讀數據。

 

 

--------------------------------------------------------------------------------------------------------------------------------------------------------

 

 

 

  刷新緩存(就是清空緩存)

在mapper的同一個namespace中,如果有其它insert、update、delete操作數據后需要刷新緩存,如果不執行刷新緩存會出現臟讀。

 

 設置statement配置中的flushCache="true" 屬性,默認情況下為true即刷新緩存,如果改成false則不會刷新。使用緩存時如果手動修改數據庫表中的查詢數據會出現臟讀。

如下:

<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" flushCache="true">

 

總結:一般下執行完commit操作都需要刷新緩存,flushCache=true表示刷新緩存,這樣可以避免數據庫臟讀。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM