美团Java开发一面凉经
目录
- 1.HashMap底层数据结构
- 2.列举几个常见的线程安全容器
- 3.HashMap线程问题
- 4.concurrentHashMap
- 5.ConcurrentModificationException
- 6.Spring AOP、IOC、DI介绍下
- 7.不使用依赖注入,使用传统方式的声明会有什么问题
- 8.最左前缀原则
- 9.TCP三次握手、四次挥手
1.HashMap底层数据结构
在 JDK 1.7 中,HashMap 使用的是数组 + 链表实现。
在 JDK 1.8 中使用的是数组 + 链表或红黑树实现的。
put实现原理
(1)先判断当前Node[]数组是不是为空,为空就新建,不为空就对hash值与容量-1做与运算得到数组下标
(2)然后会判断当前数组位置有没有元素,没有的话就把值插到当前位置,有的话就说明遇到了哈希碰撞
(3)遇到哈希碰撞后,如果Hash值相同且equals内容也相同,直接覆盖,就会看下当前链表是不是以红黑树的方式存储,是的话,就会遍历红黑树,看有没有相同key的元素,有就覆盖,没有就执行红黑树插入
(4)如果是普通链表,则按普通链表的方式遍历链表的元素,判断p.next = null的情况下,直接存放追加在next后面,然后我们要检查一下如果链表长度大于8且数组容量>=64链表转换成红黑树,否则查找到链表中是否存在该key,如果存在直接修改value值,如果没有继续遍历
(5)如果++size > threshold(阈值)就扩容
HashMap中put的实现原理
HashMap何时会链表转红黑树
2.列举几个常见的线程安全容器
1.Vector
2.HashTable
3.ConcurrentHashMap:分段
4.CopyOnWriteArrayList:写时复制
5.CopyOnWriteArraySet:写时复制
3.HashMap线程问题
JDK1.8 中,由于多线程对HashMap进行put操作,调用了HashMap#putVal(),具体原因:假设两个线程A、B都在进行put操作,并且hash函数计算出的插入下标是相同的,当线程A执行完第六行代码后由于时间片耗尽导致被挂起,而线程B得到时间片后在该下标处插入了元素,完成了正常的插入,然后线程A获得时间片,由于之前已经进行了hash碰撞的判断,所有此时不会再进行判断,而是直接进行插入,这就导致了线程B插入的数据被线程A覆盖了,从而线程不安全。
4.concurrentHashMap
ConcurrentHashMap
JDK1.7ConcurrentHashMap底层实现原理:
数据结构:Segment(大数组) + HashEntry(小数组) + 链表,每个 Segment 对应一把锁,如果多个线程访问不同的 Segment,则不会冲突
JDK1.8ConcurrentHashMap底层实现原理:
数据结构:Node 数组 + 链表或红黑树,数组的每个头节点作为锁,如果多个线程访问的头节点不同,则不会冲突。首次生成头节点时如果发生竞争,利用 cas 而非 syncronized,进一步提升性能
ConcurrentHashMap的整体架构
数据结构:Node 数组 + 链表或红黑树,数组的每个头节点作为锁,如果多个线程访问的头节点不同,则不会冲突。首次生成头节点时如果发生竞争,利用 cas 而非 syncronized,进一步提升性能
这个是ConcurrentHashMap在JDK1.8中的存储结构,它是由数组、单向链表、红黑树组成。
当我们初始化一个ConcurrentHashMap实例时,默认会初始化一个长度为16的数组。由于ConcurrentHashMap它的核心仍然是hash表,所以必然会存在hash冲突问题。
ConcurrentHashMap采用链式寻址法来解决hash冲突。
当hash冲突比较多的时候,会造成链表长度较长,这种情况会使得ConcurrentHashMap中数据元素的查询复杂度变成O(n)。因此在JDK1.8中,引入了红黑树的机制。
当数组长度大于64并且链表长度大于等于8的时候,单项链表就会转换为红黑树。
另外,随着ConcurrentHashMap的动态扩容,一旦链表长度小于8,红黑树会退化成单向链表。
ConcurrentHashMap的基本功能
ConcurrentHashMap本质上是一个HashMap,因此功能和HashMap一样,但是ConcurrentHashMap在HashMap的基础上,提供了并发安全的实现。
并发安全的主要实现是通过对指定的Node节点加锁,来保证数据更新的安全性。
ConcurrentHashMap在性能方面做的优化
- 在JDK1.8中,ConcurrentHashMap锁的粒度是数组中的某一个节点,而在JDK1.7,锁定的是Segment,锁的范围要更大,因此性能上会更低。
- 引入红黑树,降低了数据查询的时间复杂度,红黑树的时间复杂度是O(logn)。
- 当数组长度不够时,ConcurrentHashMap需要对数组进行扩容,在扩容的实现上,ConcurrentHashMap引入了多线程并发扩容的机制,简单来说就是多个线程对原始数组进行分片后,每个线程负责一个分片的数据迁移,从而提升了扩容过程中数据迁移的效率。
- ConcurrentHashMap中有一个size()方法来获取总的元素个数,而在多线程并发场景中,在保证原子性的前提下来实现元素个数的累加,性能是非常低的。ConcurrentHashMap在这个方面的优化主要体现在两个点:
- 当线程竞争不激烈时,直接采用CAS来实现元素个数的原子递增。
如果线程竞争激烈,使用一个数组来维护元素个数,如果要增加总的元素个数,则直接从数组中随机选择一个,再通过CAS实现原子递增。它的核心思想是引入了数组来实现对并发更新的负载。
为什么不用ReentrantLock而用synchronized ?
减少内存开销:如果使用ReentrantLock则需要节点继承AQS来获得同步支持,增加内存开销,而1.8中只有头节点需要进行同步。
内部优化:synchronized则是JVM直接支持的,JVM能够在运行时作出相应的优化措施:锁粗化、锁消除、锁自旋等等。
5.ConcurrentModificationException
ConcurrentModificationException异常
当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。
modCount的作用
modCount就是修改次数,在具体的实现类中的Iterator中才会使用。在List集合中,ArrayList是List接口的实现类,
modCount:表示list集合结构上被修改的次数。(在ArrayList所有涉及结构变化的方法中,都增加了modCount的值)
list结构上别修改是指:改变了list的长度的大小或者是遍历结果中产生了不正确的结果的方式。add()和remove()方法会是modCount进行+1操作。modCount被修改后会产生ConcurrentModificationException异常, 这是jdk的快速失败原则。
下面进行试验
public static void main(String[] args) {ArrayList<String> list=new ArrayList<String>();list.add("1");list.add("2");list.add("3");Iterator<String> iterator = list.iterator();while (iterator.hasNext()){String ele=iterator.next();if(ele.equals("2")) //(1)处list.remove(ele); //(2)处}System.out.println(list);}
看下ArrayList类的Iterator是如何实现的呢?
可以看出,调用next()方法获取下一个元素时,第一行代码就是调用了checkForComodification();,而该方法的核心逻辑就是比较modCount和expectedModCount这2个变量的值。
在上面的例子中,刚开始modCount和expectedModCount的值都为3,所以第1次获取元素"1"是没问题的,但是当执行完下面这行代码时:
list.remove(ele);
modCount的值就被修改成了4。(remove方法里面调用了fastRemove)
所以在第2次获取元素时,modCount和expectedModCount的值就不相等了,所以抛出了java.util.ConcurrentModificationException异常。
解决方案
使用Iterator的remove()方法
可以看出,每次删除一个元素,都会将modCount的值重新赋值给expectedModCount,这样2个变量就相等了,不会触发java.util.ConcurrentModificationException异常。
6.Spring AOP、IOC、DI介绍下
IOC
IOC—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,IOC意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。
- 谁控制谁,控制什么?
传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IOC是有专门一个容器来创建这些对象,即由IOC容器来控制对 象的创建;谁控制谁?当然是IOC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。 - 为何是反转,哪些方面反转了?
有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。
IOC的好处?
ioc的思想最核心的地方在于,资源不由使用资源者管理,而由不使用资源的第三方管理,这可以带来很多好处。第一,资源集中管理,实现资源的可配置和易管理。第二,降低了使用资源双方的依赖程度,也就是我们说的耦合度。也就是说,甲方要达成某种目的不需要直接依赖乙方,它只需要达到的目的告诉第三方机构就可以了,比如甲方需要一双袜子,而乙方它卖一双袜子,它要把袜子卖出去,并不需要自己去直接找到一个卖家来完成袜子的卖出。它也只需要找第三方,告诉别人我要卖一双袜子。这下好了,甲乙双方进行交易活动,都不需要自己直接去找卖家,相当于程序内部开放接口,卖家由第三方作为参数传入。甲乙互相不依赖,而且只有在进行交易活动的时候,甲才和乙产生联系。反之亦然。这样做什么好处么呢,甲乙可以在对方不真实存在的情况下独立存在,而且保证不交易时候无联系,想交易的时候可以很容易的产生联系。甲乙交易活动不需要双方见面,避免了双方的互不信任造成交易失败的问题。因为交易由第三方来负责联系,而且甲乙都认为第三方可靠。那么交易就能很可靠很灵活的产生和进行了。
这就是ioc的核心思想。生活中这种例子比比皆是,支付宝在整个淘宝体系里就是庞大的ioc容器,交易双方之外的第三方,提供可靠性可依赖可灵活变更交易方的资源管理中心。另外人事代理也是,雇佣机构和个人之外的第三方。
DI
依赖注入是指将依赖的对象实例交给spring帮我们注入 管理,从而释放对对象的管理权,比如可以统一替换接口的实现,更高效的开发程序
- set方法注入
- 构造方法注入
- @autowire 自动注入
AOP
面向切面编程,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取公共模块复用,降低耦合。
你们项目中有没有使用到AOP
记录操作日志,缓存,spring实现的事务
核心是:使用aop中的环绕通知+切点表达式(找到要记录日志的方法),通过环绕通知的参数获取请求方法的参数(类、方法、注解、请求方式等),获取到这些参数以后,保存到数据库
7.不使用依赖注入,使用传统方式的声明会有什么问题
主要是实现类之间的解耦,假如A类依赖B类,在实例化A类的话也要new一个B类,如果A的依赖的类换成C的话,所有实例化A的代码的new B都要替换掉,不利于代码维护。
8.最左前缀原则
过滤条件要使用索引必须按照索引建立时的顺序,依次满足,一旦跳过某个字段,索引后面的字段都无法被使用。
9.TCP三次握手、四次挥手
TCP协议
保证传输过程的三个关键的步骤,分别为三次握手、传输确认、四次挥手。
三次握手
三次握手是建立连接的过程,当客户端向服务端发起连接时,会先发一包连接请求数据,过去询问一下,能否与你建立连接,这包数据我们称之为SYN包。如果对端同意连接,则回复一包SYN+ACK包,客户端收到之后回复一包ACK包连接建立。
因为这个过程中互相发送了三包数据,所以称之为三次握手。
Q:为什么要三次握手,而不是两次握手,服务端回复完SYN+ACK包之后就建立连接
A:这是为了防止因为已失效的请求报文突然又传到服务器引起错误。解决网络信道不可靠的问题
如果没有第三次握手告诉服务器端客户端收的到服务器端传输的数据的话,服务器端是不知道客户端有没有接收到服务器端返回的信息的。服务端就认为这个连接是可用的,端口就一直开着,等到客户端因超时重新发出请求时,服务器就会重新开启一个端口连接。
这样一来,就会有很多无效的连接端口白白地开着,导致资源的浪费。
还有一种情况是已经失效的客户端发出的请求信息,由于某种原因传输到了服务器端,服务器端以为是客户端发出的有效请求,接收后产生错误。
Q:为什么不是四次握手?
A:因为通信不可能100%可靠,而上面的三次握手已经做好了通信的准备工作,再四次握手,并不能显著提高可靠性,而且也没有必要。
数据传输
经过三次握手之后,客户端和服务端都进入了数据传输状态。tcp协议需要在不可靠的信道上保证可靠的连接。现在就有几个问题需要面对:1. 一包数据有可能被拆成多包发送,如何处理丢包问题 ;2. 这些数据包到达的先后顺序不同,如何处理乱乱序问题。
针对以上的要求,TCP协议为每一个连接建立了一个发送缓冲区,从建立链接后的第一个字节的序列号为0,后面每个字节的序列号就会增加1。发送数据时,从发送缓冲区,取一部分数据组成发送报文,在其tcp协议头中会附带序列号和长度,接受端在收到数据后,需要回复确认报文。确认报文中的ACK,等于接收序列号加长度,也就是下一包数据需要发送的起始序列号。
这样一问一答的发送方式,能够使发送端确认发送的数据已经被对方收到,发送端也可以一次发送连续多包数据,接收端只需要回复一次ACK就可以了,这样发送端可以把待发送的数据分割成一系列的碎片,发送到对端。对端根据序列号和长度,在接受后重构出来完整的数据,假设其中丢失了某些数据包,在接收端可以要求发送端重传。比如丢失了100-199,这100个字节,接收端向发送端发送ACK = 100 报文,发送端收到后重传这一包数据,接受端进行补齐。
以上过程不区分客户端和服务端,TCP连接是全双工的,对于两端来说均采用上述机制。
四次挥手
处于连接状态的客户端和服务端都可以发起关闭连接请求,此时需要四次挥手来进行连接关闭。
1.假设客户端主动发起连接关闭请求,他需要将服务端发起一包FIN包,表示要关闭连接,自己进入终止等待1状态,这是第一次挥手。
2.服务端收到FIN包,发送一包ACK包,表示自己进入了关闭等待状态,客户端进入终止等待2状态,这是第二次挥手。
3.服务端此时还可以发送未发送的数据,而客户端还可以接收数据,待服务端发送完数据之后,发送一包FIN包,进入最后确认状态,这是第三次挥手。
4.客户端收到之后回复ACK包,进入超时等待状态,经过超时时间后关闭连接,而服务端收到ACK包后,立即关闭连接,这是第四次挥手。
Q:为什么客户端需要等待超时时间?
A:为了保证对方已收到ACK包,因为假设客户端发送完最后一包ACK包后就释放了连接,一旦ACK包在网络中丢失,服务端将一直停留在最后确认状态;如果客户端发送最后一包ACK包后,等待一段时间,这是服务端会因为没有收到ACK包会重发FIN包,客户端会响应这个FIN包重发ACK包并刷新超时时间。这个机制跟三次握手一样,也是为了保证在不可靠的网络链路中进行可靠的连接断开确认。
相关文章:

美团Java开发一面凉经
目录 1.HashMap底层数据结构2.列举几个常见的线程安全容器3.HashMap线程问题4.concurrentHashMap5.ConcurrentModificationException6.Spring AOP、IOC、DI介绍下7.不使用依赖注入,使用传统方式的声明会有什么问题8.最左前缀原则9.TCP三次握手、四次挥手 1.HashMap底…...
Java面试知识点(全)-spring面试知识点二
Java面试知识点(全) 导航: https://nanxiang.blog.csdn.net/article/details/130640392 注:随时更新 Spring 事物 事务简介: 事务管理是企业级应用程序开发中必不可少的技术,用来确保数据的完整性和一致性 事务就是一系列的动作&…...

【音视频开发】基础知识:视频封装格式和编码格式
文章目录 一、封装格式与编码格式的关系视频编码格式视频封装格式MP43GPRM、RMVBAVI、WMVVOBFLVMKVWebMMOVTS 封装格式与编码格式对应 一、封装格式与编码格式的关系 视频编码格式和视频封装格式的关系及区别 这两者的关系好比酒与酒瓶的关系,编码格式好比酒瓶里的…...
OData Web API 一个开放标准的协议
OData Web API 是一个开放标准的协议,用于创建和使用基于 RESTful 的 Web API。它允许开发人员通过统一的方式来发布、查询、操作和管理数据资源。 OData Web API 基于 OData 协议,该协议定义了一组规范和约定,用于建立与数据源交互的标准化…...

PT100温度采集
1、信号采集的基本原理 PT100是将温度信号转换为电阻输出,其电阻值变化范围为0~200Ω。AD转换器只能对电压进行转换,无法采集直接采集温度,因此,需要一个1mA恒电流源给PT100供电,将电阻变化转换为电压变化。使用恒流源…...

ThinkSystem DM 全闪存阵列 —— 通过全闪存 NVMe 转型加速您的业务
ThinkSystem DM 全闪存阵列——通过全闪存 NVMe 转型加速您的业务 挑战 要缩短产品上市时间并提高客户满意度,企业必须不断改善关键业务运营的速度和响应能力。其中的一个关键要素是全闪存存储,它可以大幅加速关键工作负载。 不过,随着全闪…...

SpringCloud------代码demo(二)
SpringCloud------代码demo(二) 编码实操 以订单——支付微服务模块作为基础,开始逐渐扩充 微服务架构编码构建 1.约定 > 配置 > 编码 2.IDEA新建project工作空间 3.Rest微服务工程构建 总父工程 POM project module 首先创建maven项…...
TCL语法
目录 脚本、命令和单词符 置换 变量置换 命令置换 反斜杠置换 双引号和花括号 注释 脚本、命令和单词符 一个 TCL 脚本可以包含一个或多个命令。命令之间必须用换行符或分号隔开。 set a 1 set b 2 或者 set a 1;set b 2 都是合法的 TC…...

Partial convolution Gated convolution
组会讨论帖 1. 图像修复 图像修复(Image Inpainting),顾名思义,就是将图像中损坏的部分修复起来,是一种图像编辑技术,可以应用在移除物体、修复老照片、图像补全(eg,地震插值)等等。…...

量化投资 无套利 No-arbitrage
文章目录 量化投资 无套利 No-arbitrageState of Nature市场域 Market Span 套利 Arbitrage无套利和正线性定价规则 No-arbitrage and Positive Linear Pricing RuleImplication 1: One-price PrincipleImplication 2: PositivityImplication 3: AdditivityImplication 4: Homo…...

小程序容器助力智能移动门户统一
智能移动统一门户遵循“统一规划,统一标准,统一建设,统一运维”的指导思想。它灵活运用前端展示平台,微服务后端平台,流程引擎,规则引擎,非结构化数据平台,即时通讯平台,…...

opencv-python相机标定详解
文章目录 角点检测查看角点标定 opencv中内置了张正友的棋盘格标定法,通过一些姿态各异的棋盘格图像,就能标定相机的内外参数。 角点检测 第一步是角点检测,首先需要读取棋盘格图像 import numpy as np import cv2 import ospath imgs #…...

由斯坦福、Nautilus Chain等联合主办的 Hackathon 活动,现已接受报名
由 Stanford Blockchain Accelerator、Zebec Protocol、 Nautilus Chain、Rootz Lab 共同主办的黑客松活动,现已接受优秀项目提交参赛申请。 在加密行业发展早期,密码极客们就始终在对区块链世界基础设施,在发展方向的无限可能性进行探索。而…...
PBDB Data Service:Measurements of specimens(标本测量)
Measurements of specimens(标本测量) 描述参数以下参数可用于指定您感兴趣的标本种类以下参数可用于筛选所选内容以下参数还可用于根据分类筛选结果列表以下参数可用于生成数据存档您可以使用以下参数选择要检索的额外信息,以及要获取记录的…...

低调的接口工具 ApiKit
最近发现一款接口测试工具--ApiKit,我们很难将它描述为一款接口管理工具 或 接口自测试工具。 官方给了一个简单的说明,更能说明 Apikit 可以做什么。 ApiKit API 管理 Mock 自动化测试 异常监控 团队协作 ApiKit的特点: 接口文档定义&a…...

opengauss 的回归测试
目录 一、回归测试说明 二、单独执行测试用例(开发调试) 一、回归测试说明 opengauss/postgresql 的回归测试,通过执行SQL比较输出打印,判断代码修改是否改变了其它功能逻辑。 OG的回归测试大体上和PG类似,主要是通…...
计算机组成原理基础练习题第四章-计算机的运算方法
对真值0表示形式唯一的机器数是()。A、原码 B、补码和移码C、反码 D、以上都不对在整数定点机中,下述说法正确的是()。A、原码和反码不能表示-1,补码可以表示-1B、三种机器数均可表示-1C、三种机器数均可表示…...

SpringBoot定时任务里的多线程
SpringBoot定时任务里的多线程 提示前言遇到的问题验证与解决验证单线程执行单任务分析代码及结果 单线程执行多任务 解决实现单任务的多线程为每个任务创建一个子线程 解决多任务的多线程设定固定容量线程池动态设定容量线程池固定线程池和动态线程池的选择 简单总结借鉴及引用…...

YOLO V3 SPP ultralytics 第二节:根据yolo的数据集,生成准备文件和yolo的配置文件
目录 1. 介绍 2. 完整代码 3. 代码讲解 3.1 生成 my_train_data.txt和my_val_data.txt 3.2 生成 my_data.data 文件 3.3 生成 my_yolov3.cfg 3.4 关于my_data_label.names文件 1. 介绍 根据 第一节 的操作,已经生成了下图中圆圈中的部分,而本…...

camunda流程引擎connector如何使用
在 Camunda 中,Connector 是一种用于与外部系统或服务交互的机制。它允许 BPMN 模型中的 Service Task 节点与外部系统或服务进行通信,从而使流程更加灵活和可扩展。使用 Connector,可以将业务流程与外部系统集成在一起,而无需编写…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...

如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...

uniapp 小程序 学习(一)
利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 :开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置,将微信开发者工具放入到Hbuilder中, 打开后出现 如下 bug 解…...
Kafka主题运维全指南:从基础配置到故障处理
#作者:张桐瑞 文章目录 主题日常管理1. 修改主题分区。2. 修改主题级别参数。3. 变更副本数。4. 修改主题限速。5.主题分区迁移。6. 常见主题错误处理常见错误1:主题删除失败。常见错误2:__consumer_offsets占用太多的磁盘。 主题日常管理 …...

高考志愿填报管理系统---开发介绍
高考志愿填报管理系统是一款专为教育机构、学校和教师设计的学生信息管理和志愿填报辅助平台。系统基于Django框架开发,采用现代化的Web技术,为教育工作者提供高效、安全、便捷的学生管理解决方案。 ## 📋 系统概述 ### 🎯 系统定…...
在golang中如何将已安装的依赖降级处理,比如:将 go-ansible/v2@v2.2.0 更换为 go-ansible/@v1.1.7
在 Go 项目中降级 go-ansible 从 v2.2.0 到 v1.1.7 具体步骤: 第一步: 修改 go.mod 文件 // 原 v2 版本声明 require github.com/apenella/go-ansible/v2 v2.2.0 替换为: // 改为 v…...