《后端程序猿 · Caffeine 本地缓存》

📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗
🌻 CSDN入驻一周,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数,如需交流,欢迎留言评论。👍

文章目录

    • 写在前面的话
    • 技术统括
      • 技术简介
      • 选型比较
    • 实战运用
      • 快速入门
      • Bean和Util
      • SpringCache 模式
    • 技术拓展
      • 配置属性
      • 清除/驱逐策略
      • 过期/更新策略
      • 填充策略
      • 移除监听
      • 写入/删除监听
      • 统计信息
    • 总结陈词

写在前面的话

笔者所在公司的框架采用 Redis 作为缓存中间件,在部分场景下,可以借用 Redis 实现增强接口性能、减轻数据库压力、充当持久存储等功能。 但程序访问 Redis 毕竟需要消耗网络带宽,此外,经常由于各种因素导致 Redis 的性能降低,诸如编码不当、键过多、 网络异常等。 鉴于此,公司框架基于 Google 开发的高性能的 Java 缓存库 Caffeine,封装了本地缓存工具,便于业务项目使用。由于目前 Redis 已广泛使用,框架层面并未将本地缓存与 @Cacheable 等注解绑定,而是基于按需使用的原则,以注入 Bean 的形式封装工具方法


技术统括

技术简介

【Caffeine 技术简介】
Caffeine 是一个高性能的 Java 本地缓存库,提供了强大的缓存功能和灵活的配置选项,你可以使用 Caffeine 来实现本地缓存,并根据具体的需求进行配置和使用。
Caffeine 是基于 Java8 的高性能本地缓存库,并且在 Spring5 (SpringBoot 2.x) 后,Spring 官方放弃了 Guava,而使用了性能更优秀的 Caffeine 作为默认缓存组件。
Caffeine 是在 Guava Cache 的基础上做一层封装,性能有明显提高,二者同属于内存级本地缓存,从并发的角度来讲,Caffeine明显优于Guava,原因是使用了Java 8最新的StampedLock锁技术。

据说,比 Guava Cache 优秀,那既然 Guava 还没开始用,那就直接它吧。
Maven依赖都不需要单独引入,SB2.x自动引入了,爽。

【Caffeine 优势特性】
Caffeine提供灵活的结构来创建缓存,并且有以下特性:
自动加载条目到缓存中,可选异步方式
可以基于大小剔除
可以设置过期时间,时间可以从上次访问或上次写入开始计算
异步刷新
keys自动包装在弱引用中
values自动包装在弱引用或软引用中
条目剔除通知
缓存访问统计

【Caffeine 使用场景】
Caffeine 是一个高性能的 Java 本地缓存库,适用于各种日常开发场景。
以下是一些 Caffeine 在日常开发中适合做的事情:
缓存常用数据:使用 Caffeine 缓存常用的数据,例如配置信息、用户信息、系统参数等,可以提高数据的访问速度和系统的性能。
减轻数据库压力:将频繁访问的数据库查询结果缓存到 Caffeine 中,可以减轻数据库的压力,提高系统的并发处理能力。
缓存计算结果:使用 Caffeine 缓存计算结果,例如复杂查询结果、数据聚合结果等,可以避免重复计算,提高系统的响应速度。
实现数据预热:在系统启动时将一些常用的数据预先加载到 Caffeine 缓存中,可以提高系统的初始化速度和响应速度。
实现请求限流:使用 Caffeine 缓存来记录请求次数和频率,实现请求的限流和流量控制,保护系统的稳定性和可用性。
实现本地锁:利用 Caffeine 缓存的原子性操作特性,可以实现分布式锁的简单版本,用于控制并发访问。
缓存控制器结果:在 Spring MVC 或 Spring Boot 应用中,可以使用 Caffeine 缓存控制器方法的返回结果,减少方法的执行次数,提高系统的性能和吞吐量。
总的来说,Caffeine 是一个功能强大、性能优越的本地缓存库,适用于各种日常开发场景,可以提高系统的性能、稳定性和可维护性。

