当前位置: 首页 > news >正文

橘子学Mybatis07之Mybatis关于缓存的设计

很逆天的一件事是,我上一次发mybatis是在2022年10月15号,然后直到今天才开始总结下一篇Mybatis的东西。一年里面忙成那啥了,而且重心都投入在了Elasticsearch的学习上面,基本一年下来都在搞ES,并且考下了ECE认证,后续如果有时间,一直想写一些es学习的总结,分享一下。
现在貌似又要开始往管理岗位上面凑热闹了,以后可能会有多的时间来总结之前的一些学习了,这个不知道是好事还是坏事,这里就当抱怨抱怨。哈哈。

一、缓存的意义

话不多说,我们来看Mybatis中的缓存,我们之前说过缓存,那还是在2022年的时候,我们知道mybatis作为ORM框架,他的核心任务就是和数据库打交道。
我们又知道你和数据库打交道我们不说各家数据库对于文件系统的实现是不是自身自带缓存,他总归是要和磁盘打交道的,涉及到很重的磁盘IO操作(别抬杠,别和我说硬件的进化,我说的是相对很重)。
而我们面对这种一般就是在业务设计的时候都会想到缓存,是的常见的就是Redis缓存,我们会把数据库(磁盘中)的一部分数据预先加载在缓存中,而缓存是内存角度的操作,在内存中操作数据是很轻量级的。以后我们每次读数据库的时候就在缓存里面放一份,下次再读的时候就直接走缓存了,那么是不是就能提高请求的响应,提高业务的吞吐。
缓存中的数据在修改的时候也不需要直接就刷回磁盘,我们可以在一定时间频率内进行数据的写磁盘,这样对于你系统的吞吐也是很有提升的,当然前提是你能容忍一定的数据丢失问题。这些大概就是缓存的意义,但是实现起来却并不容易,数据的一致性,数据的持久化,缓存的大小导致的数据换出,内存中存储的大小,这都是我们在设计的时候需要考虑的,如果你想知道一些扩展的东西,可以去看redis的实现。这里不多展开说了。

既然知道了缓存的大致意义,他可以做到减少和磁盘IO的交互,转为和内存的交互,这样就能减少我们的性能开支。那么mybatis是和数据库打交道的,那么他是不是可以加入关于缓存的设计呢,答案是可以,他确实这么设计了一套接口API,并且以接口的形式暴露出来,方面我们自己进行扩展,你可以很方便的就扩展为你们自己的redis架构。

二、Mybatis中缓存的设计

mybatis中缓存是设计为接口的形式,方便后面的扩展和实现。现在我们就来看一下这个扩展接口。
这个接口的位置是org.apache.ibatis.cache.Cache类,我们可以看到他是ibatis包中的一个接口。
这个接口有诸多的方法,我们可以借助idea的ctrl+F12组合键来看一下。
在这里插入图片描述
我们看到他作为缓存的顶层接口,实际上就约定了缓存操作的一些基础操作,看了一下也其实就那么回事吧。无外乎就是怎么把数据放入缓存(putObject),怎么把数据从缓存里面取出来(getObject),怎么把数据从缓存中移除出去(removeObject),怎么清除缓存(clear),其他的基本也是围绕这几个操作展开的一些更加细化的操作,我们说其实不用看他这个代码也能想到他就是这么些个功能。
原谅我这里再次吐槽一下,mybatis的源码注释,真的少。我的建议是要不干脆别加了。

这里需要额外说一件事就是那个getReadWriteLock这个方法,看着意思是获取读写锁,但是我们看一下源码:

/*** 从3.2.6开始,mybatis已经移除了这个方法,所以其实他不重要。* Optional. As of 3.2.6 this method is no longer called by the core.* * 以后的锁需要由提供缓存的人来维护这个并发安全,所以如果你怕麻烦,那我推荐你使用redis,服务端写入单线程,没有这个苦恼,我们一直都用它。* Any locking needed by the cache must be provided internally by the cache provider.** @return A ReadWriteLock*/default ReadWriteLock getReadWriteLock() {return null;}

