第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

MyBatis 緩存

1. 前言

頻繁地查詢必然會給數(shù)據(jù)庫帶來巨大的壓力,為此 MyBatis 提供了豐富的緩存功能。緩存可以有效的提升查詢效率、緩解數(shù)據(jù)庫壓力,提高應(yīng)用的穩(wěn)健性。

MyBatis 的緩存有兩層,默認(rèn)情況下會開啟一級緩存,并提供了開啟二級緩存的配置。本小節(jié)我們將一起學(xué)習(xí) MyBatis 的緩存,充分地了解和使用它。

2. 一級緩存

MyBatis 一級緩存是默認(rèn)開啟的,緩存的有效范圍是一個會話內(nèi)。一個會話內(nèi)的 select 查詢語句的結(jié)果會被緩存起來,當(dāng)在該會話內(nèi)調(diào)用 update、delete 和 insert 時,會話緩存會被刷新,以前的緩存會失效。

2.1 使用一級緩存

下面,我們以一個簡單的例子來看看 MyBatis 的一級緩存是如何工作的。

package com.imooc.mybatis.cache;

import com.imooc.mybatis.mapper.UserMapper;
import com.imooc.mybatis.model.User;
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 java.io.IOException;
import java.io.InputStream;

@SuppressWarnings({"Duplicates"})
public class CacheTest1 {
  public static void main(String[] args) throws IOException {
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    SqlSession session = sqlSessionFactory.openSession();
    // 得到 mapper
    UserMapper userMapper = session.getMapper(UserMapper.class);
    // 查詢得到 user1
    User user1 = userMapper.selectUserById(1);
    System.out.println(user1);
    // 查詢得到 user2
    User user2 = userMapper.selectUserById(1);
    // 通過 == 判斷 user1 和 user2 是否指向同一內(nèi)存區(qū)間
    System.out.println(user1 == user2);
    session.commit();
    session.close();
  }
}

結(jié)果:

User{id=1, username='peter-gao', age=180, score=1000}
true

