国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Spring Boot多級(jí)緩存實(shí)現(xiàn)方案

這篇具有很好參考價(jià)值的文章主要介紹了Spring Boot多級(jí)緩存實(shí)現(xiàn)方案。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

1.背景

緩存,就是讓數(shù)據(jù)更接近使用者,讓訪(fǎng)問(wèn)速度加快,從而提升系統(tǒng)性能。工作機(jī)制大概是先從緩存中加載數(shù)據(jù),如果沒(méi)有,再?gòu)穆僭O(shè)備(eg:數(shù)據(jù)庫(kù))中加載數(shù)據(jù)并同步到緩存中。

所謂多級(jí)緩存,是指在整個(gè)系統(tǒng)架構(gòu)的不同系統(tǒng)層面進(jìn)行數(shù)據(jù)緩存,以提升訪(fǎng)問(wèn)速度。主要分為三層緩存:網(wǎng)關(guān)nginx緩存、分布式緩存、本地緩存。這里的多級(jí)緩存就是用redis分布式緩存+caffeine本地緩存整合而來(lái)。

平時(shí)我們?cè)陂_(kāi)發(fā)過(guò)程中,一般都是使用redis實(shí)現(xiàn)分布式緩存、caffeine操作本地緩存,但是發(fā)現(xiàn)只使用redis或者是caffeine實(shí)現(xiàn)緩存都有一些問(wèn)題:

  • 一級(jí)緩存:Caffeine是一個(gè)一個(gè)高性能的 Java 緩存庫(kù);使用 Window TinyLfu 回收策略,提供了一個(gè)近乎最佳的命中率。優(yōu)點(diǎn)數(shù)據(jù)就在應(yīng)用內(nèi)存所以速度快。缺點(diǎn)受應(yīng)用內(nèi)存的限制,所以容量有限;沒(méi)有持久化,重啟服務(wù)后緩存數(shù)據(jù)會(huì)丟失;在分布式環(huán)境下緩存數(shù)據(jù)數(shù)據(jù)無(wú)法同步;
  • 二級(jí)緩存:redis是一高性能、高可用的key-value數(shù)據(jù)庫(kù),支持多種數(shù)據(jù)類(lèi)型,支持集群,和應(yīng)用服務(wù)器分開(kāi)部署易于橫向擴(kuò)展。優(yōu)點(diǎn)支持多種數(shù)據(jù)類(lèi)型,擴(kuò)容方便;有持久化,重啟應(yīng)用服務(wù)器緩存數(shù)據(jù)不會(huì)丟失;他是一個(gè)集中式緩存,不存在在應(yīng)用服務(wù)器之間同步數(shù)據(jù)的問(wèn)題。缺點(diǎn)每次都需要訪(fǎng)問(wèn)redis存在IO浪費(fèi)的情況。

綜上所述,我們可以通過(guò)整合redis和caffeine實(shí)現(xiàn)多級(jí)緩存,解決上面單一緩存的痛點(diǎn),從而做到相互補(bǔ)足。

項(xiàng)目推薦:基于SpringBoot2.x、SpringCloud和SpringCloudAlibaba企業(yè)級(jí)系統(tǒng)架構(gòu)底層框架封裝,解決業(yè)務(wù)開(kāi)發(fā)時(shí)常見(jiàn)的非功能性需求,防止重復(fù)造輪子,方便業(yè)務(wù)快速開(kāi)發(fā)和企業(yè)技術(shù)??蚣芙y(tǒng)一管理。引入組件化的思想實(shí)現(xiàn)高內(nèi)聚低耦合并且高度可配置化,做到可插拔。嚴(yán)格控制包依賴(lài)和統(tǒng)一版本管理,做到最少化依賴(lài)。注重代碼規(guī)范和注釋?zhuān)浅_m合個(gè)人學(xué)習(xí)和企業(yè)使用

Github地址:https://github.com/plasticene/plasticene-boot-starter-parent

Gitee地址:https://gitee.com/plasticene3/plasticene-boot-starter-parent

微信公眾號(hào)Shepherd進(jìn)階筆記

交流探討qun:Shepherd_126

2.整合實(shí)現(xiàn)

2.1思路