那按照我们对于缓存的理解,自然你往缓存里面放数据的时候,就要指定数据的key,方便我们后面去根据这个key去取,自然putObject的参数就有两个,一个是标识key,一个是缓存的数据。
那我们取数据的时候自然就是根据这个标识去取,自然getObject的参数就是那个key.
移除数据和获取数据其实是一样的,都是找到这个数据。这个其实就类似于map,而缓存实际上也就是map的那个意思,可以一起理解一下。
clear不说了,属于AOE大招,直接全删,自然也不需要区分什么谁是谁,不要参数,直接全干掉。
至此我们是对于这个缓存有个大概的理解了。下面我们就来实际操作一下,我们看看咋用。亲爱的。

三、先让你来设计一下缓存

既然mybatis这么贴心为我们设计了缓存接口,我们只需要实现一下就能实现缓存功能。那你不试一把,实在是对不起远在大洋彼岸的那些大佬们(或者你用plus,那就稍微对得起他们了)。
来吧,我们来试试。试试就逝逝。

3.1、实现接口

第一步、我们先定义一个org.apache.ibatis.cache.Cache接口的接口实现类,就叫他IkunCache吧。

public class IkunCache implements Cache {@Overridepublic String getId() {return null;}@Overridepublic void putObject(Object key, Object value) {}@Overridepublic Object getObject(Object key) {return null;}@Overridepublic Object removeObject(Object key) {return null;}@Overridepublic void clear() {}@Overridepublic int getSize() {return 0;}@Overridepublic ReadWriteLock getReadWriteLock() {return null;}
}

好了,我们现在已经完成了接口实现类的工作了,下一步我们要考虑一下既然是缓存,那么数据到底缓存到哪呢,redis?一上来就开大,不太好吧(实际上我本地没有redis环境)。我们先放在我们的本地内存试试。

3.2、制定存储结构

既然要在本地存,那作为java boy,本地其实就那么几种结构,存那么多缓存数据你高低得是个集合吧,那无外乎就是List,Set,Map这种,list和set不行,我直接否了,因为他们获取数据需要遍历。移除数据也要遍历。我用缓存是为了快,你给我来个遍历,你脑子和我脑子到底谁有问题。
所以我们就把目标定在了Map上,简单点,哥们,直接用HashMap,能通过key直接获取删除,等会你说key,你刚才说了key。还记不记得我们说缓存redis这种的时候,就是Key,我们又说Cache接口里面那些方法的时候也说的是key。好了,HashMap,我宣布,你就是今天的天命之子。
于是我们就要声明一个本地变量,就是HashMap,然后我们不管是写缓存,还是读缓存,还是清空缓存都用这个map就好了,那么代码就进化成为这样。

public class IkunCache implements Cache {// 缓存内容的容器private static Map<Object,Object> ikunCache = new HashMap<>();/**因为整个应用中可能存在多个缓存,比如缓存的redis,本地的,或者按照业务划分缓存的订单的,用户的等等这里可以为你的缓存指定一个名字来区分**/@Overridepublic String getId() {// 我们用缓存类的类名来区分开每个缓存实例,每个缓存类都维护自己的一个map即可,这样就区分开了,简单设计一下,别太纠结return getClass().getName();}@Overridepublic void putObject(Object key, Object value) {// 把数据放入缓存ikunCache.put(key,value);}@Overridepublic Object getObject(Object key) {// 从缓存中获取数据return ikunCache.get(key);}@Overridepublic Object removeObject(Object key) {// 从缓存中移除数据return ikunCache.remove(key);}@Overridepublic void clear() {// 开大招,清空缓存ikunCache.clear();}@Overridepublic int getSize() {// 获取缓存的长度return ikunCache.size();}@Overridepublic ReadWriteLock getReadWriteLock() {// 移除了return null;}
}

那现在是不是你就实现了这个缓存接口了,你就能用了。至于你是不是还有其他的实现类,那可以制定多个实现类。你自己多实现几个试试,你可以给你的map整个过期时间等等,或者换成别的容器,到时候用那个看你指定哪个就好。或者你直接换成redis,全部放redis里面,把你的k-v序列化好就行。
原则就是能用就行,毕竟我们的路线是,完成,完善,完美,完蛋。
这是我们的简单实现,那么mybatis实际上提供了很多内置的实现方式,也就是他自己有很多实现类,我们就来看一下。

