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

MyBatis缓存-一级缓存--二级缓存的非常详细的介绍

目录

MyBatis-缓存-提高检索效率的利器

缓存-官方文档

一级缓存

基本说明

一级缓存原理图

代码演示

修改MonsterMapperTest.java, 增加测试方法

结果 

 debug 一级缓存执行流程

 一级缓存失效分析

关闭sqlSession会话后 , 一级缓存失效

如果执行sqlSession.clearCache() , 会导致一级缓存失效

如果修改了同一个对象 , 会导致一级缓存[对象数据]失效

MyBatis--之二级缓存

基本介绍

示意图

 二级缓存快速入门

mybatis-config.xml 配置中开启二级缓存

在对应的 XxxMapper.xml 中设置二级缓存的策略

 解读

name:缓存名称。

修改 MonsterMapperTest.java , 完成测试

语句发送的顺序:

语句返回的顺序:

注意事项和使用陷阱 

理解二级缓存策略的参数

上面的配置意思如下:

 四大策略

 如何禁用二级缓存

MonsterMapper.xml 

或者更加细粒度的, 在配置方法上指定

mybatis 刷新二级缓存的设置 

注意

EhCache 缓存-细节说明  


MyBatis-缓存-提高检索效率的利器

缓存-官方文档

文档地址: https://mybatis.org/mybatis-3/zh/sqlmap-xml.html#cache

一级缓存

基本说明

1.     默认情况下,mybatis 是启用一级缓存的/本地缓存/local Cache,它是 SqlSession 级别的。

2.     同一个 SqlSession 接口对象调用了相同的 select 语句,会直接从缓存里面获取,而不是再去查询数据库

一级缓存原理图

代码演示

需求: 当我们第 1 次查询 id=1 的 Monster 后,再次查询 id=1 的 monster 对象,就会直接从一级缓存获取,不会再次发出sql

创建新module: mybatis_cache , 必要的文件和配置直接从mybatis_quickstart module拷贝即可

使用 MonsterMapperTest.java , 运行 getMonsterById() 看看是否可以看到日志输出,结论我们多次运行,总是会发出 SQL.

修改MonsterMapperTest.java, 增加测试方法

测试一级缓存的基本使用

public class MonsterMapperTest {//属性private SqlSession sqlSession;private MonsterMapper monsterMapper;/*** 解读* 1. 当方法标注 @Before, 表示在执行你的目标测试方法前,会先执行该方法* 2. 这里在测试的时候,可能小伙伴们会遇到一些麻烦,老师说了解决方案*///编写方法完成初始化@Beforepublic void init() {//获取到sqlSessionsqlSession = MyBatisUtils.getSqlSession();//获取到到MonsterMapper对象 class com.sun.proxy.$Proxy7 代理对象//, 底层是使用了动态代理机制, 后面我们自己实现mybatis底层机制时,会讲到monsterMapper = sqlSession.getMapper(MonsterMapper.class);System.out.println("monsterMapper=" + monsterMapper.getClass());}@Testpublic void getMonsterById() {Monster monster = monsterMapper.getMonsterById(3);System.out.println("monster=" + monster);if (sqlSession != null) {sqlSession.close();}System.out.println("查询成功~~~~");}//测试一级缓存@Testpublic void level1CacheTest() {//查询id=3的monsterMonster monster = monsterMapper.getMonsterById(3);System.out.println("monster=" + monster);monsterMapper.getMonsterById(8);//再次查询id=3的monster//当我们再次查询 id=3的Monster时,直接从一级缓存获取,不会再次发出sqlSystem.out.println("--一级缓存默认是打开的,当你再次查询相同的id时, 不会再发出sql----");Monster monster2 = monsterMapper.getMonsterById(3);System.out.println("monster2=" + monster2);if (sqlSession != null) {sqlSession.close();}}
}

结果 

 debug 一级缓存执行流程

 一级缓存失效分析

1. 关闭sqlSession 会话后, 再次查询,会到数据库查询, 修改MonsterMapperTest.java,