【 补充:Guava LoadingCache 适合存储那些满足以下条件的数据】
频繁访问的数据:LoadingCache 提供了高性能的数据读取和写入,适合缓存那些被频繁访问的数据。这些数据可能是热点数据,经常被应用程序读取,但不经常更新。
计算密集型或者昂贵的数据:LoadingCache 可以在缓存中存储一些计算密集型或者昂贵的数据,例如数据库查询结果、API 调用结果等。这样可以避免重复计算或者昂贵的网络请求,提高系统的性能和响应速度。
临时性的数据:LoadingCache 也适合存储一些临时性的数据,例如会话数据、用户权限信息等。这些数据可能在一段时间内频繁被访问,但是不需要长期保存。
不需要持久化的数据:LoadingCache 是一个本地缓存,不具备持久化存储的能力。因此适合存储一些不需要长期保存的数据,例如缓存数据源的数据、临时计算结果等。
需要自动加载和刷新的数据:LoadingCache 支持自动加载和刷新数据,可以通过设置 refreshAfterWrite 来定期刷新缓存数据,以保持数据的新鲜性。因此适合存储那些需要定期刷新的数据,例如缓存数据源的数据、动态配置信息等。
总的来说,LoadingCache 适合存储那些被频繁访问、不需要持久化存储、临时性的数据,以及那些需要自动加载和刷新的数据。通过合理使用 LoadingCache,可以提高系统的性能、减少资源消耗,同时提供更好的用户体验。


选型比较

【Caffeine 和 GuavaCache 差异】
剔除算法方面,GuavaCache采用的是「LRU」算法,而Caffeine采用的是「Window TinyLFU」算法,这是两者之间最大,也是根本的区别。
立即失效方面,Guava会把立即失效 (例如:expireAfterAccess(0) and expireAfterWrite(0)) 转成设置最大Size为0。这就会导致剔除提醒的原因是SIZE而不是EXPIRED。Caffiene能正确识别这种剔除原因。
取代提醒方面,Guava只要数据被替换,不管什么原因,都会触发剔除监听器。而Caffiene在取代值和先前值的引用完全一样时不会触发监听器。
异步化方方面,Caffiene的很多工作都是交给线程池去做的(默认:ForkJoinPool.commonPool()),例如:剔除监听器,刷新机制,维护工作等。

【Caffeine 和 Redis 区别】
本地缓存与分布式缓存对应,缓存进程和应用进程同属于一个JVM,数据的读、写在一个进程内完成。本地缓存没有网络开销,访问速度很快。
从横向对常用的缓存进行对比,有助于加深对缓存的理解,有助于提高技术选型的合理性。下面对比三种常用缓存:Redis、EhCache、Caffeine。
image.png

通常采用 Caffeine/Guava + Redis 实现二级缓存方案,先从本地拿,拿不到再从缓存获取,减少 Redis 的连接消耗。