四、Mybatis内置缓存实现

我们看一下Mybatis自己内置的实现类。
在这里插入图片描述
这个图好像被压缩了,我来用文字列出这几个类。

Cache (org.apache.ibatis.cache):这是那个缓存接口SoftCache (org.apache.ibatis.cache.decorators)PerpetualCache (org.apache.ibatis.cache.impl)LoggingCache (org.apache.ibatis.cache.decorators)SynchronizedCache (org.apache.ibatis.cache.decorators)ScheduledCache (org.apache.ibatis.cache.decorators)LruCache (org.apache.ibatis.cache.decorators)IkunCache (com.yx.cache) :这是我们刚才自己实现的,就不说了。WeakCache (org.apache.ibatis.cache.decorators)FifoCache (org.apache.ibatis.cache.decorators)SerializedCache (org.apache.ibatis.cache.decorators)BlockingCache (org.apache.ibatis.cache.decorators)TransactionalCache (org.apache.ibatis.cache.decorators)

我们看到除了我们自己实现的,mybatis自己内置的几个类貌似分为两种。

一种是属于org.apache.ibatis.cache.decorators包下面的,我们说decorators其实翻译一下就是装饰器
装饰器这三个字有没有唤醒你内心的设计模式之魂,所以我们知道这些类都是装饰器门面,
真正工作的其实不在他这里,其核心实际在下面这个PerpetualCache。
那我们说装饰器模式的作用是装饰器为了给你的目标类增强功能。

第二种是属于org.apache.ibatis.cache.impl包下面的,其实这个包下面就一个PerpetualCache。

根据我们对于装饰器的理解,所以其实他的目标类是在PerpetualCache,其余的都是给他增强功能用的,所以我们直接看PerpetualCache就可以了。

4.1、干活的其实是我,目标PerpetualCache登场

我们来看一下PerpetualCache的源码。

public class PerpetualCache implements Cache {private final String id;private final Map<Object, Object> cache = new HashMap<>();public PerpetualCache(String id) {this.id = id;}@Overridepublic String getId() {return id;}@Overridepublic int getSize() {return cache.size();}@Overridepublic void putObject(Object key, Object value) {cache.put(key, value);}@Overridepublic Object getObject(Object key) {return cache.get(key);}@Overridepublic Object removeObject(Object key) {return cache.remove(key);}@Overridepublic void clear() {cache.clear();}@Overridepublic boolean equals(Object o) {if (getId() == null) {throw new CacheException("Cache instances require an ID.");}if (this == o) {return true;}if (!(o instanceof Cache)) {return false;}Cache otherCache = (Cache) o;return getId().equals(otherCache.getId());}@Overridepublic int hashCode() {if (getId() == null) {throw new CacheException("Cache instances require an ID.");}return getId().hashCode();}}

再吐槽一次,你们是真不写注释啊哥,我们看到他除了传入一个id来指定缓存的名字来区分以外,其余的实现也是用了一个HashMap作为缓存容器,除了他重写了equal和hashcode方法,其余的和我们刚才的实现一毛一样。你看看,其实你也是大佬。
但是大佬肯定不能这么粗糙,于是就有了那么多的装饰器,来增强你这个无比粗糙的缓存。

4.2、我来给你加点buff吧,缓存装饰器登场

我们看到了那个缓存干活的类,PerpetualCache,主打一个粗糙,那mybats绝对不会这么low,于是他借助装饰器模式来实现了一组增强功能的装饰器。来看一下。

	LruCache (org.apache.ibatis.cache.decorators)FifoCache (org.apache.ibatis.cache.decorators)SoftCache (org.apache.ibatis.cache.decorators)LoggingCache (org.apache.ibatis.cache.decorators)SynchronizedCache (org.apache.ibatis.cache.decorators)ScheduledCache (org.apache.ibatis.cache.decorators)WeakCache (org.apache.ibatis.cache.decorators)SerializedCache (org.apache.ibatis.cache.decorators)BlockingCache (org.apache.ibatis.cache.decorators)TransactionalCache (org.apache.ibatis.cache.decorators)