关闭sqlSession会话后 , 一级缓存失效

    //测试一级缓存,失效//关闭sqlSession会话后 , 一级缓存失效@Testpublic void level1CacheTest2() {//查询id=3的monsterMonster monster = monsterMapper.getMonsterById(3);System.out.println("monster=" + monster);//关闭sqlSession, 一级缓存失效if (sqlSession != null) {sqlSession.close();}//因为关闭了sqlSession,所以需要重新初始化sqlSession和 monsterMappersqlSession = MyBatisUtils.getSqlSession();monsterMapper = sqlSession.getMapper(MonsterMapper.class);//再次查询id=3的monsterSystem.out.println("--如果你关闭了sqlSession,当你再次查询相同的id时, 仍然会发出sql----");Monster monster2 = monsterMapper.getMonsterById(3);System.out.println("monster2=" + monster2);if (sqlSession != null) {sqlSession.close();}}

如果执行sqlSession.clearCache() , 会导致一级缓存失效

 @Testpublic void level1CacheTest3() {//查询id=3的monsterMonster monster = monsterMapper.getMonsterById(3);System.out.println("monster=" + monster);//执行clearCache/*** @Override*   public void clearCache() {*     executor.clearLocalCache();*   }*/sqlSession.clearCache();//再次查询id=3的monsterSystem.out.println("--如果你执行sqlSession.clearCache(),当你再次查询相同的id时, 仍然会发出sql----");Monster monster2 = monsterMapper.getMonsterById(3);System.out.println("monster2=" + monster2);if (sqlSession != null) {sqlSession.close();}}

如果修改了同一个对象 , 会导致一级缓存[对象数据]失效

 @Testpublic void level1CacheTest4() {//查询id=3的monsterMonster monster = monsterMapper.getMonsterById(3);System.out.println("monster=" + monster);//如果修改了同一个对象 , 会导致一级缓存[对象数据]失效monster.setName("蚂蚱精");monsterMapper.updateMonster(monster);//再次查询id=3的monsterSystem.out.println("--如果你修改了同一个对象,当你再次查询相同的id时, 仍然会发出sql----");Monster monster2 = monsterMapper.getMonsterById(3);System.out.println("monster2=" + monster2);if (sqlSession != null) {sqlSession.commit();//这里需要commitsqlSession.close();}}


MyBatis--之二级缓存

基本介绍

1.    二级缓存和一级缓存都是为了提高检索效率的技术
2.    最大的区别就是作用域的范围不一样,一级缓存的作用域是 sqlSession 会话级别,在一次会话有效,而二级缓存作用域是全局范围,针对不同的会话都有效

示意图

 二级缓存快速入门

mybatis-config.xml 配置中开启二级缓存

    <!--配置MyBatis自带的日志输出-查看原生的sql--><settings><setting name="logImpl" value="STDOUT_LOGGING"/><!--1、全局性地开启或关闭所有映射器配置文件中已配置的任何缓存, 可以理解这是一个总开关2、默认就是: true--><!--开启二级缓存--><setting name="cacheEnabled" value="true"/></settings>

 使用二级缓存时 entity 类实现序列化接口 (serializable),因为二级缓存可能使用到序列化技术

 

在对应的 XxxMapper.xml 中设置二级缓存的策略

 如我这里是ehcache.xml.

<?xml version="1.0" encoding="UTF-8"?>
<ehcache><!--diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。参数解释如下:user.home – 用户主目录user.dir  – 用户当前工作目录java.io.tmpdir – 默认临时文件路径--><diskStore path="java.io.tmpdir/Tmp_EhCache"/><!--defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个。--><!--name:缓存名称。maxElementsInMemory:缓存最大数目maxElementsOnDisk:硬盘最大缓存个数。eternal:对象是否永久有效,一但设置了,timeout将不起作用。overflowToDisk:是否保存到磁盘,当系统宕机时timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。clearOnFlush:内存数量最大时是否清除。memoryStoreEvictionPolicy:可选策略(清除策略)有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。FIFO,first in first out,这个是大家最熟的,先进先出。LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。--><defaultCacheeternal="false"maxElementsInMemory="10000"overflowToDisk="false"diskPersistent="false"timeToIdleSeconds="1800"timeToLiveSeconds="259200"memoryStoreEvictionPolicy="LRU"/></ehcache>

 解读

diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。参数

解释如下:    

user.home – 用户主目录.   

user.dir  – 用户当前工作目录.

java.io.tmpdir – 默认临时文件路径.

defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个

name:缓存名称

      maxElementsInMemory:缓存最大数目.

      maxElementsOnDisk硬盘最大缓存个数。

      eternal:对象是否永久有效,一但设置了,timeout将不起作用

      overflowToDisk:是否保存到磁盘,当系统宕机时.

      timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大

      timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。

      diskPersistent:是否缓存虚拟机-重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.

      diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。

      diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。

      memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。

      clearOnFlush:内存数量-最大时是否清除。

      memoryStoreEvictionPolicy:可选策略(清除策略)有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。

      FIFO,first in first out,这个是大家最熟的,先进先出

      LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存

      LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存

修改 MonsterMapperTest.java , 完成测试

@Testpublic void level2CacheTest() {//查询id=3的monsterMonster monster = monsterMapper.getMonsterById(3);//会发出SQL, 到db查询System.out.println("monster=" + monster);//这里关闭sqlSessionif (sqlSession != null) {sqlSession.close();}//重新获取sqlSessionsqlSession = MyBatisUtils.getSqlSession();//重新获取了monsterMappermonsterMapper = sqlSession.getMapper(MonsterMapper.class);//再次查询id=3的monsterSystem.out.println("--虽然前面关闭了sqlSession,因为配置二级缓存, " +"当你再次查询相同的id时, 依然不会再发出sql, 而是从二级缓存获取数据----");Monster monster2 = monsterMapper.getMonsterById(3);System.out.println("monster2=" + monster2);Monster monster3 = monsterMapper.getMonsterById(3);System.out.println("monster3=" + monster3);if (sqlSession != null) {sqlSession.close();}}

语句发送的顺序:

第一步 先去二级缓存寻找去寻找对比有就返回-->

第二步在去一级缓存去寻找对比有就返回--->

第3步再去发送sql语句去找需要的数据

语句返回的顺序:

第二步的好处:可以及时更新缓存 然后防止缓存数据出错

第一步数据库返回需要的数据-->

第二步保存或者跟新在一级缓存里面的数据-->

第三步有一级缓存发送给用户也就是是输出-->

第四步 关闭程序或者关闭sqlSession会话后  或者   执行sqlSession.clearCache()    之前判断是否开启了二级缓存是的话就把数据保存在二级缓存如果没有开启的话就直接清除 

   //分析缓存执行顺序//二级缓存->一级缓存->DB//因为二级缓存(数据)是在一级缓存关闭之后才有的@Testpublic void cacheSeqTest2() {System.out.println("查询第1次");//DB , 会发出 SQL, cache hit ratio 0.0Monster monster1 = monsterMapper.getMonsterById(3);System.out.println(monster1);//这里我们没有关闭sqlSessionSystem.out.println("查询第2次");//从一级缓存获取id=3 , cache hit ratio 0.0, 不会发出SQLMonster monster2 = monsterMapper.getMonsterById(3);System.out.println(monster2);System.out.println("查询第3次");//还是从一级缓存获取id=3, cache hit ratio 0.0, 不会发出SQLMonster monster3 = monsterMapper.getMonsterById(3);System.out.println(monster3);if (sqlSession != null) {sqlSession.commit();sqlSession.close();}System.out.println("操作成功");}

注意事项和使用陷阱 

理解二级缓存策略的参数

<cache eviction="FIFO" flushInterval="30000" size="360" readOnly="true"/>

上面的配置意思如下:

创建了 FIFO 的策略,每隔 30 秒刷新一次,最多存放 360 个对象而且返回的对象被认为是只读的。

eviction:缓存的回收策略

flushInterval:时间间隔,单位是毫秒

size:引用数目,内存大就多配置点,要记住你缓存的对象数目和你运行环境的可用内存资源数目。默认值是 1024

readOnly:true,只读

 四大策略

√    LRU – 最近最少使用的:移除最长时间不被使用的对象,它是默认

√    FIFO – 先进先出:按对象进入缓存的顺序来移除它们。

√    SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。

√    WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。

 如何禁用二级缓存

<settings><setting name="logImpl" value="STDOUT_LOGGING"/><!--<!--全局性地开启或关闭所有映射器配置文件中已配置的任何缓存, 默认就是 true--> <!--关闭二级缓存--><setting name="cacheEnabled" value="false"/></settings>

MonsterMapper.xml 

<cache eviction="FIFO" flushInterval="30000" size="360" readOnly="true"/>

或者更加细粒度的, 在配置方法上指定

设置 useCache=false 可以禁用当前 select 语句的二级缓存,即每次查询都会发出 sql 去查询, 

默认情况是 true,即该 sql 使用二级缓存

注意:一般我们不需要去修改,使用默认的即可

mybatis 刷新二级缓存的设置 

<update id="updateMonster" parameterType="Monster" flushCache="true">UPDATE mybatis_monster SET NAME=#{name},age=#{age} WHERE id=#{id}
</update>

insert、update、delete 操作数据后需要刷新缓存,如果不执行刷新缓存会出现脏读默认为 true,默认情况下为 true 即刷新缓存,一般不用修改

注意

在 XxxMapper.xml 中启用 EhCache , 当然原来 MyBatis 自带的缓存配置就注销了

EhCache 缓存-细节说明  

 1.    MyBatis 提供了一个接口 Cache  如图,找到 org.apache.ibatis.cache.Cache ,关联源码包就可以看到 Cache 接口

2.    只要实现了该 Cache 接口,就可以作为二级缓存产品和 MyBatis 整合使用,Ehcache 就是实现了该接口.

3.    MyBatis 默认情况(即一级缓存)是使用的 PerpetualCache 类实现 Cache 接口的,是核心类.

 

4.  当我们使用了 Ehcahce 后,就是 EhcacheCache 类实现 Cache 接口的,是核心类.

5. 我们看一下源码,发现缓存的本质就是 Map<Object,Object> 

到这一步了对二级缓存也就没有多少疑惑了。

相关文章:

MyBatis缓存-一级缓存--二级缓存的非常详细的介绍

目录 MyBatis-缓存-提高检索效率的利器 缓存-官方文档 一级缓存 基本说明 一级缓存原理图 代码演示 修改MonsterMapperTest.java, 增加测试方法 结果 debug 一级缓存执行流程 一级缓存失效分析 关闭sqlSession会话后 , 一级缓存失效 如果执行sqlSession.clearCache(…...

macOS Ventura 13.4 RC2(22F63)发布

系统介绍 根据黑果魏叔官网提供&#xff1a;5 月 12 日消息&#xff0c;苹果今天面向开发人员&#xff0c;发布了 macOS Ventura 13.4 的第 2 个候选 RC 版本&#xff08;内部版本号 22F63&#xff09;&#xff0c;距离上个候选版本相隔数天时间。 macOS Ventura 带来了台前调…...

【为什么可以相信一个HTTPS网站】

解决信用&#xff0c;仅仅有加密和解密是不够的。加密解密解决的只是传输链路的安全问题&#xff0c;相当于两个人说话不被窃听。可以类比成你现在生活 的世界——货币的信用&#xff0c;是由政府在背后支撑的&#xff1b;购房贷款的信用&#xff0c;是由银行在背后支撑的&…...

4.进阶篇

目录 一、按照测试对象划分 1.界面测试&#xff08;UI测试&#xff09; 界面测试的常见错误&#xff1a; 2.可靠性测试 3.容错性测试 4.文档测试 5.兼容性测试 6.易用性 7.安装卸载测试 8.安全性测试 9.性能测试 10.内存泄漏 二、按照是否查看代码 1.黑盒测试 2.…...

conda init

在输入conda activate 的时候出现报错: 解决: "需要使用 conda init 进行初始化" 的错误通常是由于你的系统环境缺少 conda 的初始化脚本所致。当你尝试在终端中执行 conda activate 命令时,会出现此错误提示。 要解决这个问题,可以通过以下步骤进行操作: 打…...

Elasticsearch(二)

Clasticsearch&#xff08;二&#xff09; DSL查询语法 文档 文档&#xff1a;https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html 常见查询类型包括&#xff1a; 查询所有&#xff1a;查询出所有数据&#xff0c;一般测试用。如&#xff1a…...

工业视觉检测的8个技术优势

工业4.0时代&#xff0c;自动化生产线成为了这个时代的主旋律&#xff0c;而工业视觉检测技术也成为其中亮眼的表现&#xff0c;其机器视觉技术为设备提供了智慧的双眼&#xff0c;让自动化的脚步得以加速&#xff01; 在实际的生产应用中&#xff0c;视觉技术方案往往先被着手…...

16 KVM虚拟机配置-其他常见配置项

文章目录 16 KVM虚拟机配置-其他常见配置项16.1 概述16.2 元素介绍16.3 配置示例 16 KVM虚拟机配置-其他常见配置项 16.1 概述 除系统资源和虚拟设备外&#xff0c;XML配置文件还需要配置一些其他元素&#xff0c;本节介绍这些元素的配置方法。 16.2 元素介绍 iothreads&…...

(转载)从0开始学matlab(第1天)—变量和数组

MATLAB 程序的基本数据单元是数组。一个数组是以行和列组织起来的数据集合&#xff0c;并且拥有一个数组名。数组中的单个数据是可以被访问的&#xff0c;访问的方法是数组名后带一个括号&#xff0c;括号内是这个数据所对应行标和列标。标量在 MATLAB 中也被当作数组来处理——…...

Linux命令·wget

Linux系统中的wget是一个下载文件的工具&#xff0c;它用在命令行下。对于Linux用户是必不可少的工具&#xff0c;我们经常要下载一些软件或从远程服务器恢复备份到本地服务器。wget支持HTTP&#xff0c;HTTPS和FTP协议&#xff0c;可以使用HTTP代理。所谓的自动下载是指&#…...

API网关简介|TaobaoAPI接入

API网关是什么 在日常工作中&#xff0c;不同的场合下&#xff0c;我们可能听说过很多次网关这个名称&#xff0c;这里说的网关特指API网关&#xff08;API Gataway&#xff09;。字面意思是指将所有API的调用统一接入API网关层&#xff0c;由网关层负责接入和输出。 那么在什…...

OJ练习第103题——最大矩形

最大矩形 力扣链接&#xff1a;85. 最大矩形 题目描述 给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵&#xff0c;找出只包含 1 的最大矩形&#xff0c;并返回其面积。 示例 输入&#xff1a;matrix [[“1”,“0”,“1”,“0”,“0”],[“1”,“0”,“1”…...

JavaScript实现输入年份判断是否为闰年的代码

以下为实现输入年份判断是否为闰年的程序代码和运行截图 目录 前言 一、输入年份判断是否为闰年 1.1 运行流程及思想 1.2 代码段 1.3 JavaScript语句代码 1.4 运行截图 前言 1.若有选择&#xff0c;您可以在目录里进行快速查找&#xff1b; 2.本博文代码可以根据题目要…...

LiangGaRy-学习笔记-Day12

1、作业回顾 1.1、判断磁盘利用率 要求&#xff1a; 判断磁盘的使用率&#xff0c;如果超过了90%就警告 [rootNode1 sh]# vim disk_check.sh #!/bin/bash #Author By LiangGaRy #2023年5月9日 #Usage:检测硬盘的使用率 ########################################### #定义一…...

LayUI中弹出层select动态回显设置及子页面刷新父页面Table数据方法

...

浅谈Hutool工具类

一、Hutool简介 Hutool是一个Java工具类库&#xff0c;它封装了很多常用的Java工具类&#xff0c;如加密解密、文件操作、日期时间处理、Http客户端等。它的目标是让Java开发变得更加简单、高效。 二、Hutool的特点 高效&#xff1a;提供了很多高效的工具类和方法。 简单&…...

Mac终端代理

1.打开代理查看代理端口号 打开设置&#xff0c;点击网络&#xff0c;点击详细信息&#xff0c;点击代理查看代理端口号。 2.修改环境变量 1&#xff09;终端输入下面命令 vim .zshrc 2&#xff09;在.zshrc文件里添加下面两段内容&#xff08;注意&#xff1a;7980为端口号…...

Git Clone 报错 `SSL certificate problem: unable to get local issuer certificate`

如果您在尝试克隆Git存储库时得到 “SSL certificate problem: unable to get local issuer certificate” 的错误,这意味着Git无法验证远程存储库的SSL证书。如果SSL证书是自签名的&#xff0c;或者SSL证书链有问题&#xff0c;就会发生这种情况。 $ git clone https://githu…...

第八章 文件与异常

引言 码字不易&#xff0c;如果这篇文章对您有帮助的话&#xff0c;希望您能点赞、收藏、加关注&#xff01;您的鼓励就是我前进的动力&#xff01; 目录 一、读取文件&#xff08;一&#xff09;读取文件&#xff1a;open(), with, read()&#xff08;二&#xff09;文件路径…...

Gradle使用

下载Gradle Gradle Distributions 配置环境变量 测试是否成功 cmd输入gradle -v 在.gradle目录下创建一个init.gradle allprojects { repositories { maven { url file:///D:/maven/myRepository} ## 这里是本地maven仓库地址,没有就会依次向下设置的地址寻…...

从七个方面聊聊Linux到底强在哪

从事计算机相关行业的同学不难发现&#xff0c;身边总有一些朋友在学习linux&#xff0c;有的开发同学甚至自己的电脑就是它。经常听他们说linux如何好用等等。那么linux到底好在那里&#xff0c;能让大家如此喜欢。这也是我经常问自己的一个问题。下面我将通过以下七点来为大家…...

python读写json文件方法详解

在我们日常使用 Python时&#xff0c;经常会使用到 json文件。那么在平时写一些小程序时&#xff0c;如何使用 json文件呢&#xff1f;今天我将介绍如何读取和写入 Json文件。 json是一种数据结构&#xff0c;它是将字符串转换成数据的一种技术。使用 json可以非常方便的将一组…...

多处最优服务次序问题——算法设计与分析(C实现)

问题描述&#xff1a;设有n个顾客同时等待一项服务。顾客i需要的服务时间为&#xff0c;共有s处可以提供此项服务。应该如何安排n个顾客的服务次序&#xff0c;才能使平均等待时间达到最小&#xff1f;平均等待时间是n个顾客的等待服务时间的总和除以n。 算法设计&#xff1a;对…...

2023 年 IntelliJ IDEA 下载安装教程,超详细图文教程,亲测可用

. IDEA 下载 1、打开浏览器输入https://www.jetbrains.com/&#xff0c;进入 Jetbrains官网&#xff0c;点击 Developer Tools&#xff0c;再点击 Intellij IDEA 2、点击中间的 Download&#xff0c;进入IDEA下载界面 3、选择左边的 Ultimate 版本进行下载安装。Ultimate 版…...

前端框架比较:Vue.js、React、AngularJS三者的优缺点和应用场景

章节一&#xff1a;引言 在当前的互联网开发中&#xff0c;前端框架已经成为了不可或缺的一部分。然而&#xff0c;前端框架如此之多&#xff0c;该如何选择呢&#xff1f;Vue.js、React和AngularJS是目前比较受欢迎的三个前端框架&#xff0c;它们各自有着不同的优缺点和应用…...

JavaScript中的数据可视化和动画效果

摘要&#xff1a; JavaScript是一种强大而灵活的编程语言&#xff0c;被广泛用于网页开发和交互设计。在数据可视化和动画效果方面&#xff0c;JavaScript提供了丰富的工具和库&#xff0c;使开发者能够创建出令人印象深刻的交互式数据可视化和动画效果。本文将介绍JavaScript中…...

如何搭建在线产品手册

在现代社会&#xff0c;随着科技的发展&#xff0c;越来越多的企业将目光投向互联网&#xff0c;并将自己的产品推向了线上。而对于这些线上产品&#xff0c;拥有一份完备的、易用、高质量的在线产品手册显得尤为重要。 那么如何才能搭建一份高质量且易用的在线产品手册呢&…...

Java版企业电子采购招标系统源码

一、立项管理 1、招标立项申请 功能点&#xff1a;招标类项目立项申请入口&#xff0c;用户可以保存为草稿&#xff0c;提交。 2、非招标立项申请 功能点&#xff1a;非招标立项申请入口、用户可以保存为草稿、提交。 3、采购立项列表 功能点&#xff1a;对草稿进行编辑&#x…...

【操作系统复习】第6章 虚拟存储器 2

请求分页中的内存分配 在为进程分配物理块时&#xff0c;要解决下列的三个问题&#xff1a; 1. 保证进程可正常运行所需要的最少物理块数 2. 每个进程的物理块数&#xff0c;是固定值还是可变值&#xff08;分配策略&#xff09; 3. 不同进程所分配的物理块数&#xff…...

【OAI】OAI5G核心网VPP-UPF网元分析

文章目录 VPP_UPF_CONFIG_GENERATION.mdVPP UPF Configuration GenerationEnvironment variablesInterfacesInterface Configuration ExamplesCentral UPFA-UPFI-UPFUL CL FEATURE_SET.mdVPP_UPG_CLI参考文献 VPP_UPF_CONFIG_GENERATION.md VPP UPF Configuration Generation …...