Spring 本來(lái)就提供了Cache的支持,最核心的就是實(shí)現(xiàn)Cache和CacheManager接口。但是Spring Cache存在以下問(wèn)題:

  • Spring Cache 僅支持單一的緩存來(lái)源,即:只能選擇 Redis 實(shí)現(xiàn)或者 Caffeine 實(shí)現(xiàn),并不能同時(shí)使用。
  • 數(shù)據(jù)一致性:各層緩存之間的數(shù)據(jù)一致性問(wèn)題,如應(yīng)用層緩存和分布式緩存之前的數(shù)據(jù)一致性問(wèn)題。

由此我們可以通過(guò)重新實(shí)現(xiàn)Cache和CacheManager接口,整合redis和caffeine,從而實(shí)現(xiàn)多級(jí)緩存。在講實(shí)現(xiàn)原理之前先看看多級(jí)緩存調(diào)用邏輯圖:

Spring Boot多級(jí)緩存實(shí)現(xiàn)方案,spring boot,緩存,后端

2.2實(shí)現(xiàn)

首先,我們需要一個(gè)多級(jí)緩存配置類(lèi),方便對(duì)緩存屬性的動(dòng)態(tài)配置,通過(guò)開(kāi)關(guān)做到可插拔。

@ConfigurationProperties(prefix = "multilevel.cache")
@Data
public class MultilevelCacheProperties {

    /**
     * 一級(jí)本地緩存最大比例
     */
    private Double maxCapacityRate = 0.2;

    /**
     * 一級(jí)本地緩存與最大緩存初始化大小比例
     */
    private Double initRate = 0.5;

    /**
     * 消息主題
     */
    private String topic = "multilevel-cache-topic";

    /**
     * 緩存名稱(chēng)
     */
    private String name = "multilevel-cache";

    /**
     * 一級(jí)本地緩存名稱(chēng)
     */
    private String caffeineName = "multilevel-caffeine-cache";

    /**
     * 二級(jí)緩存名稱(chēng)
     */
    private String redisName = "multilevel-redis-cache";

    /**
     * 一級(jí)本地緩存過(guò)期時(shí)間
     */
    private Integer caffeineExpireTime = 300;

    /**
     * 二級(jí)緩存過(guò)期時(shí)間
     */
    private Integer redisExpireTime = 600;


    /**
     * 一級(jí)緩存開(kāi)關(guān)
     */
    private Boolean caffeineSwitch = true;

}

在自動(dòng)配置類(lèi)使用@EnableConfigurationProperties(MultilevelCacheProperties.class)注入即可使用。

接下來(lái)就是重新實(shí)現(xiàn)spring的Cache接口,整合caffeine本地緩存和redis分布式緩存實(shí)現(xiàn)多級(jí)緩存

package com.plasticene.boot.cache.core.manager;

import com.plasticene.boot.cache.core.listener.CacheMessage;
import com.plasticene.boot.cache.core.prop.MultilevelCacheProperties;
import com.plasticene.boot.common.executor.plasticeneThreadExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.cache.support.AbstractValueAdaptingCache;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.lang.NonNull;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.Objects;
import java.util.concurrent.*;

/**
 * @author fjzheng
 * @version 1.0
 * @date 2022/7/20 17:03
 */
@Slf4j
public class MultilevelCache extends AbstractValueAdaptingCache {

    @Resource
    private MultilevelCacheProperties multilevelCacheProperties;
    @Resource
    private RedisTemplate redisTemplate;


    ExecutorService cacheExecutor = new plasticeneThreadExecutor(
            Runtime.getRuntime().availableProcessors() * 2,
            Runtime.getRuntime().availableProcessors() * 20,
            Runtime.getRuntime().availableProcessors() * 200,
           "cache-pool"
    );

    private RedisCache redisCache;
    private CaffeineCache caffeineCache;

    public MultilevelCache(boolean allowNullValues,RedisCache redisCache, CaffeineCache caffeineCache) {
        super(allowNullValues);
        this.redisCache = redisCache;
        this.caffeineCache = caffeineCache;
    }


    @Override
    public String getName() {
        return multilevelCacheProperties.getName();

    }

    @Override
    public Object getNativeCache() {
        return null;
    }

    @Override
    public <T> T get(Object key, Callable<T> valueLoader) {
        Object value = lookup(key);
        return (T) value;
    }