你看到了,我把LruCache和FifoCache单独列在了一起,和我一样聪明的你一眼就看懂了,Lru和Fifo其实是一种淘汰机制,在内存页置换的时候学习的时候,你是知道的,我不多说了。算了简单说一下。
LRU:Least Recently Used,最近最少使用,换言之就是最近用的最少的数据,就先淘汰。
FIFO:First In First Out,先进先出,我不管你谁用的多,那么花里花哨没用,谁先进来谁先滚,呆那么长时间干嘛。
以上都是在缓存中的数据超过了限制的时候,再有新的数据进来的时候,需要淘汰掉老的缓存数据的时候设计的策略。可见mybatis是实现了这两种的。
LoggingCache (org.apache.ibatis.cache.decorators):增强日志打印的功能
BlockingCache (org.apache.ibatis.cache.decorators):阻塞增强,保证一时间只有一个线程读写缓存,线程安全得以保证。
ScheduledCache (org.apache.ibatis.cache.decorators):能够定时自动刷新缓存,按照一定的时间定时去清空缓存。你可以在代码设置这个时间间隔。
SerializedCache (org.apache.ibatis.cache.decorators):可以自动帮我们完成k-v的序列化和反序列化,序列化方式就是jdk的Serializedble序列化方式。
TransactionalCache (org.apache.ibatis.cache.decorators):这个装饰器只有在事务操作成功的时候才会写入缓存,你是不是发现这个保证了写入DB和缓存的一致性,不至于事务失败了,缓存写进去了,挺好的是不是。
其余的不常用就不说了。其实主要是加装饰器是为了扩展功能,但是实际上我们一般也不咋用,默认就可以了,如果你需要设计的更加精细可以考虑使用。我们一般还是借助redis去实现分布式缓存。这里的学习是为了学习他的设计。

至于这个装饰器,你说你不会用,你知道的,我会。

4.2.1、缓存装饰器简单操作

我们来写个简单的实现看看装饰器模式怎么用。

@Test
public void testMyCache() throws IOException {// 我们先声明一个PerpetualCache 被增强的目标缓存对象PerpetualCache perpetualCache = new PerpetualCache("levi");// 然后创建加buff的装饰器缓存类,把我们要增强的传入,此时的cache 就是一个有了FIFO的能力缓存了FifoCache cache = new FifoCache(perpetualCache);// 我们设计缓存大小为5来模拟缓存换出,你看看,增强之后都有设置大小的能力了,cache.setSize(5);// 放入五个对象,此时已经满了for (int i = 0; i < 5; i++) {cache.putObject(i, i);}// 输出一下第一个放入的key就是0的对象System.out.println(cache.getObject(0));// 再放一个进去,发生换出cache.putObject(5, 5);// 再取一下第一个放进去的,不出意外的话,他已经没了,因为他第一个放进去,// 按照FIFO的逻辑,他被淘汰换出了System.out.println(cache.getObject(0));
}不出意外的话,果然没有意外,输出符合预期。
0
null

4.2.2、缓存装饰器连环设置

我们上面就设置了一个增强,其实他可以多个增强,增强一组能力。写法如下。

@Test
public void testMyCache2() throws IOException {PerpetualCache perpetualCache = new PerpetualCache("levi");FifoCache fifoCache = new FifoCache(perpetualCache);LoggingCache loggingCache = new LoggingCache(perpetualCache);
}

这样他就增强了换出和日志打出的功能,你也可以再加。
或者是链式的写法。

@Test
public void testMyCache3() throws IOException {PerpetualCache perpetualCache = new PerpetualCache("levi");FifoCache fifoCache = new FifoCache(perpetualCache);LoggingCache cache = new LoggingCache(fifoCache);
}

这样都可以。至于什么是装饰器的设计,我会在设计模式写出来。

4.3、贴心的源码