【Caffeine 有什么用,为什么不直接用Map】
**解答1:**Caffeine 使用了 ConcurrentHashMap 作为其缓存数据结构的基础,但对其进行了一些优化和改进,以提高并发性能、减少内存消耗,并添加了一些额外的功能和特性,使其更适合于高性能的缓存应用场景。
ConcurrentHashMap 是 Java 标准库中提供的线程安全的哈希表实现,它使用了一种分段锁的方式来实现并发访问控制,以提高并发读写性能。Caffeine 利用了 ConcurrentHashMap 的并发性能和线程安全性,并在此基础上进行了优化和改进,以提供更高性能的缓存服务。
总的来说,尽管 Caffeine 的底层实现基于 ConcurrentHashMap,但它对 ConcurrentHashMap 进行了一些改进和扩展,使得它更适合于高性能、低延迟的缓存应用场景。
**解答2:**Caffeine 是一个用于构建内存缓存的 Java 库,它提供了一些高效、可配置的缓存功能,可以帮助开发人员在应用程序中轻松地实现缓存机制。
与直接使用 Java 中的 Map 不同,Caffeine 提供了更多的特性和优势,使得它在某些场景下更为适用:
自动加载和刷新机制:Caffeine 支持自动加载和刷新缓存中的条目,无需手动编写加载逻辑。通过 LoadingCache 接口,可以在缓存中不存在指定键的条目时,自动调用加载逻辑来获取新的值,并将其放入缓存中。
缓存的自动清理和过期处理:Caffeine 提供了可配置的过期策略,可以根据时间、大小或其他条件来自动清理缓存中的条目。这样可以确保缓存不会占用过多的内存,并及时清理过期的条目,保持缓存的有效性和性能。
高性能和低内存占用:Caffeine 的实现经过优化,具有很高的性能和低的内存占用。它使用了一些高效的数据结构和算法,以及基于并发的设计模式,可以在多线程环境下高效地处理并发访问和更新操作。
可扩展性和灵活性:Caffeine 提供了丰富的配置选项和扩展点,可以根据具体的需求和场景来定制缓存的行为。开发人员可以灵活地配置缓存的大小、过期时间、刷新策略等参数,以满足不同应用场景的需求。
总的来说,尽管 Java 中的 Map 提供了基本的键值对存储功能,但在需要更多高级特性和性能优化的场景下,使用 Caffeine 可能会更加合适和方便。Caffeine 提供了更丰富的功能和更高效的实现,可以帮助开发人员构建出更可靠、更高性能的缓存系统。


实战运用

快速入门

Step1、添加Maven依赖

注意,高版本Spring或SB以及依赖了caffeine,直接使用提供的版本即可,不要再额外引入了。

<dependency><groupId>com.github.ben-manes.caffeine</groupId><artifactId>caffeine</artifactId><version>3.1.8</version>
</dependency>

Step2、编写工具Bean

