国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

緩存的Cache Aside模式

paulli3 / 2521人閱讀

摘要:序本文主要講述下緩存的模式。更新是先更新數(shù)據(jù)庫(kù),成功后,讓緩存失效為什么不是寫(xiě)完數(shù)據(jù)庫(kù)后更新緩存主要是怕兩個(gè)并發(fā)的寫(xiě)操作導(dǎo)致臟數(shù)據(jù)。

本文主要講述下緩存的Cache Aside模式。

Cache Aside

有兩個(gè)要點(diǎn):

應(yīng)用程序先從cache取數(shù)據(jù),沒(méi)有得到,則從數(shù)據(jù)庫(kù)中取數(shù)據(jù),成功后,放到緩存中。

更新是先更新數(shù)據(jù)庫(kù),成功后,讓緩存失效.為什么不是寫(xiě)完數(shù)據(jù)庫(kù)后更新緩存?主要是怕兩個(gè)并發(fā)的寫(xiě)操作導(dǎo)致臟數(shù)據(jù)。

public V read(K key) {
  V result = cache.getIfPresent(key);
  if (result == null) {
    result = readFromDatabase(key);
    cache.put(key, result);
  }

  return result;
}

public void write(K key, V value) {
  writeToDatabase(key, value);
  cache.invalidate(key);
};
臟數(shù)據(jù)

一個(gè)是讀操作,但是沒(méi)有命中緩存,然后就到數(shù)據(jù)庫(kù)中取數(shù)據(jù),此時(shí)來(lái)了一個(gè)寫(xiě)操作,寫(xiě)完數(shù)據(jù)庫(kù)后,讓緩存失效,然后,之前的那個(gè)讀操作再把老的數(shù)據(jù)放進(jìn)去,所以,會(huì)造成臟數(shù)據(jù)。

這個(gè)case理論上會(huì)出現(xiàn),不過(guò),實(shí)際上出現(xiàn)的概率可能非常低,因?yàn)檫@個(gè)條件需要發(fā)生在讀緩存時(shí)緩存失效,而且并發(fā)著有一個(gè)寫(xiě)操作。而實(shí)際上數(shù)據(jù)庫(kù)的寫(xiě)操作會(huì)比讀操作慢得多,而且還要鎖表,而讀操作必需在寫(xiě)操作前進(jìn)入數(shù)據(jù)庫(kù)操作,而又要晚于寫(xiě)操作更新緩存,所有的這些條件都具備的概率基本并不大。

maven
        
        
            com.github.ben-manes.caffeine
            caffeine
            2.5.5
        
        
        
            com.google.guava
            guava
            22.0
        
代碼復(fù)現(xiàn)

這里使用代碼復(fù)現(xiàn)一下這個(gè)臟數(shù)據(jù)場(chǎng)景。

讀操作進(jìn)來(lái),發(fā)現(xiàn)沒(méi)有cache,則觸發(fā)loading,獲取數(shù)據(jù),尚未返回

寫(xiě)操作進(jìn)來(lái),更新數(shù)據(jù)源,invalidate緩存

loading獲取的舊數(shù)據(jù)返回,cache里頭存的是臟數(shù)據(jù)