你肯定会问我为啥知道这个装饰器怎么用,首先我告诉你我学过设计模式,那么没学过的兄弟们就不配用吗,mybatis此时从天而降,大喊一声,放开那个姑娘,让我来。
我们看一下mybatis源码有一个test包。这里都有,你照着看就行了,哥们,不难吧。
在这里插入图片描述

五、装饰器模式和代理模式的区别

5.1、核心区别

为啥要提到这两个模式呢,因为我们前面说代理模式的时候,提到过。
代理设计模式:为逻辑添加功能。增强功能。
装饰器模式:现在我们又说装饰器模式也是增强功能。
而且二者的URL设计类图都大差不差,那有啥区别的,用的时候有啥分别呢?
代理模式是为了增强的核心逻辑的额外功能。附加功能。
装饰器模式是为了增强核心逻辑的核心功能。
举个例子,我们的service的事务就是代理模式做的,那你service可能是去查用户,或者登录等等,肯定不是做的事务,事务是额外加的功能,增强的功能不是你要做的事,你本来是登录,他给你增强了事务功能,是两件事。这就是代理模式。
而我们上面的缓存装饰器增强的是缓存的换出和日志,这就是核心功能的增强,增强的是自己的功能,是一件事。这就是他们的区别。

可能你又要问了,既然都差不多,我为啥要听他呢,我用装饰器模式增强额外功能不行吗?
答案是行,就你行,谁能难得到你啊,数你能了。
那么大哥,你的代码以后还有人维护呢,你自己不按规矩来,后面的兄弟是不是会不理解,这样混杂一起,代码只会越来越烂,屎上雕花。

5.2、语法区别

装饰器代码我们刚才看到了,我们能套娃式的链式增强。
但是代理模式好像没这么写。
实际这个理由不充分,因为代理一般就增强一层,实际上他也能多个套,看你写不写了。

// 动态代理的InvocationHandler接口实现
InvocationHandler invocationHandler = new InvocationHandler(){@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 这里你可以继续对prox这个代理进行增强套娃,再增强一次,只不过不这么做而已Object result = method.invoke(userService, args);return result;}
};

5.3、无中生有

动态代理能无中生有,产生新对象。就像mybatis中生成DAO的实现类。
装饰器模式不行。

实际上那23种模式,你也用不全,有的甚至不能在javaweb中硬套进去。所以多思考设计,多用设计,多踩坑,踩坑了再改,才能理解的更深刻,设计模式就这样,看是看不会的,亲。

相关文章:

橘子学Mybatis07之Mybatis关于缓存的设计

很逆天的一件事是&#xff0c;我上一次发mybatis是在2022年10月15号&#xff0c;然后直到今天才开始总结下一篇Mybatis的东西。一年里面忙成那啥了&#xff0c;而且重心都投入在了Elasticsearch的学习上面&#xff0c;基本一年下来都在搞ES&#xff0c;并且考下了ECE认证&#…...

怎样制作一本旅游电子相册呢?

​随着数码技术的发展&#xff0c;旅游电子相册已成为越来越多旅游爱好者的必备工具。它不仅能让您随时随地欣赏自己的旅行回忆&#xff0c;还能分享给亲朋好友&#xff0c;甚至上传到社交媒体上&#xff0c;让更多人了解您的旅行故事。那么&#xff0c;如何制作一本精美的旅游…...

Windows搭建OpenCV环境(Python+Anaconda)

Windows搭建OpenCV环境(PythonAnacondapycharm) Anaconda&#xff0c;中文大蟒蛇&#xff0c;是一个开源的Python发行版本&#xff0c;其包含了conda、Python等180多个科学包及其依赖项。其中包含python调opencv相关的依赖&#xff0c;相当于大礼包全家桶。 下载地址&#xf…...

linux-等保三级脚本(2)

该脚本主要是针对 CentOS Linux 7 合规基线加固的一些配置操作&#xff0c;包括创建用户、安全审计配置、入侵防范配置、访问控制配置、身份鉴别策略配置等。如果您需要在脚本中添加公司网址&#xff0c;您可以在适当的位置添加相应的内容。不过请注意&#xff0c;在实际生产环…...

【论文阅读】Consistency Models

