5.3问题总结

一、设计模式理解

https://www.cnblogs.com/Kingyk/p/15368574.html
1、单例模式
1.1饿汉模式
一个类只允许创建一个实例(对象),在类加载时候就初始化好
特点:构造私有,静态创建实例,对外提供一个获取示例的方法
优点是:线程安全
缺点是:不支持延迟加载
1.2懒汉模式
特点:给获取实例方法了一把大锁(synchronzed),判断对象是否为空,为空才执行创建实例
优点:支持延迟加载
缺点:不支持高并发
1.3优化,示例判断为null时候才加锁,不给方法加,会引起指令重排
1.4静态内部类
instance 的唯一性、创建过程的线程安全性,都由 JVM 来保证。所以,这种实现方法既保证了线程安全,又能做到延迟加载。
2、原型模式
当要实例化的类是在运行时刻指定时;或者需要创建多个对象
深拷贝和浅拷贝问题
3、工厂模式
3.1、简单工厂
特点:定义一个用于创建对象的接口,让子类决定实例化哪一个类
不同的子类实现接口方法后,返回子类自己的示例对象,适用于:当一个类不知道它所必须创建的对象的类的时候
缺点:工厂模式需要额外创建很多 类,会增加代码的复杂性,
每个 Factory 类只是做简单的 new 操作,功能非常单薄,也没必要设计成独立的类
3.2、工厂方法
特点:工厂的工厂,定义一个静态的map,根据key匹配返回不同的对象
3.3、抽象工厂
定义一个用于创建对象的接口,让子类决定实例化哪一个类,不同于简单工厂的是适用于:一个系统要独立于它的产品的创建、组合时
不同的产品线继承相同的工厂,实现不同的方法,
4、适配器模式
它将不兼容的接口转换为可兼容的接口,让原本由于接口不兼容而不能一起工作的类可以一起工作
5、代理模式
代理模式可以对原有的类进行扩展
5.1静态代理
静态代理需要代理类与目标类有一样的继承父类和实现接口
特点:两个实现了同一个接口的类,一个类对另一个类对象可以做方法执行前后通知。
优点1.可以做到在不修改目标对象的功能前提下,对目标功能扩展.
缺点:
因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护.
5.2JDK动态代理
特点:动态代理需要使用newProxyInstance(ClassLoader loader方法,
好处:动态代理不用实现目标类的接口,不会出现大量代理类的现象,一般情况下创建一个代理类就可以了。
动态代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)
5.3CGLIB代理
上面的静态代理和动态代理模式都是要求目标对象是实现一个接口的目标对象,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以使用以目标对象子类的方式类实现代理,这种方法就叫做:Cglib代理

Cglib包的底层是通过使用一个小而块的字节码处理框架ASM来转换字节码并生成新的类.不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉.
6、构造者模式
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示,使用构造函数配合 set() 方法里面增加逻辑判断,返回不同的结果

一、设计模式六大原则

依赖倒转原则 :针对接口编程,依赖于抽象而不依赖于具体
开闭原则 :对扩展开放,对修改关闭
里氏代换原则 :任何基类可以出现的地方,子类一定可以出现
接口隔离原则 :高内聚低耦合
迪米特法则:最少知道原则 ,一个实体应当尽量少的与其它实体发生相互作用,使得功能模块相互独立
合成复用原则 :尽量使用合成或者聚合的方式,而不是使用继承

二、排序和他的时间复杂度

https://zhuanlan.zhihu.com/p/83756377
什么是排序算法稳定性?
假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的。
在这里插入图片描述

插入排序
通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
选择排序
在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
冒泡排序
重复走访要排序的序列,两两比较顺序错误就交换,依此类推,直到走完要排序序列,这时最大(最小)数浮动到数列末尾。
快速排序
又称划分交换排序。快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为较小和较大的2个子序列,然后递归地排序两个子序列。
步骤为:
挑选基准值:从数列中挑出一个元素,称为“基准”。
分割:重新排序数列,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基准后面(与基准值相等的数可以到任何一边)。在这个分割结束之后,对基准值的排序就已经完成。

堆排序
新建堆然后从堆中逐条取出元素。

归并排序
建立在归并操作基础上的一种有效排序方式,采用分治法:比较队列头部的大小然后合并

二、四种常用查找算法

https://blog.csdn.net/AJ_007/article/details/106109437
线性查找:
数组遍历的工程,找到了就返回下标,没有就返回-1,有序无序
二分查找:
一半一半的向要查找的值趋近,就想猜数游戏,大了,那你就猜比你小一半的数,适用于有序数组
插值查找:
适用于有序数组
斐波那契出擦找:
适用于有序数组:

三、char和varchar的区别

1、char定长,不足的部分用空格补齐
varchar变长,

  1. char类型的长度是固定的,varchar的长度是可变的。

char类型时定长的类型,即当定义的是char(10),输入的是"abc"这三个字符时,它们占的空间一样是10个字节,包括7个空字节。当输入的字符长度超过指定的数时,char会截取超出的字符。而且,当存储char值时,MySQL是自动删除输入字符串末尾的空格。

char是适合存储很短的、一般固定长度的字符串。例如,char非常适合存储密码的MD5值,因为这是一个定长的值。对于非常短的列,char比varchar在存储空间上也更有效率。

varchar(n)类型用于存储可变长的,长度为n个字节的可变长度且非Unicode的字符数据。存储大小为输入数据的字节的实际长度+1/2. 比如varchar(10), 然后输入abc三个字符,那么实际存储大小为3个字节。除此之外,varchar还需要使用1或2个额外字节记录字符串的长度,如果列的最大长度小于等于255字节(是定义的最长长度,不是实际长度),则使用1个字节表示长度,否则使用2个字节来表示。

二:效率不同
1、char类型:char类型每次修改的数据长度相同,效率更高。
2、varchar类型:varchar类型每次修改的数据长度不同,效率更低。
三、存储不同
1、char类型:char类型存储的时候是初始预计字符串再加上一个记录字符串长度的字节,占用空间较大。
2、varchar类型:varchar类型存储的时候是实际字符串再加上一个记录字符串长度的字节,占用空间较小。

四、MYSQL组合索引在B+树数据结构中是如何排序的

五、MySQL查询执⾏过程详解

六、equals与==的区别

https://blog.csdn.net/qq_32521381/article/details/106188209
一、对象类型不同

1、equals():是超类Object中的方法。
2、==:是操作符。
二、比较的对象不同

1、equals():equals是Object中的方法,在Object中equals方法实际"ruturn (thisobj)“,用到的还是”“,说明如果对象不重写equals方法,实际该对象的equals和”“作用是一样的,都是比较的地址值(因为”"比较的就是地址值),但是大部分类都会重写父类的equals方法,用来检测两个对象是否相等,即两个对象的内容是否相等,例如String就重写了equals方法,用来比较两个字符串内容是否相同。

2、:用于比较引用和比较基本数据类型时具有不同的功能,比较引用数据类型时,如果该对象没有重写equals方法,则比较的是地址值,如果重写了,就按重写的规则来比较两个对象;基本数据类型只能用""比较两个值是否相同,不能用equals(因为基本数据类型不是类,不存在方法)。
三、运行速度不同
1、equals():没有运行速度快。
2、
:运行速度比equals()快,因为==只是比较引用。

七、函数式编程

https://blog.csdn.net/w584212179/article/details/112802273
函数式编程更加强调程序执行的结果而非执行的过程,倡导利用若干简单的执行单元让计算结果不断渐进,逐层推导复杂的运算,而不是设计一个复杂的执行过程。
体现在lambda表达式和stream流

八、可以重写static方法吗

1,可以被继承,但是不能被重写,如果父子类静态方法名相同,则会隐藏derive类方法(调用base类的方法)

2.静态方法是编译时绑定的,方法重写是运行时绑定的。
静态方法是类在加载时就被加载到内存中的方法,在整个运行过程中保持不变,因而不能重写。但非静态方法是在对象实例化时才单独申请内存空间,为每一个实例分配独立的运行内存,因而可以重写。

所谓静态就是在运行时,虚拟机已经认定此方法属于哪个类。
JAVA静态方法形式上可以重写,但从本质上来说不是JAVA的重写。因为静态方法只与类相关,不与具体实现相关,声明的是什么类,则引用相应类的静态方法

九、 MVCC原理

一、什么是MVCC
https://blog.csdn.net/Shmily_0/article/details/118389631
多版本控制: 指的是一种提高并发的技术。引入多版本之后,只有写写之间相互阻塞,其他三种操作都可以并行,这样大幅度提高了InnoDB的并发度。
MVCC只在已提交读(Read Committed)和可重复读(Repeatable Read)两个隔离级别下工作,其他两个隔离级别和MVCC是不兼容的。
MVCC的实现原理主要是依赖每一行记录中两个隐藏字段,undo log,ReadView

二、MVcc能解决什么问题,带来真么好处
多版本并发控制(MVCC)是一种用来解决读-写冲突的无锁并发控制,也就是为事务分配单向增长的时间戳,为每个修改保存一个版本,版本与事务时间戳关联,读操作只读该事务开始前的数据库的快照。 所以MVCC可以为数据库解决以下问题:

在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并发读写的性能。
同时还可以解决脏读,幻读,不可重复读等事务隔离问题,但不能解决更新丢失问题。

三、MVCC的实现原理主要是依赖记录中的 3个隐式字段,undo日志(或者说日志中的版本链) ,ReadView 来实现的。

1.隐式字段
每行记录除了我们自定义的字段外,还有数据库隐式定义的DB_TRX_ID,DB_ROLL_PTR,DB_ROW_ID等字段。

DB_TRX_ID
6byte,最近修改(修改/插入)事务ID:记录创建这条记录/最后一次修改该记录的事务ID。
DB_ROLL_PTR
7byte,回滚指针,指向这条记录的上一个版本(存储于rollback segment里)
DB_ROW_ID
6byte,隐含的自增ID(隐藏主键),如果数据表没有主键,InnoDB会自动以DB_ROW_ID产生一个聚簇索引。
实际还有一个删除flag隐藏字段, 为true时并不代表真的删除,而是删除flag变了(逻辑删除)

不同事务或者相同事务的对同一记录的修改,会导致该记录的undo log成为一条记录版本线性表,既链表,undo log的链首就是最新的旧记录,链尾就是最早的旧记录

Read View遵循一个可见性算法,主要是将要被修改的数据的最新记录中的DB_TRX_ID取出来,与系统当前其他活跃事务的ID去对比(由Read View维护),如果DB_TRX_ID跟Read View的属性做了某些比较,不符合可见性,那就通过DB_ROLL_PTR回滚指针去取出Undo Log中的DB_TRX_ID再比较,即遍历链表的DB_TRX_ID(从链首到链尾,即从最近的一次修改查起),直到找到满足特定条件的DB_TRX_ID, 那么这个DB_TRX_ID所在的旧记录就是当前事务能看见的最新老版本。

四、MVCC能否解决了幻读问题呢
MVCC能解决不可重复读问题,但是不能解决幻读问题,不论是快照读和当前读都不能解决。RR级别解决幻读靠的是锁机制,而不是MVCC机制。