    /**
     *  注意:redis緩存的對(duì)象object必須序列化 implements Serializable, 不然緩存對(duì)象不成功。
     *  注意:這里asyncPublish()方法是異步發(fā)布消息,然后讓分布式其他節(jié)點(diǎn)清除本地緩存,防止當(dāng)前節(jié)點(diǎn)因更新覆蓋數(shù)據(jù)而其他節(jié)點(diǎn)本地緩存保存是臟數(shù)據(jù)
     *  這樣本地緩存數(shù)據(jù)才能成功存入
     * @param key
     * @param value
     */
    @Override
    public void put(@NonNull Object key, Object value) {
        redisCache.put(key, value);
        // 異步清除本地緩存
        if (multilevelCacheProperties.getCaffeineSwitch()) {
            asyncPublish(key, value);
        }
    }

    /**
     * key不存在時(shí),再保存,存在返回當(dāng)前值不覆蓋
     * @param key
     * @param value
     * @return
     */
    @Override
    public ValueWrapper putIfAbsent(@NonNull Object key, Object value) {
        ValueWrapper valueWrapper = redisCache.putIfAbsent(key, value);
        // 異步清除本地緩存
        if (multilevelCacheProperties.getCaffeineSwitch()) {
            asyncPublish(key, value);
        }
        return valueWrapper;
    }


    @Override
    public void evict(Object key) {
        // 先清除redis中緩存數(shù)據(jù),然后通過(guò)消息推送清除所有節(jié)點(diǎn)caffeine中的緩存,
        // 避免短時(shí)間內(nèi)如果先清除caffeine緩存后其他請(qǐng)求會(huì)再?gòu)膔edis里加載到caffeine中
        redisCache.evict(key);
        // 異步清除本地緩存
        if (multilevelCacheProperties.getCaffeineSwitch()) {
            asyncPublish(key, null);
        }
    }

    @Override
    public boolean evictIfPresent(Object key) {
        return false;
    }

    @Override
    public void clear() {
        redisCache.clear();
        // 異步清除本地緩存
        if (multilevelCacheProperties.getCaffeineSwitch()) {
            asyncPublish(null, null);
        }
    }



    @Override
    protected Object lookup(Object key) {
        Assert.notNull(key, "key不可為空");
        ValueWrapper value;
        if (multilevelCacheProperties.getCaffeineSwitch()) {
            // 開(kāi)啟一級(jí)緩存,先從一級(jí)緩存緩存數(shù)據(jù)
            value = caffeineCache.get(key);
            if (Objects.nonNull(value)) {
                log.info("查詢(xún)caffeine 一級(jí)緩存 key:{}, 返回值是:{}", key, value.get());
                return value.get();
            }
        }
        value = redisCache.get(key);
        if (Objects.nonNull(value)) {
            log.info("查詢(xún)r(jià)edis 二級(jí)緩存 key:{}, 返回值是:{}", key, value.get());
            // 異步將二級(jí)緩存redis寫(xiě)到一級(jí)緩存caffeine
            if (multilevelCacheProperties.getCaffeineSwitch()) {
                ValueWrapper finalValue = value;
                cacheExecutor.execute(()->{
                    caffeineCache.put(key, finalValue.get());
                });
            }
            return value.get();
        }
        return null;
    }

    /**
     * 緩存變更時(shí)通知其他節(jié)點(diǎn)清理本地緩存
     * 異步通過(guò)發(fā)布訂閱主題消息,其他節(jié)點(diǎn)監(jiān)聽(tīng)到之后進(jìn)行相關(guān)本地緩存操作,防止本地緩存臟數(shù)據(jù)
     */
    void asyncPublish(Object key, Object value) {
        cacheExecutor.execute(()->{
            CacheMessage cacheMessage = new CacheMessage();
            cacheMessage.setCacheName(multilevelCacheProperties.getName());
            cacheMessage.setKey(key);
            cacheMessage.setValue(value);
            redisTemplate.convertAndSend(multilevelCacheProperties.getTopic(), cacheMessage);
        });
    }



}