文章目录 IntroductionDiffusion ModelsConsistency ModelsDefinitionParameterizationSampling Training Consistency Models via DistillationTraining Consistency Models in IsolationExperiment Introduction 相比于单步生成的模型&#xff08;例如 GANs, VAEs, normalizi…...

Ceph应用管理

目录 资源池 Pool 管理 创建 CephFS 文件系统 MDS 接口 服务端操作 客户端操作 创建 Ceph 块存储系统 RBD 接口 创建 Ceph 对象存储系统 RGW 接口 OSD 故障模拟与恢复 资源池 Pool 管理 我们如何向 Ceph 中存储数据呢&#xff1f;首先我们需要在 Ceph 中定义一个 Pool…...

大师学SwiftUI第6章 - 声明式用户界面 Part 3

安全域视图 SwiftUI还内置了创建安全文本框的视图。这一视图会把用户输入的字符替换成点以及隐藏敏感信息&#xff0c;比如密码。 SecureField(String, text: Binding)&#xff1a;该初始化方法创建一个安全输入框。第一个参数定义占位文本&#xff0c;​​text​​参数为存储…...

使用AI自动生成PPT提高制作效率

使用AI自动生成PPT提高制作效率 在制作PPT方面&#xff0c;很多制作者都会轻易跳进一个怪圈&#xff1a;“我要制作一个关于关爱老人的PPT&#xff0c;该怎么做呢&#xff0c;有模板没有?”这个会涉及很多逻辑需要经过不断的思考&#xff0c;制作PPT要通过很多素材、使用技巧、…...

Servlet中访问网页常遇到的问题

网页出现404 出现这一种情况是浏览器访问的资源不存在 第一种情况通常是路径出错请检查你的路径是否一致 第二种情况确认你的webapp是否被正确加载 smart tomcat由于只加载一个webapp 如果加载失败 就会直接启动失败 拷贝war方式到Tomcat要加载多个webapp如果失败只有日志 查…...

Vue加载序列帧动图

解读方法 使用<img :src"currentFrame" alt"加载中" /> 加载图片动态更改src的值使用 requestAnimationFrame 定时更新在需要的页面调用封装的组件 <LoadToast v-if"showLoading" /> 封装组件 <template><div class"…...

k8s的配置资源管理

1、configmap*&#xff1a;1.2加入新的特征&#xff08;重点&#xff09; 2、secret&#xff1a;保存密码&#xff0c;token&#xff0c;保存敏感的k8s资源&#xff08;保存加密的信息&#xff09; &#xff08;1&#xff09;敏感的k8s资源&#xff0c;这类数据可以直接存放在…...

vue 指定区域可拖拽的限定拖拽区域的div(如仅弹窗标题可拖拽的弹窗)

<template><div class"container" ref"container"><div class"drag-box" v-drag><div class"win_head">弹窗标题</div><div class"win_content">弹窗内容</div></div><…...

【idea】idea插件编写教程,博主原创idea插件已上架idea插件市场 欢迎下载

前言&#xff1a;经常使用Objects.equals(a,b)方法的同学 应该或多或少都会因为粗心而传错参&#xff0c; 例如日常开发中 我们使用Objects.equals去比较 status(入参)&#xff0c;statusEnum(枚举), 很容易忘记statusEnum.getCode() 或 statusEnum.getVaule() &#xff0c;再比…...

探索Python数据结构与算法:解锁编程的无限可能

文章目录 一、引言1.1 数据结构与算法对于编程的重要性1.2 Python作为实现数据结构与算法的强大工具 二、列表和元组2.1 列表&#xff1a;创建列表、索引、切片和常用操作2.2 元组&#xff1a;不可变序列的特性和使用场景 三、字符串操作和正则表达式3.1 字符串的常见操作和方法…...

责任链模式介绍及演示

责任链模介绍 责任链模式&#xff08;Chain of Responsibility Pattern&#xff09;是一种行为设计模式&#xff0c;其主要目的是将请求的发送者和接收者解耦。在这个模式中&#xff0c;多个对象有机会处理一个请求&#xff0c;形成一条“责任链”。每个对象在链中检查该请求并…...