在這個例子中,我們連續(xù)兩次調(diào)用了 userMapper 的 selectUserById 方法,但是在程序輸出中,user1 和 user2 卻指向了同一塊內(nèi)存區(qū)域。這就是 MyBatis 緩存的作用,當(dāng)?shù)诙握{(diào)用查詢時,MyBatis 沒有查詢數(shù)據(jù)庫而是直接從緩存中拿到了數(shù)據(jù)。

2.2 棄用一級緩存

2.2.1 select 配置關(guān)閉緩存

select 默認(rèn)會啟用一級緩存,我們也可通過配置來關(guān)閉掉 select 緩存。

如下,我們通過 flushCache 屬性來關(guān)閉 select 查詢的緩存。

<select id="selectUserById" flushCache="true" parameterType="java.lang.Integer"
        resultType="com.imooc.mybatis.model.User">
  SELECT * FROM imooc_user WHERE id = #{id}
</select>

再次運行程序,結(jié)果如下:

User{id=1, username='peter-gao', age=180, score=1000}
false

此時 user1 與 user2 不再指向同一內(nèi)存區(qū),緩存失效了。

2.2.2 調(diào)用 insert、update、delete 刷新緩存

一般情況下,我們都推薦開啟 select 的緩存,因為這會節(jié)省查詢時間。當(dāng)然在一個會話中,調(diào)用 insert、update、delete 語句時,會話中的緩存也會被刷新。

如下:

UserMapper userMapper = session.getMapper(UserMapper.class);
User user1 = userMapper.selectUserById(1);
System.out.println(user1);
User user = new User();
user.setUsername("cache test");
user.setAge(10);
user.setScore(100);
userMapper.insertUser(user);
User user2 = userMapper.selectUserById(1);
System.out.println(user1 == user2);
session.commit();
session.close();
User{id=1, username='peter', age=18, score=100}
false

在第一個查詢調(diào)用前,我們先進(jìn)行了一次 insert 操作,此時會刷新緩存,user1 和 user2 又沒有指向同一處內(nèi)存。

3. 二級緩存

MyBatis 二級緩存默認(rèn)關(guān)閉,我們可以通過簡單的設(shè)置來開啟二級緩存。二級緩存的有效范圍為一個 SqlSessionFactory 生命周期,絕大多數(shù)情況下,應(yīng)用都會只有一個 SqlSessionFactory,因此我們可以把二級緩存理解為全局緩存。

3.1 全局可用

在 MyBatis 全局配置文件中,即 mybatis-config.xml 文件,二級緩存可由 settings 下的 cacheEnabled 屬性開啟。如下:

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

當(dāng)打開 cacheEnabled 屬性后,二級緩存全局可用。

TIPS:注意,這里是可用,cacheEnabled 的默認(rèn)值其實也是 true,即全局可用,由于二級緩存需要對 mapper 配置后才真正生效,簡單來說就是雙層開關(guān)。當(dāng)將其設(shè)置為 false 后,則全局關(guān)閉,mapper 中即使配置了,二級緩存也會失效。

3.2 mapper 中開啟

3.2.1 xml 開啟

在二級緩存全局可用的情況下,mapper 才可通過 cache 配置開啟二級緩存。如,在 UserMapper.xml 文件中開啟二級緩存:

<cache/>

這種情況下,緩存的行為如下:

  • mapper 下的所有 select 語句會被緩存;
  • mapper 下的 update,insert,delete 語句會刷新緩存;
  • 使用 LRU 算法來回收對象;
  • 最大緩存 1024 個對象;
  • 緩存可讀、可寫。
  • 緩存不會根據(jù)時間來刷新。

cache 提供了諸多屬性來修改緩存行為,示例如下:

 <cache
    eviction="FIFO"
    flushInterval="60000"
    size="512"
    readOnly="true"/>

這個例子下的緩存使用 FIFO 算法來回收對象,并每隔 60 秒刷新一次,最多緩存 512 個對象,且緩存只可讀。

cache 有 4 個屬性可配置,從而改變緩存的行為。

屬性 描述
eviction 回收策略,默認(rèn) LRU,可選擇的有 FIFO(先進(jìn)先出),SOFT(軟引用),WEAK(弱引用)
flushInterval 刷新時間
size 最多緩存對象數(shù)
readOnly 是否只讀

3.2.2 注解開啟

如果你不使用 mapper.xml 文件,也可以使用注解來開啟。

如下:

package com.imooc.mybatis.mapper;

import org.apache.ibatis.annotations.CacheNamespace;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.cache.decorators.FifoCache;

@Mapper
@CacheNamespace(
  eviction = FifoCache.class,
  flushInterval = 60000,
  size = 512,
  readWrite = false
)
public interface BlogMapper {
}

注解 CacheNamespace 的配置與 xml 配置保持一致,唯一區(qū)別在于若使用注解,那么 eviction 屬性需直接給出緩存實現(xiàn)類。

3.3 緩存共享

3.3.1 xml 共享

有時候,我們想在不同的 mapper 中共享緩存,為了解決這類問題,MyBatis 提供了 cache-ref 配置。

使用也很簡單,如下:

<cache-ref namespace="com.imooc.mybatis.mapper.UserMapper"/>

mapper 由 namespace 來唯一標(biāo)識,因此只需在另一個 mapper 文件中添加上 cache-ref 配置,并加上相應(yīng)的 namespace 即可。

這樣當(dāng)前的 mapper 可以共享來自 UserMapper 的緩存。

3.3.2 注解共享

同樣的,我們也可以使用注解來共享緩存。

如下:

@CacheNamespaceRef(UserMapper.class)
public interface BlogMapper {
}

這里,BlogMapper 共享了 UserMapper 的緩存。

TIPS: 注意,CacheNamespaceRef 與 CacheNamespace 不能共存,既然選擇了共享就不能再獨立開辟緩存區(qū)了。

4. 小結(jié)

  • MyBatis 的一級緩存默認(rèn)可用,有效范圍小,不會影響到其它會話,因此無特殊情況,不推薦丟棄一級緩存。
  • MyBatis 二級緩存默認(rèn)使用程序內(nèi)存緩存,但這顯然不夠安全,一般情況下我們都推薦使用 Redis 等專業(yè)的緩存。