緩存消息監(jiān)聽(tīng):我們通監(jiān)聽(tīng)caffeine鍵值的移除、打印日志方便排查問(wèn)題,通過(guò)監(jiān)聽(tīng)redis發(fā)布的消息,實(shí)現(xiàn)分布式集群多節(jié)點(diǎn)本地緩存清除從而達(dá)到數(shù)據(jù)一致性。

消息體

@Data
public class CacheMessage implements Serializable {
    private String cacheName;
    private Object key;
    private Object value;
    private Integer type;
}

caffeine移除監(jiān)聽(tīng):

@Slf4j
public class CaffeineCacheRemovalListener implements RemovalListener<Object, Object> {
    @Override
    public void onRemoval(@Nullable Object k, @Nullable Object v, @NonNull RemovalCause cause) {
        log.info("[移除緩存] key:{} reason:{}", k, cause.name());
        // 超出最大緩存
        if (cause == RemovalCause.SIZE) {

        }
        // 超出過(guò)期時(shí)間
        if (cause == RemovalCause.EXPIRED) {
            // do something
        }
        // 顯式移除
        if (cause == RemovalCause.EXPLICIT) {
            // do something
        }
        // 舊數(shù)據(jù)被更新
        if (cause == RemovalCause.REPLACED) {
            // do something
        }
    }
}

redis消息監(jiān)聽(tīng):

@Slf4j
@Data
public class RedisCacheMessageListener implements MessageListener {

    private CaffeineCache caffeineCache;
    @Override
    public void onMessage(Message message, byte[] pattern) {
        log.info("監(jiān)聽(tīng)的redis message: {}" + message.toString());
        CacheMessage cacheMessage = JsonUtils.parseObject(message.toString(), CacheMessage.class);
        if (Objects.isNull(cacheMessage.getKey())) {
            caffeineCache.invalidate();
        } else {
            caffeineCache.evict(cacheMessage.getKey());
        }
    }
}

最后,通過(guò)自動(dòng)配置類(lèi),注入相關(guān)bean:

**
 * @author fjzheng
 * @version 1.0
 * @date 2022/7/20 17:24
 */
@Configuration
@EnableConfigurationProperties(MultilevelCacheProperties.class)
public class MultilevelCacheAutoConfiguration {

    @Resource
    private MultilevelCacheProperties multilevelCacheProperties;

    ExecutorService cacheExecutor = new plasticeneThreadExecutor(
            Runtime.getRuntime().availableProcessors() * 2,
            Runtime.getRuntime().availableProcessors() * 20,
            Runtime.getRuntime().availableProcessors() * 200,
            "cache-pool"
    );

    @Bean
    @ConditionalOnMissingBean({RedisTemplate.class})
    public  RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
        template.setConnectionFactory(factory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setDefaultSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
        template.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
        return template;
    }