十、Java1.7和1.8的区别

区别:jdk1.8中取消了永久代,取而代之的是Metaspace,这个空间不占用jvm虚拟机的内存,而是占用物理机的内存;jdk8新增了lambda表达式、访问局部变量、函数式接口等特性。

4、方法与构造函数引用,jdk1.8提供了另外一种调用方式::,当 你 需 要使用 方 法 引用时 , 目 标引用 放 在 分隔符::前 ,方法 的 名 称放在 后 面

1、default关键字,在接口中可以通过使用default关键字编写方法体,实现类可以不用实现该方法,可以进行直接调用

十、hashcode相等的两个对象一定==相等么?

两个对象==相等,则其hashcode一定相等,反之不一定成立。

两个对象equals相等,则其hashcode一定相等,反之不一定成立。【和上一条等价,因为Object的equals实现用的就是 对象的==相等来判断】

十一、重写equals不重写hashCode会存在什么问题

每个覆盖了equals方法的类中,必须覆盖hashCode。如果不这么做,就违背了hashCode的通用约定,也就是上面注释中所说的。如果重写equals不重写hashCode它与散列集合HashMap、HashSet、HashTable、ConcurrentHashMap)无法正常工作。

例如:hashmap它是通过计算Map key的hashCode值来确定在链表中的存储位置的(确定唯一性)。那么这样就可以推测出,如果我们重写了equals但是没重写hashCode,那么可能存在元素重复的矛盾情况。

十二、如何让10个线程按照顺序打印0123456789

https://blog.csdn.net/qq_35571554/article/details/82743952
设定一个orderNum,每个线程执行结束之后,更新orderNum,指明下一个要执行的线程。并且唤醒所有的等待线程。

