08. 一級緩存和二級緩存

08. 一級緩存和二級緩存

1、一級緩存

Mybatis的一級緩存是指Session緩存。一級緩存的作用域默認是一個SqlSession。Mybatis默認開啟一級緩存。
也就是在同一個SqlSession中,執(zhí)行相同的查詢SQL,第一次會去數(shù)據(jù)庫進行查詢,并寫到緩存中;
第二次以后是直接去緩存中取。
當執(zhí)行SQL查詢中間發(fā)生了增刪改的操作,MyBatis會把SqlSession的緩存清空。

一級緩存的范圍有SESSION和STATEMENT兩種,默認是SESSION,如果不想使用一級緩存,可以把一級緩存的范圍指定為STATEMENT,這樣每次執(zhí)行完一個Mapper中的語句后都會將一級緩存清除。
如果需要更改一級緩存的范圍,可以在Mybatis的配置文件中,在下通過localCacheScope指定。

<setting name="localCacheScope" value="STATEMENT"/>

一級緩存的生命周期

a、MyBatis在開啟一個數(shù)據(jù)庫會話時,會 創(chuàng)建一個新的SqlSession對象,SqlSession對象中會有一個新的Executor對象。Executor對象中持有一個新的PerpetualCache對象;當會話結束時,SqlSession對象及其內部的Executor對象還有PerpetualCache對象也一并釋放掉。

b、如果SqlSession調用了close()方法,會釋放掉一級緩存PerpetualCache對象,一級緩存將不可用。

c、如果SqlSession調用了clearCache(),會清空PerpetualCache對象中的數(shù)據(jù),但是該對象仍可使用。

d、SqlSession中執(zhí)行了任何一個update操作(update()、delete()、insert()) ,都會清空PerpetualCache對象的數(shù)據(jù),但是該對象可以繼續(xù)使用

示例:

UserMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
<mapper namespace="com.company.project.dao.UserDao">
    
    <sql id="selectResult">
        id,user_name,password,reg_time
    </sql>  

     <resultMap type="UserPo" id="userResult">
        <id property="id" column="id"/>
        <result property="userName"  column="user_name"/>
        <result property="password"  column="password"/>
        <result property="regTime"  column="reg_time"/>
     </resultMap>
    
    <select id="findById" parameterType="int" resultMap="userResult">
        select 
            <include refid="selectResult"></include>
        from
            t_user 
        where id = #{id}
    </select>
    
</mapper>

測試類:

package com.company.project.test;

import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;

import com.company.project.Po.UserPo;
import com.company.project.dao.UserDao;
import com.company.project.util.MyBatisUtil;
import junit.framework.TestCase;

public class UserTest1 extends TestCase{
    Logger logger = Logger.getLogger(UserTest1.class);
    
    public void testFindById() {
        SqlSession sqlSession = null;
        try {
            sqlSession = MyBatisUtil.getSqlSession();
            UserDao userDao = sqlSession.getMapper(UserDao.class);
            UserPo userPo1 = userDao.findById(1);
            logger.debug(userPo1);
            //一級緩存,遇到相同的sql語句會把結果緩存在sqlSession中,
            //除非數(shù)據(jù)庫遇到了delete,update,insert,數(shù)據(jù)庫數(shù)據(jù)發(fā)生了改變,一級緩存就會清除
            //或者sqlSession調用了close()或者clearCache()方法,一級緩存也會清除
            //sqlSession.clearCache();
            UserPo userPo2 = userDao.findById(1);
            logger.debug(userPo2);
        }catch (Exception e) {
            e.printStackTrace();
        }finally {
            sqlSession.close();
        }   
    }
}

結果:

[DEBUG] 2020-06-22 20:28:25,419 ==>  Preparing: select id,user_name,password,reg_time from t_user where id = ? 
[DEBUG] 2020-06-22 20:28:25,449 ==> Parameters: 1(Integer)
[DEBUG] 2020-06-22 20:28:25,472 <==      Total: 1
[DEBUG] 2020-06-22 20:28:25,475 UserPo [id=1, userName=張三, password=123, regTime=2020-06-18]
[DEBUG] 2020-06-22 20:28:25,475 UserPo [id=1, userName=張三, password=123, regTime=2020-06-18]

根據(jù)結果:會發(fā)現(xiàn)開啟一級緩存時,在一個sqlSession對象中,相同的sql語句,只會執(zhí)行一次,然后還緩存下來,后面直接調用結果。

但是,如果數(shù)據(jù)庫遇到了delete,update,insert,數(shù)據(jù)庫數(shù)據(jù)發(fā)生了改變,一級緩存就會清除,或者sqlSession調用了close()或者clearCache()方法,一級緩存也會清除。

2、二級緩存

Mybatis的二級緩存是指mapper映射文件。二級緩存的作用域是同一個namespace下的mapper映射文件內容,多個SqlSession共享。Mybatis需要手動設置啟動二級緩存。

二級緩存是默認啟用的(要生效需要對每個Mapper進行配置),如想取消,則可以通過Mybatis配置文件中的元素下的子元素來指定cacheEnabled為false。

<settings>
  <setting name="cacheEnabled" value="false" />
</settings>

要使用二級緩存除了上面一個配置外,我們還需要在我們每個DAO對應的Mapper.xml文件中定義需要使用的cache。

<mapper namespace="com.company.project.dao.UserDao">
    ...
    <cache />
    ...
</mapper>

二級緩存的原理:

示例:

UserMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
<mapper namespace="com.company.project.dao.UserDao">
    <cache />

    <sql id="selectResult">
        id,user_name,password,reg_time
    </sql>  

     <resultMap type="UserPo" id="userResult">
        <id property="id" column="id"/>
        <result property="userName"  column="user_name"/>
        <result property="password"  column="password"/>
        <result property="regTime"  column="reg_time"/>
     </resultMap>
    
    <select id="findById" parameterType="int" resultMap="userResult">
        select 
            <include refid="selectResult"></include>
        from
            t_user 
        where id = #{id}
    </select>
    
</mapper>

測試:UserTest2.java

package com.company.project.test;

import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;

import com.company.project.Po.UserPo;
import com.company.project.dao.UserDao;
import com.company.project.util.MyBatisUtil;

import junit.framework.TestCase;

public class UserTest2 extends TestCase {
    Logger logger = Logger.getLogger(UserTest1.class);
    
    
    public void testFindById() {
        SqlSession sqlSession1 = null;
        SqlSession sqlSession2 = null;
        try {
            sqlSession1 = MyBatisUtil.getSqlSession();
            UserDao userDao1 = sqlSession1.getMapper(UserDao.class);
            UserPo userPo1 = userDao1.findById(1);
            logger.debug(userPo1);
            
            sqlSession2 = MyBatisUtil.getSqlSession();
            UserDao userDao2 = sqlSession2.getMapper(UserDao.class);
            UserPo userPo2 = userDao2.findById(1);
            logger.debug(userPo2);
        }catch (Exception e) {
            e.printStackTrace();
        }finally {
            sqlSession1.close();
            sqlSession2.close();
        }
    }
}

結果:

[DEBUG] 2020-06-22 20:37:50,141 ==>  Preparing: select id,user_name,password,reg_time from t_user where id = ? 
[DEBUG] 2020-06-22 20:37:50,142 ==> Parameters: 1(Integer)
[DEBUG] 2020-06-22 20:37:50,143 <==      Total: 1
[DEBUG] 2020-06-22 20:37:50,144 UserPo [id=1, userName=張三, password=123, regTime=2020-06-18]

通過觀察,我們發(fā)現(xiàn)開啟了二級緩存,在整個應用中,兩次會話,調用同一句sql,sql只執(zhí)行了一次。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容