    @Bean
    public RedisCache redisCache (RedisConnectionFactory redisConnectionFactory) {
        RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
        RedisCacheConfiguration redisCacheConfiguration = defaultCacheConfig();
        redisCacheConfiguration = redisCacheConfiguration.entryTtl(Duration.of(multilevelCacheProperties.getRedisExpireTime(), ChronoUnit.SECONDS));
        redisCacheConfiguration = redisCacheConfiguration.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));
        redisCacheConfiguration = redisCacheConfiguration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
        RedisCache redisCache = new CustomRedisCache(multilevelCacheProperties.getRedisName(), redisCacheWriter, redisCacheConfiguration);
        return redisCache;
    }

    /**
     * 由于Caffeine 不會(huì)再值過(guò)期后立即執(zhí)行清除,而是在寫(xiě)入或者讀取操作之后執(zhí)行少量維護(hù)工作,或者在寫(xiě)入讀取很少的情況下,偶爾執(zhí)行清除操作。
     * 如果我們項(xiàng)目寫(xiě)入或者讀取頻率很高,那么不用擔(dān)心。如果想入寫(xiě)入和讀取操作頻率較低,那么我們可以通過(guò)Cache.cleanUp()或者加scheduler去定時(shí)執(zhí)行清除操作。
     * Scheduler可以迅速刪除過(guò)期的元素,***Java 9 +***后的版本,可以通過(guò)Scheduler.systemScheduler(), 調(diào)用系統(tǒng)線(xiàn)程,達(dá)到定期清除的目的
     * @return
     */
    @Bean
    @ConditionalOnClass(CaffeineCache.class)
    @ConditionalOnProperty(name = "multilevel.cache.caffeineSwitch", havingValue = "true", matchIfMissing = true)
    public CaffeineCache caffeineCache() {
        int maxCapacity = (int) (Runtime.getRuntime().totalMemory() * multilevelCacheProperties.getMaxCapacityRate());
        int initCapacity = (int) (maxCapacity * multilevelCacheProperties.getInitRate());
        CaffeineCache caffeineCache = new CaffeineCache(multilevelCacheProperties.getCaffeineName(), Caffeine.newBuilder()
                // 設(shè)置初始緩存大小
                .initialCapacity(initCapacity)
                // 設(shè)置最大緩存
                .maximumSize(maxCapacity)
                // 設(shè)置緩存線(xiàn)程池
                .executor(cacheExecutor)
                // 設(shè)置定時(shí)任務(wù)執(zhí)行過(guò)期清除操作
//                .scheduler(Scheduler.systemScheduler())
                // 監(jiān)聽(tīng)器(超出最大緩存)
                .removalListener(new CaffeineCacheRemovalListener())
                // 設(shè)置緩存讀時(shí)間的過(guò)期時(shí)間
                .expireAfterAccess(Duration.of(multilevelCacheProperties.getCaffeineExpireTime(), ChronoUnit.SECONDS))
                // 開(kāi)啟metrics監(jiān)控
                .recordStats()
                .build());
        return caffeineCache;
    }

    @Bean
    @ConditionalOnBean({CaffeineCache.class, RedisCache.class})
    public MultilevelCache multilevelCache(RedisCache redisCache, CaffeineCache caffeineCache) {
        MultilevelCache multilevelCache = new MultilevelCache(true, redisCache, caffeineCache);
        return multilevelCache;
    }

    @Bean
    public RedisCacheMessageListener redisCacheMessageListener(@Autowired CaffeineCache caffeineCache) {
        RedisCacheMessageListener redisCacheMessageListener = new RedisCacheMessageListener();
        redisCacheMessageListener.setCaffeineCache(caffeineCache);
        return redisCacheMessageListener;
    }



    @Bean
    public RedisMessageListenerContainer redisMessageListenerContainer(@Autowired RedisConnectionFactory redisConnectionFactory,
                                                                       @Autowired RedisCacheMessageListener redisCacheMessageListener) {
        RedisMessageListenerContainer redisMessageListenerContainer = new RedisMessageListenerContainer();
        redisMessageListenerContainer.setConnectionFactory(redisConnectionFactory);
        redisMessageListenerContainer.addMessageListener(redisCacheMessageListener, new ChannelTopic(multilevelCacheProperties.getTopic()));
        return redisMessageListenerContainer;
    }

}

3.使用

使用非常簡(jiǎn)單,只需要通過(guò)multilevelCache操作即可:

@RestController
@RequestMapping("/api/data")
@Api(tags = "api數(shù)據(jù)")
@Slf4j
public class ApiDataController {

    @Resource
    private MultilevelCache multilevelCache;

  
    @GetMapping("/put/cache")
    public void put() {
        DataSource ds = new DataSource();
        ds.setName("多級(jí)緩存");
        ds.setType(1);
        ds.setCreateTime(new Date());
        ds.setHost("127.0.0.1");
        multilevelCache.put("test-key", ds);
    }

    @GetMapping("/get/cache")
    public DataSource get() {
        DataSource dataSource = multilevelCache.get("test-key", DataSource.class);
        return dataSource;
    }

}

4.總結(jié)

以上全部就是關(guān)于多級(jí)緩存的實(shí)現(xiàn)方案總結(jié),多級(jí)緩存就是為了解決項(xiàng)目服務(wù)中單一緩存使用不足的缺點(diǎn)。應(yīng)用場(chǎng)景有:接口權(quán)限校驗(yàn),每次請(qǐng)求接口都需要根據(jù)當(dāng)前登錄人有哪些角色,角色有哪些權(quán)限,如果每次都去查數(shù)據(jù)庫(kù)性能開(kāi)銷(xiāo)比較嚴(yán)重,再加上權(quán)限一般不怎么會(huì)頻繁變更,所以使用多級(jí)緩存是最合適不過(guò)了;還有就是很多管理系統(tǒng)列表界面都有組織架構(gòu)信息(所屬部門(mén)、小組等),這些信息同樣可以使用多級(jí)緩存來(lái)完美提升性能。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-633012.html