@Test
    public void testCacheDirty() throws InterruptedException, ExecutionException {
        AtomicReference db = new AtomicReference<>(1);

        LoadingCache cache = CacheBuilder.newBuilder()
                .build(
                new CacheLoader() {
                    public Integer load(String key) throws InterruptedException {
                        LOGGER.info("loading reading from db ...");
                        Integer v = db.get();
                        LOGGER.info("loading read from db get:{}",v);
                        Thread.sleep(1000L); //這里1秒才返回,模擬引發(fā)臟緩存
                        LOGGER.info("loading Read from db return : {}",v);
                        return v;
                    }
                }
        );

        Thread t2 = new Thread(() -> {
            try {
                Thread.sleep(500L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            LOGGER.info("Writing to db ...");
            db.set(2);
            LOGGER.info("Wrote to db");
            cache.invalidate("k");
            LOGGER.info("Invalidated cached");
        });

        t2.start();

        //這里在t2 invalidate 之前 先觸發(fā)cache loading
        //loading那里增加sleep,確保在invalidate之后,cache loading才返回
        //此時(shí)返回的cache就是臟數(shù)據(jù)了
        LOGGER.info("fire loading cache");
        LOGGER.info("get from cache: {}",cache.get("k"));

        t2.join();

        for(int i=0;i<3;i++){
            LOGGER.info("get from cache: {}",cache.get("k"));
        }
    }

輸出

15:54:05.751 [main] INFO com.example.demo.CacheTest - fire loading cache
15:54:05.772 [main] INFO com.example.demo.CacheTest - loading reading from db ...
15:54:05.772 [main] INFO com.example.demo.CacheTest - loading read from db get:1
15:54:06.253 [Thread-1] INFO com.example.demo.CacheTest - Writing to db ...
15:54:06.253 [Thread-1] INFO com.example.demo.CacheTest - Wrote to db
15:54:06.253 [Thread-1] INFO com.example.demo.CacheTest - Invalidated cached
15:54:06.778 [main] INFO com.example.demo.CacheTest - loading Read from db return : 1
15:54:06.782 [main] INFO com.example.demo.CacheTest - get from cache: 1
15:54:06.782 [main] INFO com.example.demo.CacheTest - get from cache: 1
15:54:06.782 [main] INFO com.example.demo.CacheTest - get from cache: 1
15:54:06.782 [main] INFO com.example.demo.CacheTest - get from cache: 1
使用caffeine
@Test
    public void testCacheDirty() throws InterruptedException, ExecutionException {
        AtomicReference db = new AtomicReference<>(1);

        com.github.benmanes.caffeine.cache.LoadingCache cache = Caffeine.newBuilder()
                .build(key -> {
                    LOGGER.info("loading reading from db ...");
                    Integer v = db.get();
                    LOGGER.info("loading read from db get:{}",v);
                    Thread.sleep(1000L); //這里1秒才返回,模擬引發(fā)臟緩存
                    LOGGER.info("loading Read from db return : {}",v);
                    return v;
                });

        Thread t2 = new Thread(() -> {
            try {
                Thread.sleep(500L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            LOGGER.info("Writing to db ...");
            db.set(2);
            LOGGER.info("Wrote to db");
            cache.invalidate("k");
            LOGGER.info("Invalidated cached");
        });

        t2.start();

        //這里在t2 invalidate 之前 先觸發(fā)cache loading
        //loading那里增加sleep,確保在invalidate之后,cache loading才返回
        //此時(shí)返回的cache就是臟數(shù)據(jù)了
        LOGGER.info("fire loading cache");
        LOGGER.info("get from cache: {}",cache.get("k"));

        t2.join();

        for(int i=0;i<3;i++){
            LOGGER.info("get from cache: {}",cache.get("k"));
        }
    }

輸出

16:05:10.141 [main] INFO com.example.demo.CacheTest - fire loading cache
16:05:10.153 [main] INFO com.example.demo.CacheTest - loading reading from db ...
16:05:10.153 [main] INFO com.example.demo.CacheTest - loading read from db get:1
16:05:10.634 [Thread-1] INFO com.example.demo.CacheTest - Writing to db ...
16:05:10.635 [Thread-1] INFO com.example.demo.CacheTest - Wrote to db
16:05:11.172 [main] INFO com.example.demo.CacheTest - loading Read from db return : 1
16:05:11.172 [main] INFO com.example.demo.CacheTest - get from cache: 1
16:05:11.172 [Thread-1] INFO com.example.demo.CacheTest - Invalidated cached
16:05:11.172 [main] INFO com.example.demo.CacheTest - loading reading from db ...
16:05:11.172 [main] INFO com.example.demo.CacheTest - loading read from db get:2
16:05:12.177 [main] INFO com.example.demo.CacheTest - loading Read from db return : 2
16:05:12.177 [main] INFO com.example.demo.CacheTest - get from cache: 2
16:05:12.177 [main] INFO com.example.demo.CacheTest - get from cache: 2
16:05:12.177 [main] INFO com.example.demo.CacheTest - get from cache: 2

這里可以看到invalidate的時(shí)候,loading又重新觸發(fā)了一次,然后臟數(shù)據(jù)就清除了

doc

緩存更新的套路

caffeine: Java 8高性能緩存庫(kù)包

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/61877.html

相關(guān)文章

  • (討論)緩存同步、如何保證緩存一致性、緩存誤用

    摘要:總結(jié)允許的緩存寫(xiě)場(chǎng)景大部分情況,修改成本會(huì)高于增加一次,因此應(yīng)該淘汰緩存如果還在糾結(jié),總是淘汰緩存,問(wèn)題也不大先操作數(shù)據(jù)庫(kù),還是先操作緩存這里分了兩種觀點(diǎn),的觀點(diǎn)沈老師的觀點(diǎn)。這里我覺(jué)得沈老師可能忽略了并發(fā)的問(wèn)題,比如說(shuō)以下情況一個(gè)寫(xiě)請(qǐng)求 緩存誤用 緩存,是互聯(lián)網(wǎng)分層架構(gòu)中,非常重要的一個(gè)部分,通常用它來(lái)降低數(shù)據(jù)庫(kù)壓力,提升系統(tǒng)整體性能,縮短訪問(wèn)時(shí)間。 有架構(gòu)師說(shuō)緩存是萬(wàn)金油,哪里有問(wèn)...

    msup 評(píng)論0 收藏0
  • (討論)緩存同步、如何保證緩存一致性、緩存誤用

    摘要:總結(jié)允許的緩存寫(xiě)場(chǎng)景大部分情況,修改成本會(huì)高于增加一次,因此應(yīng)該淘汰緩存如果還在糾結(jié),總是淘汰緩存,問(wèn)題也不大先操作數(shù)據(jù)庫(kù),還是先操作緩存這里分了兩種觀點(diǎn),的觀點(diǎn)沈老師的觀點(diǎn)。這里我覺(jué)得沈老師可能忽略了并發(fā)的問(wèn)題,比如說(shuō)以下情況一個(gè)寫(xiě)請(qǐng)求 緩存誤用 緩存,是互聯(lián)網(wǎng)分層架構(gòu)中,非常重要的一個(gè)部分,通常用它來(lái)降低數(shù)據(jù)庫(kù)壓力,提升系統(tǒng)整體性能,縮短訪問(wèn)時(shí)間。 有架構(gòu)師說(shuō)緩存是萬(wàn)金油,哪里有問(wèn)...

    y1chuan 評(píng)論0 收藏0
  • 知識(shí)整理之HTML篇

    摘要:最近關(guān)注的重學(xué)前端系列文章,也想把已知的前端知識(shí)體系梳理一遍,夯實(shí)基礎(chǔ)的同時(shí),總結(jié)提升。標(biāo)準(zhǔn)模式的排版和運(yùn)作模式都是以該瀏覽器支持的最高標(biāo)準(zhǔn)運(yùn)行。模式是目前最常用的模式。嚴(yán)格模式不允許展示型棄用元素和框架集。中空格不會(huì)被自動(dòng)刪除。 最近關(guān)注winter的重學(xué)前端系列文章,也想把已知的前端知識(shí)體系梳理一遍,夯實(shí)基礎(chǔ)的同時(shí),總結(jié)提升。接下來(lái)會(huì)從HTML、CSS、JS、性能、網(wǎng)絡(luò)安全、框架通...

    yck 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<