@Component
public class CaffeineCache {private final Cache<String, Object> cache;public CaffeineCache() {// 创建一个基于 Caffeine 的本地缓存,设置最大缓存条目数为 10000,过期时间为 10 分钟cache = Caffeine.newBuilder().maximumSize(10000).expireAfterWrite(10, TimeUnit.MINUTES).build();}// 添加缓存项public void put(String key, Object value) {cache.put(key, value);}// 获取缓存项public Object get(String key) {return cache.getIfPresent(key);}// 移除缓存项public void remove(String key) {cache.invalidate(key);}// 清空缓存public void clear() {cache.invalidateAll();}
}

Step3、使用测试

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class MyService {@Autowiredprivate CaffeineCache caffeineCache;public void doSomething() {// 添加缓存项caffeineCache.put("key", "value");// 获取缓存项Object value = caffeineCache.get("key");// 移除缓存项caffeineCache.remove("key");// 清空缓存caffeineCache.clear();}
}

通过以上步骤,你就可以在 Spring Boot 应用中使用 Caffeine 工具类来创建本地缓存,并在需要时进行缓存操作。你可以根据具体的需求调整缓存的配置参数,例如最大缓存条目数、过期时间等。

Bean和Util

将 Caffeine 缓存工具类设计为 Bean 是比较常见的做法,这样可以更好地与 Spring Boot 集成,并通过依赖注入的方式在需要的地方直接使用,同时也方便在配置类中对其进行配置和管理。
将 Caffeine 缓存工具类设计为 Bean 的优势包括:
便于管理和配置:作为 Spring Bean,可以利用 Spring 的依赖注入和配置功能,更方便地管理和配置 Caffeine 缓存的属性,如最大缓存条目数、过期时间等。
与 Spring Boot 集成更紧密:作为 Spring Bean,与 Spring Boot 的集成更加紧密,可以直接在其他 Bean 中通过自动装配进行使用,而不需要额外的配置。
易于测试:将 Caffeine 缓存工具类设计为 Bean 后,可以更方便地在单元测试中进行模拟和替换,提高测试的可维护性和灵活性。
因此,建议将 Caffeine 缓存工具类设计为 Spring Bean,以便更好地利用 Spring Boot 的特性和功能,并方便在应用程序中使用和管理。


SpringCache 模式

与SB整合通常体现在@Cacheable,有需要再扩展。
公司框架Redis使用已久,为减少影响,还是封装工具Bean,按需使用。


技术拓展

配置属性

initialCapacity 初始的缓存空间大小
maximumSize 缓存的最大条数
maximumWeight 缓存的最大权重
expireAfterAccess 最后一次写入或访问后,经过固定时间过期
expireAfterWrite 最后一次写入后,经过固定时间过期
refreshAfterWrite 写入后,经过固定时间过期,下次访问返回旧值并触发刷新
weakKeys 打开 key 的弱引用
weakValues 打开 value 的弱引用
softValues 打开 value 的软引用
recordStats 缓存使用统计
expireAfterWrite 和 expireAfterAccess 同时存在时,以 expireAfterWrite 为准。
weakValues 和 softValues 不可以同时使用。
maximumSize 和 maximumWeight 不可以同时使用。

清除/驱逐策略

缓存的驱逐策略是为了预测哪些数据在短期内最可能被再次用到,从而提升缓存的命中率。LRU策略或许是最流行的驱逐策略。但LRU通过历史数据来预测未来是局限的,它会认为最后到来的数据是最可能被再次访问的,从而给予它最高的优先级。
Caffeine提供三类驱逐策略:基于大小(size-based),基于时间(time-based)和基于引用(reference-based)

1、基于大小(size-based)
基于大小驱逐,有两种方式:一种是基于缓存大小,一种是基于权重。

// 根据缓存的计数进行驱逐
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder().maximumSize(10_000).build(key -> createExpensiveGraph(key));// 根据缓存的权重来进行驱逐(权重只是用于确定缓存大小,不会用于决定该缓存是否被驱逐)
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder().maximumWeight(10_000).weigher((Key key, Graph graph) -> graph.vertices().size()).build(key -> createExpensiveGraph(key));

2、基于时间:设置缓存的有效时间

// 设置缓存有效期为 10 秒,从最后一次写入开始计时 
Cache<String, String> cache = Caffeine.newBuilder().expireAfterWrite(Duration.ofSeconds(10)) .build();

3、基于引用:设置缓存为软引用或弱引用,利用GC来回收缓存数据。

// 性能较差,不建议使用。
Cache<String, String> cache = Caffeine.newBuilder().weakKeys().weakValues().build();

【弱引用相关补充】

Caffeine.weakKeys() 使用弱引用存储key。如果没有强引用这个key,则GC时允许回收该条目
Caffeine.weakValues() 使用弱引用存储value。如果没有强引用这个value,则GC时允许回收该条目
Caffeine.softValues() 使用软引用存储value, 如果没有强引用这个value,则GC内存不足时允许回收该条目

image.png


过期/更新策略

# expireAfterAccess:设置条目在最后一次访问后的过期时间。默认值为不过期。
# expireAfterWrite:设置条目在被创建或最后一次写入后的过期时间。默认值为不过期。
# refreshAfterWrite:这个其实算更新策略,设置条目在被创建或最后一次写入后的自动刷新时间。默认值为不自动刷新。
# expireAfter:
# 在expireAfter中需要自己实现Expiry接口,这个接口支持create,update,access了之后多久过期,
# 这里和前面两个API不同的是,需要你告诉缓存框架,他应该在具体的某个时间过期
# 也就是通过前面的重写create,update,access的方法,获取具体的过期时间。
Cache<String, String> cacheHandle = Caffeine.newBuilder().expireAfter(new Expiry<String, String>() {// 创建后多久过期@Overridepublic long expireAfterCreate(@NonNull String key, @NonNull String value, long currentTime) {return TimeUnit.SECONDS.toNanos(3); //3秒后过期}// 更新后多久过期@Overridepublic long expireAfterUpdate(@NonNull String key, @NonNull String value, long currentTime, @NonNegative long currentDuration) {return currentDuration; // 保持不变,即不改变过期时间}// 读取后多久过期@Overridepublic long expireAfterRead(@NonNull String key, @NonNull String value, long currentTime, @NonNegative long currentDuration) {return currentDuration; // 保持不变,即不改变过期时间}}).build();
cacheHandle.put("abc", "123");
System.out.println("abc的值:" + cacheHandle.getIfPresent("abc"));
ThreadUtil.sleep(5000);
System.out.println("abc的值:" + cacheHandle.getIfPresent("abc"));

填充策略

Caffeine 提供了四种缓存添加策略:手动加载,自动加载,手动异步加载和自动异步加载。
很好理解,其实就是build的几个重载模式。
参考:Caffeine Cache 进程缓存利器


移除监听

RemovalListener:如果我们需要在缓存被移除的时候,得到通知产生回调,并做一些额外处理工作。

Cache<String, String> cache = Caffeine.newBuilder().maximumSize(2).removalListener(((key, value, cause) -> {System.out.println("Removed key: " + key + ", value: " + value + ", cause: " + cause);})).build();
cache.put("key1", "value1");
cache.put("key2", "value22");
cache.put("key3", "value333");
ThreadUtil.sleep(1000);
System.out.println(cache.asMap());//下方是输出信息:
Removed key: key1, value: value1, cause: SIZE
{key2=value22, key3=value333}

写入/删除监听

@Autowired
private OnelinkCaffeineCacheHandle caffeineCache;Caffeine<Object, Object> customBuild = caffeineCache.getCustomBuild();
customBuild.writer(new CacheWriter<String, String>() {@Overridepublic void write(String key, String value) {System.out.println("Cache entry written for key: " + key + ", value: " + value);}@Overridepublic void delete(String key, String value, RemovalCause cause) {System.out.println("Cache entry removed for key: " + key + ", value: " + value + ", removal cause: " + cause);}
});

统计信息

【关于 CacheStats】
Guava 的 CacheStats 类是用来表示缓存的统计信息的。它提供了一组方法来获取缓存的命中率、加载次数、加载失败次数等信息。通过这些统计信息,可以帮助你了解缓存的使用情况,优化缓存的配置和性能。
以下是 CacheStats 类的一些常用方法:
hitCount():返回缓存命中的次数。
missCount():返回缓存未命中的次数。
loadSuccessCount():返回缓存加载成功的次数。
loadExceptionCount():返回缓存加载失败的次数。
totalLoadTime():返回缓存加载的总时间,单位为纳秒。
evictionCount():返回缓存中条目被回收的次数。
使用 CacheStats 类可以帮助你监控缓存的性能,并且根据统计信息来调整缓存的配置,以提高系统的性能和稳定性。

【示例代码】

Tips:for循环中大量使用才有统计的意义,正常生产环境也没必要记录。

public static void main(String[] args) {Cache<String, String> cache = Caffeine.newBuilder().maximumSize(2).recordStats().removalListener(((key, value, cause) -> {System.out.println("Removed key: " + key + ", value: " + value + ", cause: " + cause);})).build();// 添加一些条目cache.put("key1", "value1");cache.put("key2", "value22");cache.put("key3", "value333");ThreadUtil.sleep(1000);// 此时缓存大小超过最大权重,将会驱逐一些条目System.out.println(cache.asMap());System.out.println(cache.stats());//输出信息如下:// Removed key: key1, value: value1, cause: SIZE// {key2=value22, key3=value333}// CacheStats{hitCount=0, missCount=0, loadSuccessCount=0, loadFailureCount=0, totalLoadTime=0, evictionCount=1, evictionWeight=1}// hitCount(): 返回命中缓存的总数// evictionCount():缓存逐出的数量
}

总结陈词

上文介绍了本地缓存的用法,仅供参考。
本地缓存具备其独有美丽,可以搭配Redis发挥更多作用。
但切记缓存都是一个双刃剑,用的姿势如果不对,会造成更严重的后果。

💗 后续会逐步分享企业实际开发中的实战经验,有需要交流的可以联系博主。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/369560.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

满足GMSL静电防护要求的方案

什么是GMSL&#xff1f;它是做什么用的&#xff1f;它有什么优点&#xff1f;设计GMSL防静电有啥难度&#xff1f; 带着这些疑问我们先了解下什么是GMSL。 一&#xff0e;简述 GMSL GMSL&#xff08;Gigabit Multimedia Serial Link&#xff09;即千兆多媒体串行链路&#xf…

MySQL中的DDL语句

第一题 输入密码登录mysql&#xff0c;创建数据库zoo&#xff0c;转换到zoo数据库&#xff0c; mysql> create database zoo character set gbk; mysql> use zoo查看创建数据库zoo信息 mysql> show create database zoo;删除数据库zoo mysql> drop database zo…

TP8/6 更改后台入口地址admin改为myadmin 隐藏真实后台网址

原来www.xxx.com/admin 改后www.xxx.com/myadmin config/app.php // 应用映射&#xff08;自动多应用模式有效&#xff09;app_map > [admintest>admin], 官方文档&#xff1a;ThinkPHP官方手册

在C#/Net中使用Mqtt

net中MQTT的应用场景 c#常用来开发上位机程序&#xff0c;或者其他一些跟设备打交道比较多的系统&#xff0c;所以会经常作为拥有数据的终端&#xff0c;可以用来采集上传数据&#xff0c;而MQTT也是物联网常用的协议&#xff0c;所以下面介绍在C#开发中使用MQTT。 安装MQTTn…

TK养号工具开发会用上的源代码科普!

在当今数字化时代&#xff0c;社交媒体平台的崛起使得网络账号的维护与管理变得日益重要&#xff0c;其中&#xff0c;TK作为一款备受欢迎的社交媒体平台&#xff0c;吸引了大量用户。 在TK上进行账号养护&#xff0c;即通过各种方式提升账号权重、增加曝光量&#xff0c;已成…

小阿轩yx-LVS+Keepalived群集

小阿轩yx-LVSKeepalived群集 Keepalived 双机热备份基础知识 起初是专门针对 LVS 设计的一款强大的辅助工具主要用来提供故障切换(Failover)和健康检査(HealthChecking)功能—判断LVS 负载调度器、节点服务器的可用性当 master 主机出现故障及时切换到backup 节点保证业务正常…

LeetCode-刷题记录-滑动窗口合集(本篇blog会持续更新哦~)

一、滑动窗口概述 滑动窗口&#xff08;Sliding Window&#xff09;是一种用于解决数组&#xff08;或字符串&#xff09;中子数组&#xff08;或子串&#xff09;问题的有效算法。 Sliding Window核心思想&#xff1a; 滑动窗口技术的基本思想是维护一个窗口&#xff08;一般…

odoo 物联网 设备数据采集方案

图一 架构手稿(许老师专属) 图二 架构简图 部署 方案一&#xff1a; odoo业务数据库与设备采集数据库使用一个instance。 缺点&#xff1a;重启pg服务相互影响。 方案二&#xff1a; odoo业务数据库与设备采集数据库独立部署&#xff0c;使用两个instance。 优点&#xff1a;…

简单的git pull fail Can‘t update has no tracked branch解决记录

简单的git pull fail Can‘t update has no tracked branch解决记录 1. 问题描述 上午同事使用idea拉取代码的时候&#xff0c;发现拉取不了&#xff0c;提示用户权限问题&#xff0c;之后修改了git用户信息&#xff0c;发现还是拉取不了分支代码&#xff0c;然后删除了git r…

Java基础:爬虫

1.本地爬虫 Pattern:表示正则表达式 Matcher:文本匹配器&#xff0c;作用按照正则表达式的规则去读取字符串&#xff0c;从头开始读取。在大串中去找符合匹配规则的子串。 1.2.获取Pattern对象 通过Pattern p Pattern.compile("正则表达式");获得 1.3.…

Spire.PDF for .NET【文档操作】演示:以特定的缩放比例/百分比打开 PDF 文件

有时&#xff0c;我们可能需要在显示 PDF 文件时更改缩放比例以满足我们的要求。在本文中&#xff0c;我们将演示如何使用 Spire.PDF for .NET 以特定的缩放比例/百分比&#xff08;例如默认值、100% 或任何其他所需的缩放比例&#xff09;打开 PDF 文件。 Spire.PDF for .NET…

一种频偏估计与补偿方法

一种简易的频偏估计补偿方法&#xff0c;使用QAM等信号。估计精度受FFT长度限制&#xff0c;可以作为粗频偏估计。 Nfft 1024; % FFT长度 N 10*Nfft; % 仿真符号数 M 16; % 调制QAM16 freq 1e…

【SpringBoot3学习 | 第2篇】SpringBoot3整合+SpringBoot3项目打包运行

文章目录 一. SpringBoot3 整合 SpringMVC1.1 配置静态资源位置1.2 自定义拦截器&#xff08;SpringMVC配置&#xff09; 二. SpringBoot3 整合 Druid 数据源三. SpringBoot3 整合 Mybatis3.1 Mybatis整合3.2 声明式事务整合配置3.3 AOP整合配置 四. SpringBoot3 项目打包和运行…

三万字带你一遍跑通uer

三万字带你一遍跑通uer 参考文档 今天给大家介绍个非常强大的项目uer&#xff0c;集成了许多可以做自然语言的东西&#xff0c;效果的话也非常好&#xff0c;很适合企业级的应用&#xff01; 1. 先将项目uer从github拉取下来&#xff08;zip或git都ok&#xff09; 2. 用pycha…

Qt项目:基于Qt实现的网络聊天室---注册模块

文章目录 基本页面设计创建登录界面创建注册界面优化样式完善注册类界面 客户端逻辑完善客户端增加post逻辑客户端配置管理 邮箱注册服务认证服务读取配置邮箱验证服务联调设置验证码过期封装redis操作类封装redis连接池注册功能Server端接受注册请求封装mysql连接池封装DAO操作…

【CV炼丹师勇闯力扣训练营 Day24:§7 回溯3】

CV炼丹师勇闯力扣训练营 代码随想录算法训练营第24天 93 复原IP地址 有效 IP 地址 正好由四个整数&#xff08;每个整数位于 0 到 255 之间组成&#xff0c;且不能含有前导 0&#xff09;&#xff0c;整数之间用 ‘.’ 分隔。 例如&#xff1a;“0.1.2.201” 和 “192.168.…

智慧校园变革之路:资产标签设置功能的关键应用

在智慧校园的资产管理实践中&#xff0c;资产标签设置扮演着桥梁角色&#xff0c;将实体资产与数字化信息紧密相连&#xff0c;极大地提升了管理的效率与精确度。这项功能的核心在于&#xff0c;为校园内的每一项固定资产配备独一无二的标识——可能是传统的条形码、二维码&…

适合金融行业的国产传输软件应该是怎样的?

对于金融行业来说&#xff0c;正常业务开展离不开文件传输场景&#xff0c;一般来说&#xff0c;金融行业常用的文件传输工具有IM通讯、邮件、自建文件传输系统、FTP应用、U盘等&#xff0c;这些传输工具可以基础实现金融机构的文件传输需求&#xff0c;但也存在如下问题&#…

科普文:一文搞懂nginx原理和实战

1. Nginx简介与核心架构 1.1 Nginx简介 Nginx (engine x) 是一个高性能的 HTTP 和反向代理服务器&#xff0c;也是一个 IMAP/POP3/SMTP 邮件代理服务器。 由 Igor Sysoev 于2004年首次发布&#xff0c;其设计目标是解决 C10K 问题&#xff0c;即在一台服务器上同时处理一万个并…

2024年7月6日 十二生肖 今日运势

小运播报&#xff1a;2024年7月6日&#xff0c;星期六&#xff0c;农历六月初一 &#xff08;甲辰年庚午月辛未日&#xff09;&#xff0c;法定节假日。 红榜生肖&#xff1a;猪、马、兔 需要注意&#xff1a;狗、鼠、牛 喜神方位&#xff1a;西南方 财神方位&#xff1a;正…