到了這里,關(guān)于Spring Boot多級(jí)緩存實(shí)現(xiàn)方案的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶(hù)投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Spring Boot 整合支付寶實(shí)現(xiàn)在線(xiàn)支付方案(沙箱環(huán)境)

    Spring Boot 整合支付寶實(shí)現(xiàn)在線(xiàn)支付方案(沙箱環(huán)境)

    TIP:對(duì)于許多個(gè)人開(kāi)發(fā)者而言,實(shí)現(xiàn)支付寶支付功能在以往往往意味著需要跨越復(fù)雜的商業(yè)流程。這涉及到擁有自己的網(wǎng)站及其備案,以及提交營(yíng)業(yè)執(zhí)照等一系列文檔。但現(xiàn)在,支付寶開(kāi)放平臺(tái)帶來(lái)了突破性的便利——通過(guò)沙箱環(huán)境,個(gè)人僅需擁有支付寶賬號(hào),就能夠測(cè)試并

    2024年01月16日
    瀏覽(94)
  • Spring Boot進(jìn)階(67):高性能緩存!使用Spring Boot輕松集成Memcached。

    Spring Boot進(jìn)階(67):高性能緩存!使用Spring Boot輕松集成Memcached。

    ????????Memcached是一款高性能的分布式內(nèi)存對(duì)象緩存系統(tǒng),主要用于動(dòng)態(tài)Web應(yīng)用中減輕數(shù)據(jù)庫(kù)負(fù)載。Spring Boot是一款基于Spring框架的快速開(kāi)發(fā)框架,集成了大量的常用技術(shù)和組件,方便開(kāi)發(fā)者快速搭建項(xiàng)目。將兩者結(jié)合起來(lái),可以提高Web應(yīng)用的性能,并減少數(shù)據(jù)庫(kù)的壓力。

    2024年02月07日
    瀏覽(31)
  • Spring Boot 整合 Shiro(后端)

    Spring Boot 整合 Shiro(后端)

    1 Shiro 什么是 Shiro 官網(wǎng): http://shiro.apache.org/ 是一款主流的 Java 安全框架,不依賴(lài)任何容器,可以運(yùn)行在 Java SE 和 Java EE 項(xiàng)目中,它的主要作用是對(duì)訪(fǎng)問(wèn)系統(tǒng)的用戶(hù)進(jìn)行身份認(rèn)證、 授權(quán)、會(huì)話(huà)管理、加密等操作。 Shiro 就是用來(lái)解決安全管理的系統(tǒng)化框架。 2 Shiro 核心組件 用

    2024年02月09日
    瀏覽(26)
  • Spring Boot 緩存應(yīng)用實(shí)踐

    緩存是最直接有效提升系統(tǒng)性能的手段之一。個(gè)人認(rèn)為用好用對(duì)緩存是優(yōu)秀程序員的必備基本素質(zhì)。本文結(jié)合實(shí)際開(kāi)發(fā)經(jīng)驗(yàn),從簡(jiǎn)單概念原理和代碼入手,一步一步搭建一個(gè)簡(jiǎn)單的二級(jí)緩存系統(tǒng)。 1、緩存基礎(chǔ)算法 FIFO(First In First Out) ,先進(jìn)先出,和OS里的FIFO思路相同,如

    2024年02月13日
    瀏覽(41)
  • Spring Boot系統(tǒng)之高可用限流實(shí)現(xiàn)解決方案

    Spring Boot系統(tǒng)之高可用限流實(shí)現(xiàn)解決方案

    1.什么是限流 限流是對(duì)某一時(shí)間窗口內(nèi)的請(qǐng)求數(shù)進(jìn)行限制,保持系統(tǒng)的可用性和穩(wěn)定性,防止因流量暴增而導(dǎo)致的系統(tǒng)運(yùn)行緩慢或宕機(jī)。 為什么需要限流 其實(shí)限流思想在生活中隨處可見(jiàn),例如景區(qū)限流,防止人滿(mǎn)為患。熱門(mén)餐飲需要排隊(duì)就餐等?;氐交ヂ?lián)網(wǎng)網(wǎng)絡(luò)上,同樣也

    2024年02月11日
    瀏覽(19)
  • Spring Boot 緩存 Cache 入門(mén)

    Spring Boot 緩存 Cache 入門(mén)

    在系統(tǒng)訪(fǎng)問(wèn)量越來(lái)越大之后,往往最先出現(xiàn)瓶頸的往往是數(shù)據(jù)庫(kù)。而為了減少數(shù)據(jù)庫(kù)的壓力, 我們可以選擇讓產(chǎn)品砍掉消耗數(shù)據(jù)庫(kù)性能的需求 。 當(dāng)然也可以引入緩存,在引入緩存之后,我們的讀操作的代碼,往往代碼如下: 這段代碼,是比較常用的緩存策略,俗稱(chēng)**“被動(dòng)寫(xiě)

    2024年02月15日
    瀏覽(23)
  • Spring Boot整合canal實(shí)現(xiàn)數(shù)據(jù)一致性解決方案解析-部署+實(shí)戰(zhàn)

    Spring Boot整合canal實(shí)現(xiàn)數(shù)據(jù)一致性解決方案解析-部署+實(shí)戰(zhàn)

    ??? 個(gè)人主頁(yè) :牽著貓散步的鼠鼠? ??? 系列專(zhuān)欄 :Java全棧-專(zhuān)欄 ??? 個(gè)人學(xué)習(xí)筆記,若有缺誤,歡迎評(píng)論區(qū)指正 ? 1.前言 2.canal部署安裝 3.Spring Boot整合canal 3.1數(shù)據(jù)庫(kù)與緩存一致性問(wèn)題概述 3.2 整合canel 4.總結(jié) canal [k?\\\'n?l] ?,譯意為水道/管道/溝渠,主要用途是 基于

    2024年03月19日
    瀏覽(23)
  • 【Spring Boot】緩存預(yù)熱與緩存清除--原理、作用和目的

    在本文中,我們將詳細(xì)講解兩個(gè)與緩存相關(guān)的重要概念: 緩存預(yù)熱 和 緩存清除 。 我們將了解緩存的基本概念,然后分別介紹緩存預(yù)熱和緩存清除的原理、作用和目的。 緩存是一種數(shù)據(jù)存儲(chǔ)技術(shù),用于存儲(chǔ)經(jīng)常訪(fǎng)問(wèn)的數(shù)據(jù),以便在需要時(shí)快速獲取 。通過(guò)緩存數(shù)據(jù),可以 減

    2023年04月21日
    瀏覽(23)
  • 如何在Spring Boot中使用EhCache緩存

    如何在Spring Boot中使用EhCache緩存

    在查詢(xún)數(shù)據(jù)的時(shí)候,數(shù)據(jù)大多來(lái)自于數(shù)據(jù)庫(kù),我們會(huì)基于SQL語(yǔ)句與數(shù)據(jù)庫(kù)交互,數(shù)據(jù)庫(kù)一般會(huì)基于本地磁盤(pán)IO將數(shù)據(jù)讀取到內(nèi)存,返回給Java服務(wù)端,我們?cè)賹?shù)據(jù)響應(yīng)給前端,做數(shù)據(jù)展示。 但是MySQL這種關(guān)系型數(shù)據(jù)庫(kù)查詢(xún)數(shù)據(jù)相對(duì)比較慢,因?yàn)橛写疟P(pán)IO,或者是全盤(pán)掃描的風(fēng)

    2024年02月01日
    瀏覽(15)
  • React.js前端 + Spring Boot后端員工管理

    該項(xiàng)目是一個(gè)員工管理系統(tǒng),前端使用 React.js 構(gòu)建,后端使用 Spring Boot 和 Data JPA 和 Lombok 構(gòu)建。它提供了有效管理員工信息的全面解決方案。 特征 響應(yīng)式設(shè)計(jì):響應(yīng)式 UI 設(shè)計(jì),確??绺鞣N設(shè)備的可用性。 數(shù)據(jù)驗(yàn)證:驗(yàn)證用戶(hù)輸入以確保數(shù)據(jù)完整性。 使用的技術(shù) 前端:R

    2024年04月28日
    瀏覽(25)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包