在每一个线程的开始,要while判断orderNum是否等于自己的要求值!!不是,则wait,是则执行本线程。
@Override
public void run() {
// TODO Auto-generated method stub
//1、判断该资源是否被占用
synchronized(lobject){
//2、如果资源空闲,则判断是否已经打印完成
while(lobject.orderNum <= lobject.MaxValue){
//3、没有打印完则判断是否是自己需要打印的数字
if(lobject.orderNum == printNum){
System.out.print(printNum);
lobject.orderNum++;
if(lobject.orderNum==10){
System.out.println(“线程打印完毕”);
}
//打印完毕后,唤醒所有的线程
lobject.notifyAll();
}else{
//4、不是该线程打印的数字,则继续等待
try {
lobject.wait();
}

十三、进程间通信的方式有哪些

https://www.php.cn/faq/469981.html
1、管道通常指无名管道,
半双工即数据只能在一个方向上流动,
它只能用于具有亲缘关系的进程之间的通信
不是普通的文件,并不属于其他任何文件系统,并且只存在于内存中。
2、FIFO,是一种文件类型;
FIFO可以在无关的进程之间交换数据,与无名管道不同。
FIFO有路径名与之相关联,它以一种特殊设备文件形式存在于文件系统中。
3、消息队列,是消息的链接表,存放在内核中;
消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。
消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取
4、信号量,是一个计数器;
信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。
每次对信号量的 PV 操作不仅限于对信号量值加 1 或减 1,而且可以加减任意正整数。
信号量基于操作系统的 PV 操作,程序对信号量的操作都是原子操作。
支持信号量组。
5、共享内存。
指两个或多个进程共享一个给定的存储区

十四、怎么保证线程安全?

https://zhuanlan.zhihu.com/p/504400777
导致线程不安全的原因,主要有三点:

原子性:一个或者多个操作在CPU执行的过程中被中断
可见性:一个线程对共享变量的修改,另外一个线程不能立刻看到
有序性:程序执行的顺序没有按照代码的先后顺序执行。ava平台的两种编译器:静态编译器(javac)和动态编译器(jit:just in time)。
区别在于:
静态编译器是将.java文件编译成.class文件,之后便可以解释执行。
动态编译器是将.class文件编译成机器码,之后再由jvm运行。有时候,动态编译器为了程序的整体性能会对指令进行重排序,虽然重排序可以提升程序的性能,但是重排序之后会导致源代码中指定的内存访问顺序与实际的执行顺序不一样,就会出现线程不安全的问题。

下面简单谈谈针对以上的三个问题,java程序如何保证线程安全呢?
针对原子性问题:
JDK里面提供了很多atomic类,比如AtomicInteger、AtomicLong、AtomicBoolean等等:这些类本身可以通过CAS来保证操作的原子性,另外Java也提供了各种锁机制,来保证锁内的代码块在同一时刻只能有一个线程执行,比如使用synchronized加锁,这样,就能够保证一个线程在对资源进行读、改、写操作时,其他线程不可对此资源进行操作,:从而保证了线程的安全性。

针对可见性问题::同样可以通过synchronized关键字加锁来解决。与此同时,java还提供了volatile关键字,要优于synchronized的性能,同样可以保证修改对其他线程的可见性。volatile一般用于对变量的写操作不依赖于当前值的场景中,比如状态标记量等。

针对重排序问题:可以通过synchronized关键字定义同步代码块或者同步方法保障有序性,另外也可以通过Lock接口来保障有序性。

以上就是保证线程安全的方案!

十五、hashMap jdk1.7和jdk1.8的不同

整体结构和 JDK1.8 中的 HashMap 类似,相比 JDK1.7 中的 ConcurrentHashMap, 它抛弃了原有的 Segment 分段锁实现,采用了 CAS + synchronized 来保证并发的安全性。JDK1.8 中的 ConcurrentHashMap 对节点Node类中的共享变量,和 JDK1.7 一样,使用volatile关键字,保证多线程操作时,变量的可见行!

虽然 HashMap 在多线程环境下操作不安全,但是在 java.util.concurrent 包下,java 为我们提供了 ConcurrentHashMap 类,保证在多线程下 HashMap 操作安全!

在 JDK1.7 中,ConcurrentHashMap 采用了分段锁策略,将一个 HashMap 切割成 Segment 数组,其中 Segment 可以看成一个 HashMap, 不同点是 Segment 继承自 ReentrantLock,在操作的时候给 Segment 赋予了一个对象锁,从而保证多线程环境下并发操作安全。

但是 JDK1.7 中,HashMap 容易因为冲突链表过长,造成查询效率低,所以在 JDK1.8 中,HashMap 引入了红黑树特性,当冲突链表长度大于 8 时,会将链表转化成红黑二叉树结构。

在 JDK1.8 中,与此对应的 ConcurrentHashMap 也是采用了与 HashMap 类似的存储结构,但是 JDK1.8 中 ConcurrentHashMap 并没有采用分段锁的策略,而是在元素的节点上采用 CAS + synchronized 操作来保证并发的安全性,源码的实现比 JDK1.7 要复杂的多。、

十六、HashMap的底层结构和实现原理

十六、为什么扩容因子是0.75

泊松分布有关。
选择0.75作为默认的加载因子,完全是时间和空间成本上寻求的一种折衷选择。

十六、HashMap解决hash冲突

https://blog.csdn.net/weixin_26804345/article/details/113076248
当我们通过put(key, value)向hashmap中添加元素时,需要通过散列函数确定元素究竟应该放置在数组中的哪个位置,当不同的元素被放置在了数据的同一个位置时,后放入的元素会以链表的形式,插在前一个元素的尾部,这个时候我们称发生了hash冲突。

开放寻址法(开放定址法根据步长不同可以分为3种)
我们就重新探测一个空闲位置,再将元素插入。
线性探查法,平方探测法,伪随机探测法
缺点:
当冲突多的时候数据容易堆集在一起,这时候对查找不友好
删除结点的时候不能简单将结点的空间置空,否则将截断在它填入散列表之后的同义词结点查找路径。因此如果要删除结点,只能在被删结点上添加删除标记,而不能真正删除结点;

但我们往散列表中插入元素时,如果某个数据经过散列函数散列之后,存储位置已经被占用了,那么我们就从当前位置开始,依次往后遍历,直到找到空余的位置插入为止(插入第一个空余的位置,方便查找)
2. 再哈希法
,用于同义词发生地址冲突时,计算出另一个哈希函数地址,直到不发生冲突位置。这种方法不容易产生堆集,但是会增加计算时间。
所以再哈希法的缺点是:
增加了计算时间。

  1. 建立一个公共溢出区
    ,一旦发生冲突,不管他们哈希函数得到的哈希地址是什么,都填入溢出表。
    但这个方法的缺点在于:
    查找冲突数据的时候,需要遍历溢出表才能得到数据。

  2. 链地址法(拉链法)
    将冲突位置的元素构造成链表。在添加数据的时候,如果哈希地址与哈希表上的元素冲突,就放在这个位置的链表上。
    拉链法的优点:
    处理冲突的方式简单,且无堆集现象,非同义词绝不会发生冲突,因此平均查找长度较短;
    由于拉链法中各链表上的结点空间是动态申请的,所以它更适合造表前无法确定表长的情况;
    删除结点操作易于实现,只要简单地删除链表上的相应的结点即可。

十七、如何访问一个类的private方法

利用java反射机制得到类的属性和方法
Test test=new Test();
test.getclass.getfields();
test.getclass.getMothods();
够强制调用,但是并不推荐,因为它与面向对象的设计规则背道而驰。违背了我们当初的设计初衷。

十八、四个访问修饰符的区别

public:被public修饰的成员变量或者成员方法,可以直接被类的调用者使用

private:被private修饰的成员变量或者成员方法,不能被类的调用者使用

protected:对于类的子类和同一个包的其他类来说,protected修饰的字段和方法是可以访问的,对于类的调用者来说,protected修饰的字段和方法是不能访问的

无(default):同一个包内可以访问,包外不能访问

在这里插入图片描述

十九、java的基本数据类型,byte的最大最小值

数值型 byte 1字节 、short 2字节、 int 4个字节、 long 8个字节

布尔型 boolean (无字节,在内存中以byte数组类型存储,1个字节,8位)

字符型 float 4个字节、 double 8 个字节
byte范围:-128 到 127
在这里插入图片描述

基本数据类型转换 byte short char int long float double
隐式转换 小精度–>大精度 int->double
显式转换(强制转换) 大精度 – > 小精度 double->int 会出现精度丢失, 丢失原因: 小精度的数据类型没有能够容 纳大精度的位数,只能截取其大精度的最 后的位数。

十九、Java中final、finally和finalize的区别

https://blog.csdn.net/cyl101816/article/details/67640843/
1、final修饰符(关键字)。
被final修饰的类,不能作为父类而被子类继承。因此一个类不能既被abstract声明,又被final声明。
将变量或方法声明为final,可以保证他们在使用的过程中不被修改。被声明为final的变量必须在声明时给出变量的初始值,而在以后的引用中只能读取。
被final声明的方法也同样只能使用,即不能方法重写。

、finally是在异常处理时提供finally块来执行任何清除操作。不管有没有异常被抛出、捕获,finally块都会被执行。try块中的内容是在无异常时执行到结束。catch块中的内容,是在try块内容发生catch所声明的异常时,跳转到catch块中执行。finally块则是无论异常是否发生,都会执行finally块的内容,所以在代码逻辑中有需要无论发生什么都必须执行的代码,就可以放在finally块中。

3、finalize是方法名。java技术允许使用finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在object类中定义的,因此所有的类都继承了它。子类覆盖finalize()方法以整理系统资源或者被执行其他清理工作。finalize()方法是在垃圾收集器删除对象之前对这个对象调用的。

二十、Spring Boot有哪些常用注解?

https://www.cnblogs.com/October-28/p/15655723.html
@SpringBootApplication、@Repository、@Service、@RestController、@ResponseBody、@Component、@ComponentScan等等。

二一、mysql b+树的查找算法

树可以进行两种查找运算:一种是利用 sqt 链表做顺序查找,另一种是从树的根结点开始,进行类似于二分查找的查找方式。

在 B+树中,所有非叶子节点都相当于是叶子节点的索引,而所有的关键字都存放在叶子节点中,所有在从根节点出发做查找操作时,如果非叶子节点上的关键字恰好等于给定值,此时并不算查找完成,而是要继续向下直到叶子节点。

B+树的查找操作,无论查找成功与否,每次查找操作都是走了一条从根结点到叶子结点的路径。

二二、堆排序原理

一个完全二叉树,其特点在于:

从作为第一层的根开始,除了最后一层之外,第N层的元素个数都必须是2的N次方;第一层2个元素,第二层4个,第三层8个,以此类推。
而最后一行的元素,都要紧贴在左边,换句话说,每一行的元素都从最左边开始安放,两个元素之间不能有空闲,具备了这两个特点的树,就是一棵完全二叉树。
那么,完全二叉树与堆有什么关系呢?

我们假设有一棵完全二叉树,在满足作为完全二叉树的基础上,对于任意一个拥有父节点的子节点,其数值均不小于父节点的值;这样层层递推,就是根节点的值最小,这样的树,称为小根堆。

1.首先将待排序的数组构造成一个大根堆,此时,整个数组的最大值就是堆结构的顶端

2.将顶端的数与末尾的数交换,此时,末尾的数为最大值,剩余待排序数组个数为n-1

3.将剩余的n-1个数再构造成大根堆,再将顶端数与n-1位置的数交换,如此反复执行,便能得到有序数组
在这里插入图片描述

二三、Java注解究竟是如何起作用的及注解的基本概念

注解实际上就是一个标签
它的定义方式是@interface
注解实际上就是使用反射实现的

当我们注明一个注解的时候,只是制造出了一个标签
当我们给一个类加上注解的时候,就是给这个对象贴上了某个标签
然后实现一个方法:通过反射得到一个对象,然后判断对象上是否有此注解,如果有再进行相应的操作,通过反射我们可以得到这个对象的所有信息,所以想要进行什么操作也是可以的。
元注解基本概念:
元注解是负责对其它注解进行说明的注解,自定义注解时可以使用元注解。Java 5 定义了 4 个注解,分别是 @Documented、@Target、@Retention 和 @Inherited。Java 8 又增加了 @Repeatable 和 @Native 两个注解。
@Documented 注解修饰的注解类会被 Javadoc 工具提取成文档
@Target 注解用来指定一个注解的使用范围,
@Retention 用于描述注解的生命周期,
@Inherited 是一个标记注解,用来指定该注解可以被继承

二四、SQL查询时的join与where筛选比较

https://blog.csdn.net/cillent_boy/article/details/84314114

on是查询后在连接,where是连接后在查询
在使用left jion时,on和where条件的区别如下:

1、 on条件是在生成临时表时使用的条件,它不管on中的条件是否为真,都会返回左边表中的记录。

2、where条件是在临时表生成好后,再对临时表进行过滤的条件。这时已经没有left join的含义(必须返回左边表的记录)了,条件不为真的就全部过滤掉。

ON与where的使用一定要注意场所:

(1):ON后面的筛选条件主要是针对的是关联表【而对于主表刷选条件不适用】。

(2):对于主表的筛选条件应放在where后面,不应该放在ON后面。

(3):对于关联表我们要区分对待。如果是要条件查询后才连接应该把查询件放置于ON后。

            如果是想在连接完毕后才筛选就应把条件放置于where后面。

(4): 对于关联表我们其实可以先做子查询再做join

二五、ReentrantLock原理分析
https://blog.csdn.net/qq_43049310/article/details/121038549
表示重入锁,它是唯一一个实现了 Lock 接口的类。重入锁指的是线程在获得锁之后,再次获取该锁不需要阻塞,而直接关联一次计数器增加重入次数
ReentrantLock主要利用CAS+AQS队列来实现。它支持公平锁和非公平锁

AQS 是什么
在 Lock 中,用到了一个同步队列 AQS
AQS 的两种功能
从使用层面来说,AQS 的功能分为两种:独占和共享
独占锁,每次只能有一个线程持有锁,比如前面给大家演示的 ReentrantLock 就是以独占方式实现的互斥锁
共 享 锁 , 允 许 多 个 线 程 同 时 获 取 锁 , 并 发 访 问 共 享 资 源 , 比 如ReentrantReadWriteLock

AQS 的内部实现
AQS 队列内部维护的是一个 FIFO 的双向链表,这种结构的特点是每个数据结构都有两个指针,分别指向直接的后继节点和直接前驱节点。所以双向链表可以从任意一个节点开始很方便的访问前驱和后继。每个 Node 其实是由线程封装,当线程争抢锁失败后会封装成 Node 加入到 ASQ 队列中去;当获取锁的线程释放锁以后,会从队列中唤醒一个阻塞的节点(线程)。
CAS 的实现原理
通过 cas 乐观锁的方式来做比较并替换,这段代码的意思是,如果当前内存中的state 的值和预期值 expect 相等,则替换为 update。更新成功返回 true,否则返回 false.
这个操作是原子的,不会出现线程安全问题,这里面涉及到Unsafe这个类的操作,以及涉及到 state 这个属性的意义。state 是 AQS 中的一个属性,它在不同的实现中所表达的含义不一样,对于重入锁的实现来说,表示一个同步状态。它有两个含义的表示
CAS
当 state=0 时,表示无锁状态
当 state>0 时,表示已经有线程获得了锁,也就是 state=1,但是因为
ReentrantLock 允许重入,所以同一个线程多次获得同步锁的时候,state 会递增,比如重入 5 次,那么 state=5。而在释放锁的时候,同样需要释放 5 次直到 state=0其他线程才有资格获得锁

CAS:Compare and Swap,比较并交换。CAS有3个操作数:内存值V、预期值A、要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。该操作是一个原子操作,被广泛的应用在Java的底层实现中。在Java中,CAS主要是由sun.misc.Unsafe这个类通过JNI调用CPU底层指令实现

Unsafe 类
Unsafe 类是在 sun.misc 包下,不属于 Java 标准。但是很多 Java 的基础类库,包括一些被广泛使用的高性能开发库都是基于 Unsafe 类开发的,比如 Netty、Hadoop、Kafka 等;

Unsafe 可认为是 Java 中留下的后门,提供了一些低层次操作,如直接内存访问、线程的挂起和恢复、CAS、线程同步、内存屏障而 CAS 就是 Unsafe 类中提供的一个原子操作,第一个参数为需要改变的对象,第二个为偏移量(即之前求出来的 headOffset 的值),第三个参数为期待的值,第四个为更新后的值整个方法的作用是如果当前时刻的值等于预期值 var4 相等,则更新为新的期望值 var5,如果更新成功,则返回 true,否则返回 false;

ReentrantLock的基本实现可以概括为:先通过CAS尝试获取锁。如果此时已经有线程占据了锁,那就加入AQS队列并且被挂起。当锁被释放之后,排在CLH队列队首的线程会被唤醒,然后CAS再次尝试获取锁。在这个时候,如果:

非公平锁:如果同时还有另一个线程进来尝试获取,那么有可能会让这个线程抢先获取;

公平锁:如果同时还有另一个线程进来尝试获取,当它发现自己不是在队首的话,就会排到队尾,由队首的线程获取到锁。

二五、Spring IoC和AOP的实现原理解析
https://cloud.tencent.com/developer/article/1846138
https://baijiahao.baidu.com/s?id=1713404380069820518&wfr=spider&for=pc

控制反转(IoC),即上层控制下层,而不是下层控制着上层。我们用依赖注入(Dependency Injection)这种方式来实现控制反转。所谓依赖注入,就是把底层类作为参数传入上层类,实现上层类对下层类的“控制”。
IOC容器的是通过:工厂 + 反射,实现的。
通过一张图来给大家讲解SpirngIOC的实现原理(基于XML配置文件)
在这里插入图片描述

spring IOC相关的类:
BeanDefinition:容器中每一个bean都有一个相对应的BeanDefinition实例,该实例负责保存bean对象的所有必要信息,包括bean对象的class类型、是否是抽象类、构造方法和参数、其它属性等等。当客户端向容器请求相应对象时,容器就会通过这些信息为客户端返回一个完整可用的bean实例。
BeanDefinitionRegistry:抽象出bean的注册逻辑,bean对象对应的 BeanDefinition实例会在BeanDefinitionRegistry中进行注册。
BeanFactory:抽象出了bean的管理逻辑,而各个BeanFactory的实现类就具体承担了bean的注册以及管理工作

(1)IOC之容器启动阶段 这个阶段主要会进行:加载配置文件并解析,然后将解析后的数据封装为BeanDefinition实例,最后把这些保存了bean定义的BeanDefinition,注册到相应的BeanDefinitionRegistry,这样容器的启动工作就完成了。当然这个过程还包含了其他很多操作。 (2)IOC之容器实例化阶段 当某个请求通过容器的getBean方法请求某个对象,或者因为依赖关系容器需要隐式的调用getBean时,就会触发第二阶段的活动:容器会首先检查所请求的对象之前是否已经实例化完成。如果没有,则会根据注册的BeanDefinition所提供的信息实例化被请求对象,并为其注入依赖。当该对象装配完毕后,容器会立即将其返回给请求方法使用。

3.Spring AOP底层原理
  Spring AOP全称为Spring Aspect-Oriented Programming,即面向切面编程,是运行时织入的,那么运行时织入到底是怎么实现的呢?答案就是代理对象。代理对象又可以分为静态代理和动态代理。
  动态代理:在程序运行时,运用反射机制动态创建而成。
  生成的代理类的所有方法都拦截了目标类的所有的方法。而拦截器中invoke方法的内容正好就是代理类的各个方法的组成体;

利用JDK代理方式必须有接口的存在。

3.2.2 CGLib代理模式
  CGLib采用非常底层的字节码技术,可以为一个类创建子类,并在子类中采用方法去技术拦截所有的父类方法的调用,并顺势织入横切逻辑。

CGLib和JDK的原理类似,也是通过方法去反射调用目标对象的方法。

二五、springboot启动原理

https://baijiahao.baidu.com/s?id=1711888823130753987&wfr=spider&for=pc
SpringBoot整个启动流程分为两个步骤:初始化一个SpringApplication对象、执行该对象的run方法。

1、初始化流程中最重要的就是通过SpringFactoriesLoader找到spring.factories文件中配置的ApplicationContextInitializer和ApplicationListener两个接口的实现类名称,以便后期构造相应的实例,ApplicationContextInitializer的主要目的是在ConfigurableApplicationContext做refresh之前,对ConfigurableApplicationContext实例做进一步的设置或处理。
ApplicationListener的目的就没什么好说的了,它是Spring框架对Java事件监听机制的一种框架实现。

Spring Boot应用的整个启动流程都封装在SpringApplication.run方法中,本质上其实就是在spring的基础之上做了封装,做了大量的扩张。
//1.通过SpringFactoriesLoader查找并加载所有的SpringApplicationRunListeners,通过调用
//starting()方法通知所有的SpringApplicationRunListeners:应用开始启动了

//2.创建并配置当前应用将要使用的Environment(用于描述应用程序当前的运行环境)
//3.打印banner
//4.根据是否是web项目,来创建不同的ApplicationContext容器
//5.创建一系列FailureAnalyzer(分析故障并提供相关诊断信息)
//6.初始化ApplicationContext
//7.调用ApplicationContext的refresh()方法,刷新容器
//8.查找当前context中是否注册有CommandLineRunner和ApplicationRunner,如果有则遍历执行它们。

二六、如何自定义 Spring Boot Starter

https://blog.csdn.net/gozhuyinglong/article/details/123227882
1 Starter 是什么
Spring Boot 的 Starter 是一组比较方便的依赖描述符,可以通过 Maven 将其打成jar包,并在你的项目中直接引用。
通过 Starter 你可以获取该功能的所有依赖,以及统一的配置,避免了复制、粘贴代码和依赖带来的麻烦。
Starter 主要使用了自动配置,所以它下面的所有组件会被 Spring Boot 通过META-INF/spring.factories文件注入IOC容器中。

2.1 Starter 项目的命名规范
所有由Spring官方提供的Starter都会遵循spring-boot-starter-*的命名规范

3.2 POM中引入相关依赖
在POM中引入两个依赖:
spring-boot-starter:该依赖是 Starter 的核心,包括自动配置、日志和YAML的支持。我们所有自定义的 Starter 都应该直接或间接的引入该依赖。
spring-boot-configuration-processor:包含一个 Java 注解处理器,当使用@ConfigurationProperties注解配置自己的元数据时,需要引入此依赖。

3.3 定义一个配置元数据类
自定义一个配置元数据类DemoProperties,用于映射YAML中的配置,使用@ConfigurationProperties注解需要指定配置项的前缀,此处的前缀为demo。当前配置项只有一个type字段,用于配置宠物的类型,那么该配置项的 Key 为:demo.type。

3.4 定义一个实体类
先看自定义的宠物实体类Pet,很简单,只有一个name属性(此类纯属为了演示 Starter,无它)。

3.5 增一个配置类DemoAutoConfiguration,该类也非常简单:
使用@Configuration注解声明该类为一个配置类;
使用@EnableConfigurationProperties(DemoProperties.class)注解,引入自定义的配置元数据DemoProperties
声明了一个Pet的 Bean,根据配置项中的type来返回不同的宠物。使用该 Bean 的目的,主要是用来演示 Starter 的自动配置。
@Bean
public Pet pet() {

3.5 定义自动配置的候选
在resources资源目录中增加文件META-INF/spring.factories,并将自定义的配置类DemoAutoConfiguration加入到自动配置类列表中,

Spring Boot 会检查所有发布的jar中是否包含META-INF/spring.factories文件,并将该文件中目标类注入IOC容器中,自动配置类就是使用这种方式加载的。--------------------------------------去看二七:SpringBoot自动配置原理

4 使用 Starter:引入自定义 Starter 依赖,创建启动类,配置“宠物”的类型,创建一个 Controller 类

二七、SpringBoot自动配置原理

https://mp.weixin.qq.com/s/UXNcTOpjx9cr4kd4ECPg6g
Spring Boot 的自动配置可以根据添加的jar依赖,自动配置 Spring Boot 应用程序
1、我们知道在Spring Boot 项目中,都会有一个@SpringBootApplication注解,它标识了该项目的启动类。该注解是一个组合注解,其中有一个@EnableAutoConfiguration注解,用于启用自动配置。

2、我们进入@EnableAutoConfiguration注解可以看到,通过@Import注解导入了AutoConfigurationImportSelector类,从类名可以看出,该类是通过实现ImportSelector接口来导入配置类的。

3、该方法用于获取所有配置类的名字,最终是通过SpringFactoriesLoader加载器来获取的,SpringFactoriesLoader加载器
该类是 Spring 核心提供的一种类加载方式,用于加载资源文件META-INF/spring.factories中配置的类。loadFactoryNames()方法用于加载所有类的名字。

4、进入loadSpringFactories()静态方法,用于加载资源文件META-INF/spring.factories中配置的类。加载的类会放到缓存中,下次会直接从缓存中获取。

5、META-INF/spring.factories资源文件。这个资源文件中,包含了所有的自动配置类。文档内容必须是Properties格式,其中键是接口或抽象类的全类名,值是用逗号分隔的实现类列表

二七、SpringBoot Starter原理(依赖引入,自动配置)

http://www.51gjie.com/javaweb/1048.html
依赖引入
spring-boot-starter 核心Spring Boot starter,包括自动配置支持,日志和YAML,
spring-boot-starter-web 对全栈web开发的支持, 包括Tomcat和spring-webmvc。
依赖spring-boot-starter-web,springboot会根据需要自动引入jar包。

自动配置
我们引入starter的依赖,会将自动配置的类的jar引入。@SpringBootApplication的注解中有一个是@EnableAutoConfiguration注解,这个注解有一个@Import({EnableAutoConfigurationImportSelector.class}),EnableAutoConfigurationImportSelector内部则是使用了SpringFactoriesLoader.loadFactoryNames方法进行扫描具有META-INF/spring.factories文件的jar包。而自动配置类的jar的是有一个META-INF/spring.factories文件内容如

应用在启动时就会加载spring-boot-autoconfigure的jar包下面的META-INF/spring.factories文件中定义的autoconfiguration类。将configuration类中定义的bean加入spring到容器中。就相当于加载之前我们自己配置组件的xml文件。而现在SpringBoot自己定义了一个默认的值,然后直接加载进入了Spring容器。

二八、springboot原理(核心原理)

http://www.51gjie.com/javaweb/1041.html
SpringBoot是一个快速开发框架,快速的将一些常用的第三方依赖整合(原理:通过Maven子父工程的方式),简化XML配置,全部采用注解形式,内置Http服务器(Jetty和Tomcat),最终以java应用程序进行执行,它是为了简化Spring应用的创建、运行、调试、部署等而出现的,使用它可以做到专注于Spring应用的开发,而无需过多关注XML的配置。

  1. SpringBoot核心通过Maven继承依赖关系快速整合第三方框架
    1. 基于SpringMVC无配置文件(纯Java)完全注解化实现SpringBoot框架,Main函数启动。

二八、ConcurrentHashMap和Hashtable的区别(线程安全和并发性性)

https://blog.csdn.net/love_somnus_/article/details/63686037
Hashtable和ConcurrentHashMap有什么分别呢?它们都可以用于多线程的环境,但是当Hashtable的大小增加到一定的时候,性能会急剧下降,因为迭代时需要被锁定很长的时间。因为ConcurrentHashMap引入了分割(segmentation),不论它变得多么大,仅仅需要锁定map的某个部分,而其它的线程不需要等到迭代完成才能访问map。简而言之,在迭代的过程中,ConcurrentHashMap仅仅锁定map的某个部分,而Hashtable则会锁定整个map。

二九、LinkedList和ArrayList在尾部插入数据效率对比

https://blog.csdn.net/qq_28817739/article/details/87740998
因为每次都是在尾部插入数据,而LinkedLiist里面有一个last指针一直指向最后一个元素,而ArrayList则根据索引来找到最后一个元素,那么,这两个方式中,效率应该是差不多的;

但是实验结果却不是这样的;
原来 LinkedList每次增加的时候,会new 一个Node对象来存新增加的元素,所以当数据量小的时候,这个时间并不明显,而ArrayList需要扩容,所以LinkedList的效率就会比较高,其中如果ArrayList出现不需要扩容的时候,那么ArrayList的效率应该是比LinkedList高的,当数据量很大的时候,new对象的时间大于扩容的时间,那么就会出现ArrayList’的效率比Linkedlist高了。

三十、一致性哈希算法

https://www.zsythink.net/archives/1182
其实,一致性哈希算法也是使用取模的方法,只是,刚才描述的取模法是对服务器的数量进行取模,而一致性哈希算法是对2^32取模

一致性哈希算法的优点,如果使用之前的hash算法,服务器数量发生改变时,所有服务器的所有缓存在同一时间失效了,而使用一致性哈希算法时,服务器的数量如果发生改变,并不是所有缓存都会失效,而是只有部分缓存会失效,前端的缓存仍然能分担整个系统的压力,而不至于所有压力都在同一时间集中到后端服务器上。

产生的问题:hash环的偏斜
“虚拟节点”是”实际节点”(实际的物理服务器)在hash环上的复制品,一个实际节点可以对应多个虚拟节点。以便减小hash环偏斜所带来的影响,虚拟节点越多,hash环上的节点就越多,缓存被均匀分布的概率就越大。

三二、Java中的String类能否被继承?为什么?以及final和static的区
不能被继承,因为String类有final修饰符,而final修饰的类是不能被继承的。

Static修饰的成员属性和成员方法是和类相关的,没有Static修饰的成员方法和属性是和对象相关的。
Static修饰的成员变量属于全局变量,所有对象共享这个成员变量。(用类名调用)
Static修饰的成员方法内部只能用Static修饰的变量和方法。
Static修饰的代码块,是在类加载时使用。因为虚拟机对类只加载一次,在构造方法之前执行。

3.什么时候变量声明为实例的,什么时候声明为静态的?
如果这个类型的所有对象的某个属性值都是一样的,不建议定义为实例变量,浪费内存空间。
建议定义为类级别特征,定义为静态变量,在方法区中只保留一份,节省内存开销。

一个对象一份的是实例变量。
所有对象一份的是静态变量。
静态变量在类加载时初始化,不需要new对象,静态变量的空间就开出来了。
静态变量存储在方法区。

三一、MySQL查询执⾏过程详解一、执行一个查询过程概述

2服务器先检查查询缓存,如果命中了缓存,则立即返回存储在缓存中的结果。否则进入下一阶段;
3.服务器端进行SQL解析、预处理,再由优化器生成对应的执行计划;
4.MySQL根据优化器生成的执行计划,调用存储引擎的API来执行查询;
5.将结果返回给客户端;

三一、sql

–用一条SQL语句查询出每门课都大于80分的学生姓名
select distinct name from aa where name not in (select distinct name from aa where fengshu<=80)

,查找所有课程成绩90分以上的学生姓名。
select name from student group by name having min(score) >= 90

,查找平均成绩大于等于成绩90分以上的学号和平均成绩。
select sid,agv(score) from student group by sid having agv(score) >= 90

查询平均分大于80的学生名单:
1 select name from (
2 select count() t, sum(score) num, name from grade group by name
3 ) as a where a.num>80
t;

https://blog.csdn.net/weixin_36210213/article/details/113515662
下面我们就来实现三个表的联合查询,查询出文件的所有信息的所有信息:

select * from wenjian,admin_group,sort where wenjian.group_id=admin_group_id and admin_group.sort_id=sort.sort_id order by wenjian.wenjian_id DESC;(这里我们把文件表作为主表来查询)

如果我们只是想要文件表中的所有信息,其他两个表中的部分信息,那么我们可以把sql与剧中的 * 替换为wenjian.*,admin_group.group_name,sort.sort_name

如果要实现两个表的联合查询,我们就要用到left join on了,这次我们要查询文件表里面的所有信息与分类表的分类名,查询语句如下:

select w.*,sort.sort_name from wenjian as w left join sort as s on w.sort_id=s.sort_id order by w.wenjian_id dese

MySQL查询每个部门的员工个数
问题:查询每个部门的员工个数

注意!某些部门可能是没有员工的(员工个数为0)。(事实上是department_id在120之后的那些部门)
这时候如果简单利用连接查询并分组,将会使得员工个数为0的部门不会被查询出来。

SELECT e.department_id,COUNT(*)
FROM employees e
JOIN departments d ON e.department_id = d.department_id
GROUP BY e.department_id;

三二、bean属性注入的方式

三三、「spring」依赖注入之@Autowired寻找能注入的Bean

https://baijiahao.baidu.com/s?id=1725296676744401135&wfr=spider&for=pc
@Autowired源码分析:
find Autowire Candidates(找到自动装配的候选人)
这个方法是依赖注入的核心!
先ByType后ByName,所以现在市面上认为@Autowired是ByType方式进行注入的!

1、找出BeanFactory中类型为type的所有的Bean的名字,注意是名字,
( result CollectionUtils.newLinkedHashMap(Names.length))
2、把resolvableDependencies中key为type的对象找出来并添加到result中
// 这里会生成一个Bean的名字,放到缓存中的是没有Bean的名字的
// 类型匹配,将当前值添加进去
if (requiredType.isInstance(autowiringValue)) {
result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
break;
}

3、遍历根据type找出的beanName,判断当前beanName对应的Bean是不是能够被自动注入

先判断beanName对应的BeanDefinition中的autowireCandidate属性,如果为false,表示不能用来进行自动注入,如果为true则继续进行判断

4、判断当前type是不是泛型,如果是泛型是会把容器中所有的beanName找出来的,如果是这种情况,那么在这一步中就要获取到泛型的真正类型,然后进行匹配,如果当前beanName和当前泛型对应的真实类型匹配,那么则继续判断

5、如果当前DependencyDescriptor上存在@Qualifier注解,那么则要判断当前beanName上是否定义了Qualifier,并且是否和当前DependencyDescriptor上的Qualifier相等,相等则匹配

经过上述验证之后,当前beanName才能成为一个可注入的,添加到result中

三三、依赖注入的源码分析

https://blog.csdn.net/m0_47954009/article/details/122216577
调用了getBean起的是一个起点的作用,在里面主要完成了缓存判断的事情,缓存中不存在就进行createBean方法来创建Bean
这里是使用CGLIB对Bean进行实例化,

三三、IOC容器初始化概述

https://blog.csdn.net/m0_47954009/article/details/122132678
IOC容器初始化是由refresh()方法来启动的,这个方法标志着IOC容器的正式启动。Spring将IOC容器启动的过程分开,并使用不同的模块来完成,如使用ResourceLoader,BeanDefinition等模块, IOC容器的启动主要包括三个过程:

Resource加载过程:
Resource定位指beanDefinition的资源定位,由ResourceLoader通过统一的Resource接口来完成,这个Resource对各种形式的BeanDefinition的使用都提供了统一的接口。这个过程类似于容器寻找数据的过程。

BeanDefinition的载入:
BeanDefinition载入过程指的是把用户定义好的Bean表示为容器内部的数据结构,这个容器的数据结构其实就是BeanDefinition。实际上BeanDefinition就是POJO对象在容器的抽象,通过BeanDefinition来定义的数据结构,像是世间万物在java中的抽象,java的对象又在容器中的抽象就是BeanDefinition。

向容器注册BeanDefinition:
这个注册过程是通过调用BeanDefinitionRegistry接口来完成的,就是把载入过程中解析得到的BeanDefinition向IOC容器进行注册。通过下面的源码可以得到,注册过程就是在IOC容器将BeanDefinition注入到一个HashMap中,IOC容器就是通过这个HashMap来持有BeanDefinition数据的。

三三、log4j的源码分心

https://blog.csdn.net/qq_39326472/article/details/122569260
https://blog.csdn.net/qq_39326472/article/details/122569260
关键的功能类
LogManager:Log4j日志系统的入口类,最通用的用途是通过getLogger方法向外提供Logger类

LoggerContextFactry:用来定位ContextSelector的工厂,并通过getContext方法向外提供LoggerContext类

LoggerContext:维护应用程序请求的所有Logger的列表和对Configuration的引用。配置记录器、附加器、过滤器等,并在重新配置时自动更新。通过getLogger方法向外提供Logger类

LoggerRegistry:最终Logger map的封装。封装Logger的名称与对应Logger的关联关系。

1、应用请求LogManager获取Logger对象
2、LogManager的context其实用的是LoggerContextFactory.getContext方法获取LoggerContext变量

为每一个ClassLoader创建一个LoggerContext并存储到map中
3、,调用LoggerContext的getLogger方法获取Logger变量,然后放入LoggerRegistry辅助存储映射关系

三四、泛型是什么

https://blog.csdn.net/qq_28761767/article/details/80938968
泛型:参数化类型来实现在同一份代码上操作多种数据类型
泛型类、泛型接口、泛型方法
// 比如:ArrayList E就是泛型。 这种不确定的数据类型需要在使用这个类的时候才能够确定出来。
// 泛型可以省略,如果省略,默认泛型是Object类型。
// 泛型的好处:
// 1. 省略了强转的代码。(Object转String)
// 2. 可以把运行时的问题提前到编译时期。
如果泛型指定的string但是添加值添加的int,编译的时候就会报错,如果没有给出泛型,则不会报错

三五、https://blog.csdn.net/Mr_wzc/article/details/119478793

三六、注解的使用

https://blog.csdn.net/Mr_wzc/article/details/119478793
我们使用注解一般有两种使用方式:

运行时处理注解:运用反射,比如GSON序列化
编译期处理注解:使用注解处理器AbstractProcessor处理注解,然后通过javapoet生成一个新的java类。如:Arouter、Butterknife等
运行时注解
比如我现在有个数据类User,数据上传的时候需要把name转换成"T0",age转换成"T1"。

1、先创建注解类
2、给User类加上这个注解
3、,创建一个处理类,通过反射获得user类的成员变量数组
4、遍历数组, 确定注解类型
if (field.isAnnotationPresent(SerializedName.class))
5、头上带这个注解的话,就在处理类内部手动把这个user改了

三七、java默认收集器_jvm默认垃圾收集器

jdk1.7 默认垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)

jdk1.8 默认垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)

jdk1.9 默认垃圾收集器G1

三八、spring的一些常用注解

三九、springboot的常用注解

四十、自己写一个切面实现

四一、自己写一个bean

四二、spring中bean的定义方法

https://zhuanlan.zhihu.com/p/387259323
在这里插入图片描述

  1. xml文件配置bean

四三、JVM内存模型

四四、大对象可以直接进老年代么

可以、大对象直接进入老年代有一个JvM参数,就是 -XX:PretenureSizeThreshold“,可以把他的值设置为字节数,比如“1048576”,就是1M

如果你创建一个大于这个大小的对象,比如一个超大的数组,或者是别的啥东西,此时就直接把这个大对象放在老年代中,压根不会经过新生代,这样可以避免新生代出现那种大对象,然后在2个Survivor区域里回来复制多次之后才能进入老年代

深入理解JVM—满足什么条件的对象才会进入老年代?
https://www.csdn.net/tags/NtjaAg5sOTYxMjItYmxvZwO0O0OO0O0O.html
到底满足什么样条件的对象才能进入老年代,然后造成full gc呢?

1、 躲过15次minor gc之后
2、动态对象年龄判断
假如说当前放对象的Survivor区域里一批对象的 总大小大于了这块Survivor区域的内存大小的50% ,那么此时大于等于这批对象年龄的对象,就可以直接进入老年代了
4.MinorGC后的对象太多无法放入Survivor区怎么办?
如果在Minor GC之后发现剩余的存活对象太多了,没办法放入另外一块Survivor,那么这个时候就必须得把这些对象直接转移到老年代中去
5.老年代空间分配担保规则

在执行任何一次Minor GC之前,JVM会检查一下老年代可用的可用内存空间,是否大于新生代所有对象的总大小

为啥会检查这个呢?因为最极端的情况下,可能新生代的Minor GC过后,所有对象都存活下来了,那岂不是新生代所有对象全部都要进入老年代?
如果在Minor GC之后发现剩余的存活对象太多了,没办法放入另外一块Survivor,那么这个时候就必须得把这些对象直接转移到老年代中去

(1)Minor GC过后,剩余的存活对象的大小,是小于Survivor区的大小的,那么此时存活对象进入Survicor区域即可

(2)Minor GC过后,剩余的存活对象的大小是大于Survivor区域的大小,但是是小于老年代可用内存大小的,此时就直接进入老年代即可

(3)Minor GC过后,剩余的存活对象的大小,大于了Survivor区域的大小,也大于了老年代可用内存的大小,此时老年代都放不下这些存活对象了,就会发生Handle Promotion Failure的情况,这个时候就会触发一次Full GC

四五、Spring Boot、Spring MVC 和 Spring 有什么区别?

https://blog.csdn.net/zzk00007/article/details/114397932

分别描述各自的特征:
Spring 框架就像一个家族,有众多衍生产品例如 boot、security、jpa等等;但他们的基础都是Spring 的ioc和 aop,ioc 提供了依赖注入的容器, aop解决了面向切面编程,然后在此两者的基础上实现了其他延伸产品的高级功能。

Spring MVC提供了一种轻度耦合的方式来开发web应用;它是Spring的一个模块,是一个web框架;通过DispatcherServlet, ModelAndView 和 View Resolver,开发web应用变得很容易;解决的问题领域是网站应用程序或者服务开发——URL路由、Session、模板引擎、静态Web资源等等。

Spring Boot实现了auto-configuration自动配置(另外三大神器actuator监控,cli命令行接口,starter依赖),降低了项目搭建的复杂度。它主要是为了解决使用Spring框架需要进行大量的配置太麻烦的问题,所以它并不是用来替代Spring的解决方案,而是和Spring框架紧密结合用于提升Spring开发者体验的工具;同时它集成了大量常用的第三方库配置(例如Jackson, JDBC, Mongo, Redis, Mail等等),Spring Boot应用中这些第三方库几乎可以零配置的开箱即用(out-of-the-box)。

所以,用最简练的语言概括就是:
Spring 是一个“引擎”;
Spring MVC 是基于Spring的一个 MVC 框架;
Spring Boot 是基于Spring4的条件注册的一套快速开发整合包。

四六、spring事务

https://blog.csdn.net/cjhxydream/article/details/123230249
3.2.1 在Spring进行事务管理操作有两种方式
(1)编程式事务管理
(2)声明式事务管理(常用)

3.2.2 声明式事务管理实现方式
(1)基于注解方式实现(常用)
(2)基于xml配置文件方式实现

注意:在Spring中进行声明式事务管理,底层使用的是AOP
3.2.3 Spring事务管理API
Spring中提供一个接口PlatformTransactionManager,此接口代表事务管理器,这个接口针对不同的框架提供不同的实现类。

4 注解方式实现声明式事务
1.在Spring配置文件中配置事务管理器
2.在Spring配置文件中,开启事务注解
3.在service类上面或者service类中方法上面添加事务注解

4.2声明式事务参数
在service类上面添加注解@Transactional, 这个注解里面可以配置事务相关参数
1.propagation:事务传播行为
多个事务之间进行调用,在调用的过程中事务是如果进行管理的
默认的传播行为是required
2.ioslation:事务隔离级别
MySQL默认隔离级别为REPEATABLE_READ
3.timeout:超时时间
事务要在一定的时间内提交,如果不提交就需要进行回滚
默认为-1,即为永不超时,超时单位为秒
4.readOnly:是否只读
读:查询操作 写:增删改操作
readOnly默认值为false,表示可以进行增删改操作
将readOnly设置为true,则只能查询,不能增删改
5.rollbackFor:回滚
设置出现哪些异常进行事务回滚
6.norollbackFor:不回滚
设置出现哪些异常不进行事务回滚

5.XML方式实现声明式事务
5.1 在Spring配置文件中进行配置
第一步 配置事务管理器

第二步 配置通知

第三步 配置切入点和切面

四七、mybatis手动事务

默认手动提交:在需要提交的时候,调用SqlSession的commit()方法;
sqlSession.insert(“com.wang.mapper.EmpMapper.insetOne”);//调用mapper中sql语句
sqlSession.commit();//提交事务

mybatis手动进行事务管理
定义事务管理器DataSourceTransactionManager
@Bean(name = “orderTransactionManager”)
public DataSourceTransactionManager orderTransactionManager() {
return new DataSourceTransactionManager(getOrderDataSource());
}

注入事务管理器然后开启
@Resource(name = “masterTransactionManager”)
private DataSourceTransactionManager dataSourceTransactionManager;

四八、dockerfile里cmd和的区别

四九、springboot启动类注解详解

五十、详解Spring中接口的bean是如何注入的

五一、Spring AOP 五大通知类型

https://blog.csdn.net/weixin_43871678/article/details/116272646
1、前置通知
在目标方法执行之前执行执行的通知。
2、环绕通知
在目标方法执行之前和之后都可以执行额外代码的通知。
3、后置通知
在目标方法执行之后执行的通知。
4、异常通知
在目标方法抛出异常时执行的通知。
5、最终通知
是在目标方法执行之后执行的通知。
以上5种都可以额外接收一个JoinPoint参数,来获取目标对象和目标方法相关信息,但一定要保证必须是第一个参数。

五种通知的执行顺序:
1、在目标方法没有抛出异常的情况下
前置通知
环绕通知的调用目标方法之前的代码
目标方法

环绕通知的调用目标方法之后的代码
后置通知
最终通知

2、在目标方法抛出异常的情况下
前置通知
环绕通知的调用目标方法之前的代码
目标方法

抛出异常
异常通知
最终通知

五一、【开发】实现一个简单的切面编程(Aspect)

https://blog.csdn.net/qq_43014198/article/details/119751662
面向切面概念
什么是切面?
切面就是把多个类的公共行为封装起来。(比如日志记录,拦截方法,过滤等操作)
反过来理解就是多个类都需要这个操作,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。

1.首先创建一个切面接口(注解)
public @interface APIAESEncryption {
String value() default “”;
}

2.创建一个类,@Pointcut定义切点。(相当于为APIAESEncryption 接口添加了实现方法。即切面的具体实现内容)

3.添加以接口为名的注解即可(添加该注解就会实现此切面行为)

4.依赖

org.springframework.boot
spring-boot-starter-aop
test

五一、自己写一个创建Bean对象的工厂(BeanFactory)

https://blog.csdn.net/ouyu2014/article/details/106902709/
第一个,需要一个配置文件来配置我们的service和da0,配置的内容:唯一标志 = 全限定类名(key = value)
第二个,通过读取配置文件中配置的内容,反射创建对象
三、 //定义一个Map,用于存放我们要创建的对象,我们把它称之为容器
private static Map<String,Object> beans;

//实例化对象
props = new Properties();
//获取properties文件的流对象
InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream(“bean.properties”);
props.load(in);
//实例化容器
beans = new HashMap<String, Object>();
//取出配置文件中所有的key
Enumeration keys = props.keys();
//遍历枚举
while(keys.hasMoreElements()){
//取出每个key
String key = keys.nextElement().toString();
//根据key获取value
String beanPath = props.getProperty(key);
//反射创建对象
Object value = Class.forName(beanPath).newInstance();
//把key和value存入容器中
beans.put(key,value);
}

五一、Bean的四种创建方式

https://blog.csdn.net/qq_36892672/article/details/103542323
1.1 普通的方式
实例化一个有公共无参构造的方法,要求有无参构造函数。

//自己写的对象:Dao,Service,Action都使用这种方法

1.2 FactoryBean方式
一个类实现了FactoryBean接口
执行getObject方式,返回的值也会变成一个Bean
准备一个FactoryBean

1.3 静态工厂
工厂中有一个静态方法
直接拿到这个方法中返回的对象(bean)
准备一个静态工厂
public class DaoFactory {
//在这个工厂中有一个静态方法
public static MyDao createMyDao(){
return new MyDao();
配置这个工厂对应的方法

1.4 实例工厂
工厂中有个方法
直接拿到这个方法中返回的对象(bean)
准备一个静态工厂
public class DaoFactory {
public MyDao createMyDao(){
return new MyDao();
}
}
配置这个工厂对应的方法

五一、你知道spring中有哪些方式可以定义bean

在这里插入图片描述

  1. xml文件配置bean
  2. 1.1 构造器,bean.xml,,它默认使用了无参构造器创建bean
  3. 1.2 setter方法
    除此之外,spring还提供了另外一种思路:通过setter方法设置bean所需参数,这种方式耦合性相对较低,比有参构造器使用更为广泛。
    1.3 静态工厂
    这种方式的关键是需要定义一个工厂类,它里面包含一个创建bean的静态方法
    然后bean.xml文件中配置bean时,需要先配置工厂bean。然后在配置实例bean时,通过factory-bean参数指定该工厂bean的引用。

我们通过上面五种方式,在bean.xml文件中把bean配置好之后,spring就会自动扫描和解析相应的标签,并且帮我们创建和实例化bean,然后放入spring容器中。

二、为了解决bean太多时,xml文件过大,从而导致膨胀不好维护的问题。在spring2.5中开始支持:@Component、@Repository、@Service、@Controller等注解定义bean。

如果你有看过这些注解的源码的话,就会惊奇得发现:其实后三种注解也是@Component,
@Component系列注解的出现,给我们带来了极大的便利。我们不需要像以前那样在bean.xml文件中配置bean了,现在只用在类上加Component、Repository、Service、Controller,这四种注解中的任意一种,就能轻松完成bean的定义。

不过,需要特别注意的是,通过这种@Component扫描注解的方式定义bean的前提是:需要先配置扫描路径。

目前常用的配置扫描路径的方式如下:
在applicationContext.xml文件中使用context:component-scan标签。例如:
<context:component-scan base-package=“com.sue.cache” />
在springboot的启动类上加上@ComponentScan注解,例如:
@ComponentScan(basePackages = “com.sue.cache”)
直接在SpringBootApplication注解上加,它支持ComponentScan功能:
@SpringBootApplication(scanBasePackages = “com.sue.cache”)

此外,除了上述四种@Component注解之外,springboot还增加了@RestController注解,它是一种特殊的@Controller注解,所以也是@Component注解。

@RestController还支持@ResponseBody注解的功能,即将接口响应数据的格式自动转换成json。

  1. JavaConfig
    有了config就告别麻烦的xml时代,@Component系列注解虽说使用起来非常方便,但是bean的创建过程完全交给spring容器来完成,我们没办法自己控制。

spring从3.0以后,开始支持JavaConfig的方式定义bean。它可以看做spring的配置文件,但并非真正的配置文件,我们需要通过编码java代码的方式创建bean。例如:
@Configuration
public class MyConfiguration {
@Bean
public Person person() {
return new Person();
}
}

在JavaConfig类上加@Configuration注解,相当于配置了标签。而在方法上加@Bean注解,相当于配置了标签。

此外,springboot还引入了一些列的@Conditional注解,用来控制bean的创建。
这个功能非常有用,相当于一个开关控制着Person类,只有满足一定条件才能实例化。

  1. Import注解
    通过前面介绍的@Configuration和@Bean相结合的方式,我们可以通过代码定义bean。但这种方式有一定的局限性,它只能创建该类中定义的bean实例,不能创建其他类的bean实例,如果我们想创建其他类的bean实例该怎么办呢?

这时可以使用@Import注解导入。

五一、SpringBoot启动类核心注解及SpringBoot的启动机制

https://blog.csdn.net/I_like_kan_draw/article/details/118279364
@SpringBootApplication:是SpringBoot中的最核心注解,用于开启自动配置和启动SpirngBoot项目的前置条件。

@ComponentScan:用于扫描被@Component注解标注的类,用于交给SpringBoot管理并注入bean容器。也即是控制反转IOC的实现方式。不过虽然其中含有这个扫描注解,但也可以在启动类上添加@ComponentScan注解进一步标点其扫描的范围,而不需要关系SpringBoot的启动类的位置。
@EnableAutoConfiguration:借助@Import的支持,收集和注册特定场景相关的bean定义。其借助@Import(AutoConfigurationImportSelector.class)注解使用AutoConfigurationImportSelector将所有被@Configuration注解标注的类加载并注入到ioc容器中。
SpringFactoriesLoader类:其主要是从特点的配置文件META-INF/spring.factories中加载配置。配合@EnableAutoConfiguration注解使用时,@EnableAutoConfiguration注解会优先找到这个加载文件并将其中的配置汇总为一个配置类并加载到ioc容器中。
@SpringBootConfiguration:其功能和@Configuration注解功能类似,都是声明这个类为配置类并加载到ioc容器中
@Inherited :表示这个使用这个注解的类被继承了之后。我子类也会继承这个注解。表示注解继承的概念。
@Documented: 用于记录的注解
@Retention():其中RetentionPolicy是一个枚举类,拥有标定这个注释的保留时间
@Target():表示该注解的可标定范围,类或方法或属性等等。
SpringBoot的启动流程机制:有SpringApplication类的run()方法来实现项目的启动

public static void main(String[] args) {
SpringApplication app = new SpringApplication(MyApplication.class);
Environment nev = app.run(args).getEnvironment();//可以拿到在启动后的端口数据和主机地址
//SpringApplication.run(MyApplication.class, args); //寻常启动方式
}

1
2
3
4
5
6
首先向SpringApplication的实例对象中传入启动类的class对象,根据这个传入的实例对象的classpath,并使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationContextInitializer(应用程序上下文初始化器)和ApplicationListener(应用程序监听器)
首先使用在上下文中拿到的所有应用监听器,分别遍历的调用它们的SpringApplicationRunListener类的started()方法,使其启动
创建并配置SpringBoot需要用到的Environment配置,包括主机编号和端口号等
环境准备好了之后,再次调用监听器SpringApplicationRunListener的environmentPrepared()方法,加载环境变量并进行下一步动作
若使用了banner,则打印横幅,启动的图像,代表SpringBoot开始启动
通过前置配置创建ApplicationContext并将环境参数传入其中
创建好应用程序上下文之后,再次使用SpringFactoriesLoader遍历查找加载classpath下的ApplicationContextInitializer类并调用initialize(applicationContext)方法完成上下文的初始化操作
在完成初始化操作之后,再将之前通过注解等方式获取到的ioc容器中的配置类加载到准备完毕的ApplicationContext中
再遍历调用SpringApplicationRunListener监听器的contextLoaded()方法,告知监听器初始化操作已经完成
完成上下文的基本配置后,再调用ApplicationContext的refresh()方法,完成IOC容器的所有与初始化操作
查找ApplicationContext中的所有存在的CommandLineRunner,遍历的执行这些命令行操作
最后,再调用SpringApplicationRunListener的finished()方法,完成整个时间的监听过程。

https://blog.csdn.net/wang_1220/article/details/107767035
@SpringBootApplication

之前用户使用的是3个注解注解他们的main类。分别是@Configuration、@EnableAutoConfiguration、@ComponentScan。由于这些注解一般都是一起使用,spring boot提供了一个统一的注解@SpringBootApplication。

1、@Configuration:提到@Configuration就要提到他的搭档@Bean。使用这两个注解就可以创建一个简单的spring配置类,可以用来替代相应的xml配置文件。

注:@Configuration的注解类标识这个类可以使用Spring IoC容器作为bean定义的来源。@Bean注解告诉Spring,一个带有@Bean的注解方法将返回一个对象,该对象应该被注册为在Spring应用程序上下文中的bean。

2、@EnableAutoConfiguration:能够自动配置spring的上下文,试图猜测和配置你想要的bean类,通常会自动根据你的类路径和你的bean定义自动配置。

3、@ComponentScan:会自动扫描指定包下的全部标有@Component的类,并注册成bean,当然包括@Component下的子注解@Service,@Repository,@Controller。

五一、详解Spring中接口的bean是如何注入的

https://www.jb51.net/article/188635.htm
再来说Controller获取实例的过程:使用@Autowired,程序在spring的容器中查找类型是TestService的bean,刚好找到有且只有一个此类型的bean,即testServiceImpl,所以就把testServiceImpl自动装配到了controller的实例testService中,testService其实就是TestServiceImpl实现类;

如果使用的是@Resource,则是先在容器中查找名字为testService的bean,但并没有找到,因为容器中的bean名字是TestServiceImpl(如果@Service没指定bean的value属性,则注入bean的名字就是类名,如果指定了则是指定的名字),然后再通过类型查找TestService类型的bean,找到唯一的了个TestService类型bean(即TestServiceImpl),所以就自动装配实例成功了。

效率上来说@Autowired/@Resource差不多,不过推荐使用@Resource一点,因为当接口有多个实现时@Resource直接就能通过name属性来指定实现类,而@Autowired还要结合@Qualifier注解来使用,且@Resource是jdk的注释,可与Spring解耦。
@Resource如果不显示的指定name值,就会自动把实例变量的名称作为name的值的

五二、注册中心做了那些事

五三、Spring中单例Bean是线程安全的吗

https://blog.csdn.net/weixin_43727372/article/details/100324678
Spring容器中的Bean是否线程安全,容器本身并没有提供Bean的线程安全策略,因此可以说Spring容器中的Bean本身不具备线程安全的特性,但是具体还是要结合具体scope的Bean去研究。

Spring 的 bean 作用域(scope)类型
1、singleton:单例,默认作用域。

2、prototype:原型,每次创建一个新对象。

3、request:请求,每次Http请求创建一个新对象,适用于WebApplicationContext环境下。

4、session:会话,同一个会话共享一个实例,不同会话使用不用的实例。

5、global-session:全局会话,所有会话共享一个实例。

线程安全这个问题,要从单例与原型Bean分别进行说明。

原型Bean
对于原型Bean,每次创建一个新对象,也就是线程之间并不存在Bean共享,自然是不会有线程安全的问题。

单例Bean
对于单例Bean,所有线程都共享一个单例实例Bean,因此是存在资源的竞争。

如果单例Bean,是一个无状态Bean,也就是线程中的操作不会对Bean的成员执行查询以外的操作,那么这个单例Bean是线程安全的。比如Spring mvc 的 Controller、Service、Dao等,这些Bean大多是无状态的,只关注于方法本身。

有状态对象(Stateful Bean) :就是有实例变量的对象,可以保存数据,是非线程安全的。每个用户有自己特有的一个实例,在用户的生存期内,bean保持了用户的信息,即“有状态”;一旦用户灭亡(调用结束或实例结束),bean的生命期也告结束。即每个用户最初都会得到一个初始的bean。

无状态对象(Stateless Bean):就是没有实例变量的对象,不能保存数据,是不变类,是线程安全的。bean一旦实例化就被加进会话池中,各个用户都可以共用。即使用户已经消亡,bean 的生命期也不一定结束,它可能依然存在于会话池中,供其他用户调用。由于没有特定的用户,那么也就不能保持某一用户的状态,所以叫无状态bean。但无状态会话bean 并非没有状态,如果它有自己的属性(变量),那么这些变量就会受到所有调用它的用户的影响,这是在实际应用中必须注意的。

对于有状态的bean,Spring官方提供的bean,一般提供了通过ThreadLocal去解决线程安全的方法,比如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等。

使用ThreadLocal的好处
使得多线程场景下,多个线程对这个单例Bean的成员变量并不存在资源的竞争,因为ThreadLocal为每个线程保存线程私有的数据。这是一种以空间换时间的方式。

五四、分段锁的原理

五五、JAVA Stream debug技巧

https://blog.csdn.net/dushan1234/article/details/103909483
JDK8 stream使用起来很方便,但是调试的话,却不像之前单步debug那样,能看到每一步的运行结果。
所以,idea有一个插件JAVA STREAM DEBUGGER插件,目前最新的idea2018,2019已经集成了该插件。

五六、Git常用命令

https://blog.csdn.net/weixin_67585820/article/details/123554416
git branch
分支的增删查改都靠它
git branch //创建一个分支
git branch -d //删除一个分支
git branch -v //显示所有分支信息

2.git checkout
git checkout //通过移动HEAD检出版本,可用于切换分支
git checkout -b //创件一个分支并切换
git checkout //将其移动到一个引用
git checkout - //恢复到上一个分支
1
2
3
4
git checkout 也可以跟一个commitid,这时候HEAD指向这个commitid跟所有分支分离,这个状态为detached

git reset
//git reset 将当前分支回退到历史某个版本
git reset --mixed //(默认)
git reset --soft
git reset --hard

git reflog
在这里插入图片描述
.git stash
git stash 用来保存目前的工作目录和暂存区状态,并返回到干净的工作空间

有时候我们要切换分支会有以下提示,是因为当前分支还有内容未提交,现在切换内容会丢失。这时候要用到git stash 命令

五七、gitbase 是什么

https://linux.cn/article-10249-1.html
gitbase 是一个使用 go 开发的的开源项目,它实现了在 Git 仓库上执行 SQL 查询。,可以使用 SQL 对 git 仓库进行大规模分析。

五八、CHAR与VARCHAR字段类型的适用场景

五九、char varchar nchar nvarchar的区别

https://blog.csdn.net/cjune/article/details/80868417
类型特点
1.char
固定长度,存储ANSI字符,不足的补英文半角空格
2.varchar
可变长度,存储ANSI字符,根据数据长度自动变化
3.nchar
固定长度,存储Unicode字符,不足的补英文半角空格
4.nvcarchar
可变长度,存储Unicode字符,根据数据长度自动变化。
区别
1.前面加“n”与不加“n”
1.char、varchar、这两个只能用于单字节来存储数据,适合英文,中文会不兼容。我们常用的汉字需要用两个字节来存储,所以就要使用nchar、nvarchar。
2.char、varchar因为是单字节的所以在存储的时候最大数值可以达到8000,而nchar、nvarchar是最大数值4000。
2.char与varchar的区别
直接举例子:char(10)就是给予一个固定的空间,不管存储的内容有没有到达10个字节,都占用10个字节的空间,同时,varchar(10)和nvarchar(10)的最大空间
只能为10字节,如果不到10字节就不占用10字节。

如何使用
1.如果你肯定存储的数据长度,而且不包中文的,可以选择char类型。
2.如果肯定存储的数据长度,但可能包括中文,可以选择nchar类型。
3.如果不确定存储的数据长度,存储只有英文、数字的最好用varchar
4.如果不确定存储的数据长度,也有可能有中文,可以选择nvarchar类型,在SQL Server2005中也是比较常用的字符数据类型。

六十、redis 锁机制

https://blog.csdn.net/odelia145/article/details/105951076/
redis能用的的加锁命令分别为:incr、setNX、set
1、incr锁
这种加锁的思路是, key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作进行加一。
然后其它用户在执行 INCR 操作进行加一时,如果返回的数大于 1 ,说明这个锁正在被使用当中

这种加锁的思路是,如果 key 不存在,将 key 设置为 value
如果 key 已存在,则 SETNX 不做任何动作

3、set锁

上面两种方法都有一个问题,会发现,都需要设置 key 过期。那么为什么要设置key过期呢?如果请求执行因为某些原因意外退出了,导致创建了锁但是没有删除锁,那么这个锁将一直存在,以至于以后缓存再也得不到更新。于是乎我们需要给锁加一个过期时间以防不测。
但是借助 Expire 来设置就不是原子性操作了。所以还可以通过事务来确保原子性,但是还是有些问题,所以官方就引用了另外一个,使用 SET 命令本身已经从版本 2.6.12 开始包含了设置过期时间的功能。

4、其它问题

虽然上面一步已经满足了我们的需求,但是还是要考虑其它问题?
1、 redis发现锁失败了要怎么办?中断请求还是循环请求?
2、 循环请求的话,如果有一个获取了锁,其它的在去获取锁的时候,是不是容易发生抢锁的可能?
3、 锁提前过期后,客户端A还没执行完,然后客户端B获取到了锁,这时候客户端A执行完了,会不会在删锁的时候把B的锁给删掉?

5、解决办法

针对问题1:使用循环请求,循环请求去获取锁
针对问题2:针对第二个问题,在循环请求获取锁的时候,加入睡眠功能,等待几毫秒在执行循环
针对问题3:在加锁的时候存入的key是随机的。这样的话,每次在删除key的时候判断下存入的key里的value和自己存的是否一样

六一、什么是MongoDB?它有什么用处?

https://cloud.tencent.com/developer/news/358112
https://blog.csdn.net/hayre/article/details/80628431
MongoDB 是一个基于分布式文件存储的非关系型数据库。由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。
MongoDB的核心是一个文档数据库,数据存储格式
是JSON格式,

2.为什么要使用MongoDB?
(1)MongoDB提出的是文档、集合的概念,使用BSON(类JSON)作为其数据模型结构,其结构是面向对象的而不是二维表,存储一个用户在MongoDB中是这样子的。

username:‘123’,
password:‘123’

使用这样的数据模型,使得MongoDB能在生产环境中提供高读写的能力,吞吐量较于mysql等SQL数据库大大增强。

(2)易伸缩,自动故障转移。易伸缩指的是提供了分片能力,能对数据集进行分片,数据的存储压力分摊给多台服务器。自动故障转移是副本集的概念,MongoDB能检测主节点是否存活,当失活时能自动提升从节点为主节点,达到故障转移。

(3)数据模型因为是面向对象的,所以可以表示丰富的、有层级的数据结构,比如博客系统中能把“评论”直接怼到“文章“的文档中,而不必像myqsl一样创建三张表来描述这样的关系。

MongoDB的优势:
MongoDB是开源产品
JSON 文档模型、动态的数据模式、二级索引强大、查询功能、自动分片、水平扩展、自动复制、高可用、文本搜索、企业级安全、聚合框架MapReduce、大文件存储GridFS

什么时候该MongDB:
新应用,需求会变,数据模型无法确定
我需要整合多个外部数据源
我的系统需要99.999%高可用
我的数据量是有亿万级或者需要不断扩容

六二、es是什么,能做什么?

https://blog.csdn.net/LYLLOAD/article/details/80432605
es是什么
elasticsearch简写es,es是一个高扩展、开源的全文检索和分析引擎,它可以准实时地快速存储、搜索、分析海量的数据。

什么是全文检索
全文检索是指计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。这个过程类似于通过字典中的检索字表查字的过程。全文搜索搜索引擎数据库中的数据。

六三、深入理解 http 反向代理(nginx)

https://zhuanlan.zhihu.com/p/464965616
一个很直接的原因就是利用反向代理可以作为内部 负载均衡(load balance) 的手段.

六四、反向代理的四大用途

https://baijiahao.baidu.com/s?id=1729437314889620848&wfr=spider&for=pc
负载均衡

一般来说,大部分日常活跃用户量比较大的网站都没有办法通过单个服务器来处理所有的请求,所以网站需要多个后端服务器以分配用户的访问请求,而这就是反向代理服务器的用处所在,并且反向代理服务器还可以有效的避免服务器出现过载的情况。

提高安全性

当站点使用反向代理时,站点的服务器地址会变为隐藏,而且反向代理服务器还可以拦截来自特定站点的可疑流量,大大提升了站点服务器的安全性。

缓存数据

反向代理服务器可以缓存用户通常请求的数据,当有其他用户请求相同数据时可以直接返回,大大减少了站点服务器的负载,提高了站点服务器的性能。

SSL加密

当网站每天都有大量访问请求时,SSL协议通信可能不能完全覆盖到每一个用户,而使用反向代理则可以完成加密解密的任务,确保通信数据的安全。

六五、怎么设计一个树

https://www.csdn.net/tags/MtzaYgzsNjc1MzItYmxvZwO0O0OO0O0O.html
二叉树(binary tree)是指树中结点的孩子不大于2的有序树
二叉树的链式存储是通过一个一个的节点引用起来的,常见的表示方式有二叉和三叉表示方式,具体如下:

// 孩子表示法
class Node {
int val; // 数据域
Node left; // 左孩子的引用,常常代表左孩子为根的整棵左子树
Node right; // 右孩子的引用,常常代表右孩子为根的整棵右子树
}
// 孩子双亲表示法
class Node {
int val; // 数据域
Node left; // 左孩子的引用,常常代表左孩子为根的整棵左子树
Node right; // 右孩子的引用,常常代表右孩子为根的整棵右子树
Node parent; // 当前节点的根节点
}

六六、SQL Explain 各项参数详解

https://blog.csdn.net/qq_43012298/article/details/121377693
使用EXPLAIN关键字可以模拟优化器执行SQL语句,从而知道MySQL是 如何处理你的SQL语句的。分析你的查询语句或是结构的性能瓶颈
在 select 语句之前增加 explain 关键字,MySQL 会在查询上设置一个标记,执行查询时,会返回执行计划的信息
explain 只能解释select查询,并不会对存储过程、insert、update、delete或其他语句做解释。可以通过重写非select查询,来利用explain

一、explain 的两种使用方式
1)explain extended:会在 explain 的基础上额外提供一些查询优化的信息。紧随其后通过 show warnings 命令可以 得到优化后的查询语句,从而看出优化器优化了什么。额外还有 filtered 列,是一个半分比的值,rows * filtered/100 可以估算出将要和 explain 中前一个表进行连接的行数(前一个表指 explain 中的id值比当前表id值小的表)

mysql> explain extended select * from film where id = 1;

mysql> show warnings;

2)explain partitions:相比 explain 多了个 partitions 字段,如果查询是基于分区表的话,会显示查询将访问的分区
在这里插入图片描述

二、explain中的列
https://www.jianshu.com/p/3cf1cd8202bd?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation
1、id列的编号是 select 的序列号,有几个 select 就有几个id,并且id的顺序是按 select 出现的顺序增长的。MySQL将 select 查询分为简单查询(SIMPLE)和复杂查询(PRIMARY)。
复杂查询分为三类:简单子查询、派生表(from语句中的子查询)、union 查询

id列越大执行优先级越高,id相同则从上往下执行,id为NULL最后执行,
union结果总是放在一个匿名临时表中,临时表不在SQL中出现,因此它的id是NULL。

2、select_type列
select_type 表示对应行是简单还是复杂的查询,如果是复杂的查询,又是上述三种复杂查询中的哪一种。

3、table列
这一列表示 explain 的一行正在访问哪个表。

四:partitions 分区
查询将从中匹配记录的分区。对于未分区的表,该值为NULL。

type访问类型,mysql决定如何查找表中的行 从最差到最优 ALL、INDEX、RANGE、REF、eq_ref、const、system、NULL

possilble_keys
这一列显示了查询可以使用到的哪些索引。

key
这一列显示了mysql决定使用哪个索引来优化对该表的访问

key_len
该列显示了mysql在索引里使用的字节数

ref
这一列显示了之前的表在key列记录的索引中查找值所用的列或常量。

rows
这一列显示了mysql为了找到所需的行而需要读取的行数

extra
这一列包含了不适合在其他列显示的信息

using index
表示mysql将使用索引覆盖,以避免访问表

using where
表示mysql服务器将在存储引擎检索行后再进行过滤

using temporary
表示mysql 在对查询结果排序时使用了临时表。

using filesort
mysql将对结果使用一个外部索引排序,而不是按索引次序读取。

六七、分段锁的原理https://blog.csdn.net/rlnLo2pNEfx9c/article/details/79784983

前言:在分析ConcurrentHashMap的源码的时候,了解到这个并发容器类的加锁机制是基于粒度更小的分段锁,分段锁也是提升多并发程序性能的重要手段之一。

在并发程序中,串行操作是会降低可伸缩性,并且上下文切换也会减低性能。在锁上发生竞争时将通水导致这两种问题,使用独占锁时保护受限资源的时候,基本上是采用串行方式—-每次只能有一个线程能访问它。所以对于可伸缩性来说最大的威胁就是独占锁。

我们一般有三种方式降低锁的竞争程度:
1、减少锁的持有时间
2、降低锁的请求频率
3、使用带有协调机制的独占锁,这些机制允许更高的并发性。

在某些情况下我们可以将锁分解技术进一步扩展为一组独立对象上的锁进行分解,这成为分段锁。其实说的简单一点就是:容器里有多把锁,每一把锁用于锁容器其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效的提高并发访问效率,这就是ConcurrentHashMap所使用的锁分段技术,首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。

比如:在ConcurrentHashMap中使用了一个包含16个锁的数组,每个锁保护所有散列桶的1/16,其中第N个散列桶由第(N mod 16)个锁来保护。假设使用合理的散列算法使关键字能够均匀的分部,那么这大约能使对锁的请求减少到越来的1/16。也正是这项技术使得ConcurrentHashMap支持多达16个并发的写入线程。

当然,任何技术必有其劣势,与独占锁相比,维护多个锁来实现独占访问将更加困难而且开销更加大。

六八、注册中心的作用在这里插入图片描述

六九、关系型数据库和非关系型数据库

https://www.jianshu.com/p/9366b6eaa429
关系 的个人理解:关系就是表内数据之间的、表之间的关系。表内数据是严格的对应关系,字段缺一不可,值缺一不可,也就是一致的数据结构,这也就是 django 新增字段时,需要删掉数据,重新 migrate。表之间的关系三种:一对一、一对多、多对多。关系模型指的就是二维表格模型;

1.关系型数据库理论 - ACID
ACID,是指数据库管理系统(DBMS)在写入或更新资料的过程中,为保证事务(transaction)是正确可靠的,所必须具备的四个特性:原子性(atomicity,或称不可分割性)、一致性(consistency)、隔离性(isolation,又称独立性)、持久性(durability)。

2.优缺点
关系型数据库的优势:
容易理解:二维表结构是非常贴近逻辑世界一个概念,关系模型相对网状、层次等其他模型来说更容易理解;
保持数据的一致性(事务处理)
由于以标准化为前提,数据更新的开销很小(相同的字段基本上都只有一处)
支持SQL,可以进行Join等复杂查询(几张表之间)
关系型数据库的不足:

不擅长的处理
大量数据的写入处理
为有数据更新的表做索引或表结构(schema)变更
字段不固定时应用
对简单查询需要快速返回结果的处理

非关系数据库
结构不固定,集合内数据字段可以不一样,自由度高,可以减少一些时间和空间的开销。

四大类型:
键值对存储(key-value),文档存储(document store:mongodb),基于列的数据库(column-oriented),还有就是图形数据库(graph database)

主流的非关系型数据库有 NoSql、MongoDB、Cloudant、

特征:
1、使用键值对存储数据;
2、分布式;
3、一般不支持ACID特性;
4、非关系型数据库严格上不是一种数据库,应该是一种数据结构化存储方法的集合。

优点:
1、无需经过sql层的解析,读写性能很高;
2、基于键值对,数据没有耦合性,容易扩展;
3、存储数据的格式:nosql的存储格式是key,value形式、文档形式、图片形式等等,文档形式、图片形式等等,而关系型数据库则只支持基础类型。

缺点:
1、不提供sql支持,学习和使用成本较高;
2、无事务处理,附加功能bi和报表等支持也不好;

七十、

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值