智能小程序小部件(Widget)表单组件属性说明+代码明细

在 Tuya MiniApp Tools 中&#xff0c;新建项目并选择小部件(Widget)对应模板即可自动创建小部件(Widget)项目。 button 按钮&#xff0c;用于强调操作并引导用户去点击。 属性说明 属性名类型默认值必填说明sizestringdefault否按钮的大小typestringdefault否按钮的样式类…...

自学Python笔记总结(更新中……)

自学Python笔记总结 网址数据类型类型查看类型&#xff0c;使用type内置类标识符 输出输入语句format函数的语法及用法数据类型的转换运算符算数运算符赋值运算符的特殊场景拆包 比较运算符逻辑运算符 与 短路位运算符运算符优先级 程序流程控制分支语句pass 占位 循环语句 whi…...

十四.变量、异常处理

变量、异常处理 1.变量1.1系统变量1.1.1系统变量分类1.1.2查看系统变量 1.2用户变量1.2.1用户变量分类1.2.2会话用户变量1.2.3局部变量1.2.4对比会话用户变量与局部变量 补充:MySQL 8.0的新特性—全局变量的持久化 2.定义条件与处理程序2.1案例分析2.2定义条件2.3定义处理程序2…...

import { ArrowRight } from “@element-plus/icons-vue“;

今天下午快被这个问题折磨疯了 虽然知道这个问题怎么产生的 但项目里那个碍眼的红线就是去不掉 后来才发现 这是插件的锅 我的心情 你知道我想要说什么的 想必能看到这篇文章的 也知道这个问题是怎么产生的 vue3ts使用的时候 默认是需要带上文件名的 但是引入el组件时 …...

Kubernetes 面试宝典

创建 Pod的主要流程? 客户端提交 Pod 的配置信息(可以是 yaml 文件定义的信息)到 kube-apiserver. Apiserver 收到指令后,通知 controllr-manager 创建一个资源对象 controller-manager 通过 apiserver 将 pod 的配置信息存储到 ETCD 数据中薪心中 kube-scheduler 检查到 p…...

springboot 百货中心供应链管理系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;百货中心供应链管理系统被用户普遍使用&#xff0c;为方…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

Python爬虫实战:研究feedparser库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级

在互联网的快速发展中&#xff0c;高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司&#xff0c;近期做出了一个重大技术决策&#xff1a;弃用长期使用的 Nginx&#xff0c;转而采用其内部开发…...

微信小程序云开发平台MySQL的连接方式

注&#xff1a;微信小程序云开发平台指的是腾讯云开发 先给结论&#xff1a;微信小程序云开发平台的MySQL&#xff0c;无法通过获取数据库连接信息的方式进行连接&#xff0c;连接只能通过云开发的SDK连接&#xff0c;具体要参考官方文档&#xff1a; 为什么&#xff1f; 因为…...

今日科技热点速览

&#x1f525; 今日科技热点速览 &#x1f3ae; 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售&#xff0c;主打更强图形性能与沉浸式体验&#xff0c;支持多模态交互&#xff0c;受到全球玩家热捧 。 &#x1f916; 人工智能持续突破 DeepSeek-R1&…...

SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)

上一章用到了V2 的概念&#xff0c;其实 Fiori当中还有 V4&#xff0c;咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务)&#xff0c;代理中间件&#xff08;ui5-middleware-simpleproxy&#xff09;-CSDN博客…...

智能AI电话机器人系统的识别能力现状与发展水平

一、引言 随着人工智能技术的飞速发展&#xff0c;AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术&#xff0c;在客户服务、营销推广、信息查询等领域发挥着越来越重要…...

R语言速释制剂QBD解决方案之三

本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...

快刀集(1): 一刀斩断视频片头广告

一刀流&#xff1a;用一个简单脚本&#xff0c;秒杀视频片头广告&#xff0c;还你清爽观影体验。 1. 引子 作为一个爱生活、爱学习、爱收藏高清资源的老码农&#xff0c;平时写代码之余看看电影、补补片&#xff0c;是再正常不过的事。 电影嘛&#xff0c;要沉浸&#xff0c;…...