diff --git a/Java/JVM.md b/Java/JVM.md index b19e730..57e50e2 100644 --- a/Java/JVM.md +++ b/Java/JVM.md @@ -510,6 +510,8 @@ public class ReferenceCountingGc { ## 垃圾收集器 +[CMS和G1]: https://blog.csdn.net/KIMTOU/article/details/120939751 + 经典的垃圾收集器主要有三种类型:串行收集器、并行收集器和并发标记清除收集器CMS,这三种收集器分别可以是满足Java应用三种不同的需求:内存占用及并发开销最小化、应用吞吐量最大化和应用GC暂停时间最小化。 JDK1.7和1.8中默认使用的是Parallel Scavenge和Parallel Old收集器组合。jdk1.9 默认垃圾收集器是G1。 diff --git "a/Java/Java\345\237\272\347\241\200.md" "b/Java/Java\345\237\272\347\241\200.md" index 3a08dc1..572fc61 100644 --- "a/Java/Java\345\237\272\347\241\200.md" +++ "b/Java/Java\345\237\272\347\241\200.md" @@ -138,13 +138,13 @@ JRE是运行基于Java语言编写的程序所不可缺少的运行环境。也 ## 基本数据类型 -- byte,8bit -- char,16bit -- short,16bit -- int,32bit -- float,32bit -- long,64bit -- double,64bit +- byte,8bit, 一个字节 +- char,16bit, 二个字节 +- short,16bit, 二个字节 +- int,32bit, 四个字节 +- float,32bit,四个字节 +- long,64bit,八个字节 +- double,64bit,八个字节 - boolean,只有两个值:true、false,可以使⽤用 1 bit 来存储,但是具体⼤小没有明确规定。 ## 包装类型 @@ -156,6 +156,10 @@ Integer x = 1; // 装箱 调⽤ Integer.valueOf(1) int y = x; // 拆箱 调⽤了 X.intValue() ``` +​ 从反编译得到的字节码内容可以看出,在装箱的时候自动调用的是Integer的valueOf(int)方法。而在拆箱的时候自动调用的是Integer的intValue方法。 + +​ 装箱过程是通过调用包装器的valueOf方法实现的,而拆箱过程是通过调用包装器的 xxxValue方法实现的。(xxx代表对应的基本数据类型)。 + ### 包装类缓存 使用Integer.valueOf(i)生成Integer,如果 -128 <= i <= 127,则直接从cache取对象返回,不会创建新的对象,避免频繁创建包装类对象。 @@ -172,22 +176,23 @@ int y = x; // 拆箱 调⽤了 X.intValue() String是final类,不可被继承。 -### String拼接 +### String拼接(String、StringBuilder、StringBuffer区别和效率比较) 字符串拼接可以使用String用+做拼接,也可以使用StringBuilder和StringBuffer实现,三种方式对比: - 底层都是char数组实现的 - - 字符串拼接性能:StringBuilder > StringBuffer > String - String 是字符串常量,一旦创建之后该对象是不可更改的,用+对String做拼接操作,实际上是先通过建立StringBuilder,然后调用append()做拼接操作,所以在大量字符串拼接的时候,会频繁创建StringBuilder,性能较差。 - StringBuilder和StringBuffer的对象是字符串变量,对变量进行操作就是直接对该对象进行修改(修改char[]数组),所以速度要比String快很多。 -- 在线程安全上,StringBuilder是线程不安全的,而StringBuffer是线程安全的,StringBuffer中很多方法带有synchronized关键字,可以保证线程安全。 +- 在线程安全上,StringBuilder是线程不安全的,而StringBuffer是线程安全的,StringBuffer中很多方法带有synchronized关键字,可以保证线程安全。StringBuffer为了做到线程安全,牺牲一定的效率是必然的,所以StringBuffer的效率比StringBuilder效率差。 + +**总结:**效率比较StringBuilder>StringBuffer>String ## 关键字 ### static -static可以用来修饰类的成员方法、类的成员变量。 +static可以用来修饰类的成员方法、类的成员变量、代码快和内部类。 #### 静态变量 @@ -446,8 +451,7 @@ public class Person { String name = "程序员大彬"; Person p1 = new Person(18, name); Person p2 = new Person(18, name); - - System.out.println(p1.equals(p2)); + } //output //false @@ -878,8 +882,6 @@ Java中接口和抽象类的定义语法分别为interface与abstract关键字 abstract void method(); ``` -抽象方法必须用abstract关键字进行修饰。如果一个类含有抽象方法,则称这个类为抽象类,抽象类必须在类前用abstract关键字修饰。因为抽象类中含有未实现的方法,所以不能用抽象类创建对象。 - 抽象类的特点: - 抽象类不能被实例化只能被继承; @@ -939,7 +941,7 @@ Java反射就是在运行状态中,对于任意一个类,都能够知道这 ## Class类 -在Java中,每定义一个Java class实体都会产生一个Class对象。这个Class对象用于表示这个类的类型信息。 +在Java中,每定义一个Java class实例都会产生一个Class对象。这个Class对象用于表示这个类的类型信息。 获取Class对象的三种方式: @@ -1390,6 +1392,7 @@ ThreadLocal 适用场景:每个线程需要有自己单独的实例,且需 线程安全:代码段在多线程下执行和在单线程下执行能获得一样的结果。 线程安全类:线程安全的类其方法是同步的,每次只能有一个线程访问,效率较低。 + - vector:比arraylist多了个同步化机制,效率较低 - stack:堆栈类,继承自vector - hashtable:hashtable不允许插入空值,hashmap允许 diff --git "a/Java/Java\351\233\206\345\220\210\351\235\242\350\257\225\351\242\230.md" "b/Java/Java\351\233\206\345\220\210\351\235\242\350\257\225\351\242\230.md" index 5af404d..c336e0a 100644 --- "a/Java/Java\351\233\206\345\220\210\351\235\242\350\257\225\351\242\230.md" +++ "b/Java/Java\351\233\206\345\220\210\351\235\242\350\257\225\351\242\230.md" @@ -111,6 +111,7 @@ HashMap 使用数组+链表+红黑树(JDK1.8增加了红黑树部分)实现 * 开放定址法基本思想就是,如果`p=H(key)`出现冲突时,则以`p`为基础,再次hash,`p1=H(p)`,如果p1再次出现冲突,则以p1为基础,以此类推,直到找到一个不冲突的哈希地址`pi`。 因此开放定址法所需要的hash表的长度要大于等于所需要存放的元素,而且因为存在再次hash,所以`只能在删除的节点上做标记,而不能真正删除节点。` * 再哈希法提供多个不同的hash函数,当`R1=H1(key1)`发生冲突时,再计算`R2=H2(key1)`,直到没有冲突为止。 这样做虽然不易产生堆集,但增加了计算的时间。 * 链地址法将哈希值相同的元素构成一个同义词的单链表,并将单链表的头指针存放在哈希表的第i个单元中,查找、插入和删除主要在同义词链表中进行。链表法适用于经常进行插入和删除的情况。 +* 建立公共溢出区,将哈希表分为基本表和溢出表,将发生冲突的都存放在溢出表中。 ### 使用的hash算法? diff --git "a/Java/\345\271\266\345\217\221.md" "b/Java/\345\271\266\345\217\221.md" index 65ea9c9..da71be4 100644 --- "a/Java/\345\271\266\345\217\221.md" +++ "b/Java/\345\271\266\345\217\221.md" @@ -147,7 +147,7 @@ public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveT **CPU 密集型任务(N+1)**: 这种任务消耗的主要是 CPU 资源,可以将线程数设置为 N(CPU 核心数)+1,比 CPU 核心数多出来的一个线程是为了防止某些原因导致的任务暂停(线程阻塞,如io操作,等待锁,线程sleep)而带来的影响。一旦某个线程被阻塞,释放了cpu资源,而在这种情况下多出来的一个线程就可以充分利用 CPU 的空闲时间。 -**I/O 密集型任务(2N)**: 系统会用大部分的时间来处理 I/O 操作,而线程等待 I/O 操作会被阻塞,释放 cpu资源,这时就可以将 CPU 交出给其它线程使用。因此在 I/O 密集型任务的应用中,我们可以多配置一些线程,具体的计算方法:最佳线程数 = CPU核心数 * (1/CPU利用率) = CPU核心数 * (1 + (I/O耗时/CPU耗时)),一般可设置为2N。 +**I/O 密集型任务(2N)**: 系统会用大部分的时间 ### 关闭线程池 @@ -398,6 +398,8 @@ Java内存模型:线程之间的共享变量存储在主内存里,每个线 ### 中断 +[线程中断机制]: https://www.jianshu.com/p/e0ff2e420ab6 + 线程中断即线程运行过程中被其他线程给打断了,它与 stop 最大的区别是:stop 是由系统强制终止线程,而线程中断则是给目标线程发送一个中断信号,如果目标线程没有接收线程中断的信号并结束线程,线程则不会终止,具体是否退出或者执行其他逻辑取决于目标线程。 线程中断三个重要的方法: diff --git "a/Redis/Redis\345\205\245\351\227\250\346\214\207\345\215\227\346\200\273\347\273\223.md" "b/Redis/Redis\345\205\245\351\227\250\346\214\207\345\215\227\346\200\273\347\273\223.md" index a3b0f32..ebadfc4 100644 --- "a/Redis/Redis\345\205\245\351\227\250\346\214\207\345\215\227\346\200\273\347\273\223.md" +++ "b/Redis/Redis\345\205\245\351\227\250\346\214\207\345\215\227\346\200\273\347\273\223.md" @@ -1,4 +1,4 @@ -## 简介 +## 简介 Redis是一个高性能的key-value数据库。Redis对数据的操作都是原子性的。 @@ -385,6 +385,13 @@ struct sdshdr { | 只能保存文本数据。 | 可以保存文本或者二进制数据。 | | 可以使用所有 `` 库中的函数。 | 可以使用一部分 `` 库中的函数。 | +> 优点: +> +> + 获取字符串长度的时间复杂度为O(1) +> + 支持动态扩容 +> + 减少内存分配次数 +> + 二进制安全 + #### 字典 字典使用hashtable作为底层实现。键值对的值可以是一个指针, 或者是一个 uint64_t 整数, 又或者是一个 int64_t 整数。 @@ -672,7 +679,7 @@ Redis启动时会读取RDB快照文件,将数据从硬盘载入内存。通过 ### AOF方式 -AOF(append only file)持久化:以独立日志的方式记录每次写命令,Redis重启时会重新执行AOF文件中的命令达到恢复数据的目的。AOF的主要作用是**解决了数据持久化的实时性**,目前已经是Redis持久化的主流方式。 +AOF(append only file)持久化:以独立日志的方式记录每次写命令, Redis重启时会重新执行AOF文件中的命令达到恢复数据的目的。AOF的主要作用是**解决了数据持久化的实时性**,目前已经是Redis持久化的主流方式。 默认情况下Redis没有开启AOF方式的持久化,可以通过appendonly参数启用`appendonly yes`。开启AOF方式持久化后每执行一条写命令,Redis就会将该命令写进aof_buf缓冲区,AOF缓冲区根据对应的策略向硬盘做同步操作。 @@ -808,6 +815,18 @@ public class TestSentinels { 哨兵模式解决了主从复制不能自动故障转移、达不到高可用的问题,但还是存在主节点的写能力、容量受限于单机配置的问题。 cluster模式实现了Redis的分布式存储,每个节点存储不同的内容,解决主节点的写能力、容量受限于单机配置的问题。 +> 总结,主从和哨兵可以饥饿绝高可用、高并发读的问题。但以下两个问题依然没有得到解决: +> +> + 海量数据存储问题 +> + 高并发写问题 +> +> 使用分片集群可以解决上述问题,分片集群的特征: +> +> + 集群有多个master,每个master保存不同的数据 +> + 每个master都可以有多个slave +> + master之间通过ping监测彼此健康状态 +> + 客户端请求可以访问集群任意节点,最终都会被转发到正确的节点 + #### 哈希分区算法 节点取余分区。使用特定的数据,如Redis的键或用户ID,对节点数量N取余:hash(key)%N计算出哈希值,用来决定数据映射到哪一个节点上。 diff --git "a/Redis/Redis\345\205\245\351\227\250\346\214\207\345\215\227\346\200\273\347\273\223.pdf" "b/Redis/Redis\345\205\245\351\227\250\346\214\207\345\215\227\346\200\273\347\273\223.pdf" new file mode 100644 index 0000000..8df73e0 Binary files /dev/null and "b/Redis/Redis\345\205\245\351\227\250\346\214\207\345\215\227\346\200\273\347\273\223.pdf" differ diff --git "a/Redis/Redis\351\235\242\350\257\225\351\242\230.md" "b/Redis/Redis\351\235\242\350\257\225\351\242\230.md" index b9a05f4..f394e2e 100644 --- "a/Redis/Redis\351\235\242\350\257\225\351\242\230.md" +++ "b/Redis/Redis\351\235\242\350\257\225\351\242\230.md" @@ -1,4 +1,4 @@ -## Redis是什么? +## Redis是什么 ? Redis(`Remote Dictionary Server`)是一个使用 C 语言编写的,高性能非关系型的键值对数据库。与传统数据库不同的是,Redis 的数据是存在内存中的,所以读写速度非常快,被广泛应用于缓存方向。Redis可以将数据写入磁盘中,保证了数据的安全不丢失,而且Redis的操作是原子性的。 @@ -95,10 +95,26 @@ Redis基于Reactor模式开发了网络事件处理器,这个处理器被称 ## Redis的内存用完了会怎样? +根据“八二原理“,即 80% 的请求访问了 20% 的数据,因此如果按照这个原理来配置,将 Redis 内存大小设置为数据总量的 20%,就有可能拦截到 80% 的请求。当然,只是有可能,对于不同的业务场景需要进行不同的配置,一般**建议把缓存容量设置为总数据量的 15% 到 30%,兼顾访问性能和内存空间开销**。 + 如果达到设置的上限,Redis的写命令会返回错误信息(但是读命令还可以正常返回)。 也可以配置内存淘汰机制,当Redis达到内存上限时会冲刷掉旧的内容。 +## 内存淘汰机制? + +allkeys:在设置了过期时间的数据中筛选;volatile:在所有数据中筛选 + +- noecition:默认,不淘汰,返回OOM报错信息 + +- allkeys-random:随机删除 +- allkeys-lru:使用 LRU 算法进行筛选删除 +- allkeys-lfu:使用 LFU 算法进行筛选删除 +- volatile-random:随机删除 +- volatile-ttl:根据过期时间先后进行删除,越早过期的越先被删除 +- volatile-lru:使用 LRU 算法进行筛选删除 +- volatile-lfu:使用 LFU 算法进行筛选删除 + ## Redis如何做内存优化? 可以好好利用Hash,list,sorted set,set等集合类型数据,因为通常情况下很多小的Key-Value可以用更紧凑的方式存放到一起。尽可能使用散列表(hashes),散列表(是说散列表里面存储的数少)使用的内存非常小,所以你应该尽可能的将你的数据模型抽象到一个散列表里面。比如你的web系统中有一个用户对象,不要为这个用户的名称,姓氏,邮箱,密码设置单独的key,而是应该把这个用户的所有信息存储到一张散列表里面。 @@ -574,7 +590,7 @@ PS:这种接口限流的实现方式比较简单,问题也比较多,一般 ## 什么是RedLock? -Redis 官方站提出了一种权威的基于 Redis 实现分布式锁的方式名叫 *Redlock*,此种方式比原先的单节点的方法更安全。它可以保证以下特性: +Redis 官方站提出了一种权威的基于 Redis 实现分布式锁的方式名叫 *Redlock*,此种方式比原先的单节点的方法更安全。 1. 安全特性:互斥访问,即永远只有一个 client 能拿到锁 2. 避免死锁:最终 client 都可能拿到锁,不会出现死锁的情况,即使原本锁住某资源的 client 挂掉了 @@ -582,9 +598,34 @@ Redis 官方站提出了一种权威的基于 Redis 实现分布式锁的方式 ## Redis大key怎么处理? +> BigKey的危害: +> +> + 网络阻塞:对BigKey执行读请求时,少陵的QPS就可能导致带宽被占满,导致redis实例乃至所在物理机变慢 +> + 数据倾斜:BigKey所在的Redis实例内存使用率远超其他实例,无法使数据分片的内存资源达到均衡 +> + Redis阻塞:对元素较多的hash、list、zset等做运算会耗时较久,使主线程阻塞 +> + CPU压力:对BigKey的数据序列化和反序列化会导致CPU的使用率飙升,影响Redis实例和本机其他应用 +> +> 如何发现BigKey : +> +> + redis-cli --bigkeys +> +> 利用redis-cli提供的--bigkeys参数,可以遍历分析所有key,并返回Key的整体统计信息与每个数据类型的Top1的BigKey +> +> + scan扫描 +> +> 自己编程,利用scan扫描Redis中的所有key,利用strlen、hlen等命令判断Key的长度(此处不建议使用MEMORY USAGE) +> +> + 第三方工具 +> +> 利用第三方工具,如Redis-Rdb-Tols分析RDB快照文件,全面分析内存使用情况 +> +> + 网络加快 +> +> 自定义工具,监控进出Redis的网络数据,超出预警值时主动告警 + 通常我们会将含有较大数据或含有大量成员、列表数的Key称之为大Key。 -以下是对各个数据类型大key的描述: +以下 是对各个数据类型大key的描述: - value是STRING类型,它的值超过5MB - value是ZSET、Hash、List、Set等集合类型时,它的成员数量超过1w个 @@ -594,7 +635,17 @@ Redis 官方站提出了一种权威的基于 Redis 实现分布式锁的方式 怎么处理: 1. 当vaule是string时,可以使用序列化、压缩算法将key的大小控制在合理范围内,但是序列化和反序列化都会带来更多时间上的消耗。或者将key进行拆分,一个大key分为不同的部分,记录每个部分的key,使用multiget等操作实现事务读取。 -2. 当value是list/set等集合类型时,根据预估的数据规模来进行分片,不同的元素计算后分到不同的片。 +2. 当value是list/set等集合类型时,根据预估的数据规模来进行分片,不同的元素计算后分到不同的片。 + +> 怎么删除BigKey? +> +> + Redis3.0以前 +> +> 如果是集合类型,则遍历BigKey的元素,先逐个删除子元素,最后删除BigKey +> +> + Redis4.0以后 +> +> Redis在4.0后提供了异步删除的命令:unlink ## Redis常见性能问题和解决方案? diff --git "a/Redis/Redis\351\235\242\350\257\225\351\242\230.pdf" "b/Redis/Redis\351\235\242\350\257\225\351\242\230.pdf" new file mode 100644 index 0000000..1887ec5 Binary files /dev/null and "b/Redis/Redis\351\235\242\350\257\225\351\242\230.pdf" differ diff --git "a/Redis/\347\274\223\345\255\230\347\251\277\351\200\217\343\200\201\347\274\223\345\255\230\351\233\252\345\264\251\343\200\201\347\274\223\345\255\230\345\207\273\347\251\277.md" "b/Redis/\347\274\223\345\255\230\347\251\277\351\200\217\343\200\201\347\274\223\345\255\230\351\233\252\345\264\251\343\200\201\347\274\223\345\255\230\345\207\273\347\251\277.md" index ca08607..07a49a1 100644 --- "a/Redis/\347\274\223\345\255\230\347\251\277\351\200\217\343\200\201\347\274\223\345\255\230\351\233\252\345\264\251\343\200\201\347\274\223\345\255\230\345\207\273\347\251\277.md" +++ "b/Redis/\347\274\223\345\255\230\347\251\277\351\200\217\343\200\201\347\274\223\345\255\230\351\233\252\345\264\251\343\200\201\347\274\223\345\255\230\345\207\273\347\251\277.md" @@ -8,6 +8,8 @@ +[缓存三问题]: https://cloud.tencent.com/developer/article/2046488 + # 缓存穿透 缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时被动写的,如果从DB查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到DB去查询,失去了缓存的意义。在流量大时,可能DB就挂掉了。 diff --git a/fsg b/fsg new file mode 100644 index 0000000..dd84d20 --- /dev/null +++ b/fsg @@ -0,0 +1,629 @@ +commit 8f8e07cd359bc88430495d0aeed3d3a417aa7107 (HEAD -> master, origin/master, origin/HEAD) +Author: tyson +Date: Tue Jul 5 08:28:01 2022 +0800 + + 更改目录 + +commit 4dc2e1c43caabd59ef24f6df046ddc5840275ae1 +Author: tyson +Date: Sun Jun 19 17:15:50 2022 +0800 + + update + +commit 8ef828dd4e63fd24fa28b06b2334ec0f863b1715 +Author: tyson +Date: Thu Jun 16 23:32:40 2022 +0800 + + update + +commit 1afc40b4f82950c3153ab2753d0bc3a3bfaf30e1 +Author: tyson +Date: Fri Jun 3 14:38:18 2022 +0800 + + 调整目录结构 + +commit 156db24662d9c971173edfdf1c30c36662976135 +Author: tyson +Date: Sun May 22 20:14:47 2022 +0800 + + update + +commit bc29969701ab5354886331a1c405cd0975e96be8 +Author: tyson +Date: Sun May 22 16:57:41 2022 +0800 + + update + +commit 415bd82b7b98c8e75e60a4f70c32d4a081a84493 +Author: tyson +Date: Wed May 18 21:20:58 2022 +0800 + + update img url + +commit 14844a8d7c1441c5184ef02cab7ce54f41a2d4be +Author: tyson +Date: Wed May 18 21:15:06 2022 +0800 + + update img url + +commit 75801c53fe4162b5b615edb91101666607eea014 +Author: tyson +Date: Tue May 10 21:02:30 2022 +0800 + + update + +commit e44546f63d22dd1f953d561405f69b77348c0d3c +Author: tyson +Date: Sat Mar 26 14:46:53 2022 +0800 + + update img path + +commit 9234ac1f36f8d3920b537a1fc7b41034319f201f +Author: tyson +Date: Sat Mar 26 14:34:34 2022 +0800 + + add 操作系统 + +commit 09ae10db27d8352d7a60fbada8f2f797594cfe90 +Author: tyson +Date: Sat Mar 26 14:33:16 2022 +0800 + + 更新Java基础面试题 + +commit dc17e5157e9de057dd4f34062cb395b7475daf9a +Author: tyson +Date: Sat Mar 26 10:51:22 2022 +0800 + + Java基础面试题补充 + +commit b9e246dc14f55d87c41ce9397d5a687918bea22b +Author: tyson +Date: Mon Mar 21 12:05:13 2022 +0800 + + 增加消息队列面试题 + +commit 76efb6e79383466814af0e3fbf0b2e2b02d20349 +Author: tyson +Date: Sun Mar 20 11:40:39 2022 +0800 + + Redis面试题补充 + +commit 24b957b1ea052967458a33a55d6cf2b83dbc6a1a +Author: tyson +Date: Sat Mar 19 14:09:45 2022 +0800 + + 增加Java并发面试题 + +commit da27883e5049eaa3bfc9cdff183235a8cc2b76fa +Author: tyson +Date: Fri Mar 11 08:49:32 2022 +0800 + + LeetCode刷题技巧 + +commit c07d8623b63ab75ca9d4b2f3956d5742a5b79f58 +Author: tyson +Date: Sun Mar 6 18:09:06 2022 +0800 + + 怎么写简历 + +commit c575e476cfaa9be5c8934c6de80b27baeef88335 +Author: tyson +Date: Sun Mar 6 12:06:00 2022 +0800 + + 图解索引下推 + +commit a0f984384379fe5df12d47ab86716a0cdf3cfdd9 +Author: tyson +Date: Wed Mar 2 18:00:46 2022 +0800 + + 存储过程语句查看 + +commit 665c518390f875bf6002256243f1746ae477d2ac +Author: tyson +Date: Mon Feb 28 12:11:14 2022 +0800 + + add Springboot面试题总结 + +commit 472280dcafdf69bac915a6df9a30237235ff4cc0 +Author: tyson +Date: Sun Feb 27 19:05:28 2022 +0800 + + update readme + +commit 456157e0964f53ce5147ea3c69e29a445a689a7c +Author: tyson +Date: Sun Feb 27 18:07:38 2022 +0800 + + 整理Spring面试题 + +commit da6295e00b59696c99cc810493be2b2df482570e +Author: tyson +Date: Sun Feb 27 18:02:58 2022 +0800 + + 整理JVM面试题 + +commit c1f015c2b9102c74e7419bb206c05dc13e94aad1 +Author: tyson +Date: Sun Feb 27 12:29:48 2022 +0800 + + Java集合面试题整理 + +commit 59f74b80fa1e2630565993a54d2ea3f5ef603d16 +Author: tyson +Date: Sun Feb 27 00:31:00 2022 +0800 + + Java核心知识面试题整理 + +commit 8b08743b38340b9b8fce41dc9dbcb583cc5ab7fa +Author: tyson +Date: Sat Feb 26 18:22:13 2022 +0800 + + 并发知识点整理补充 + +commit 59267fe8354383a6fbe3578f6e3e46c983ee19a9 +Author: tyson +Date: Sat Feb 12 00:19:21 2022 +0800 + + 更新jvm jinfo + +commit de7997162bfc9305046e4db0c1147cc226d280ca +Author: tyson +Date: Sat Feb 12 00:18:44 2022 +0800 + + 更新MySQL幻读 + +commit 8f3014a19f7173dbb7fa715a77bc37bab6cf18d4 +Author: tyson +Date: Sun Dec 19 09:09:12 2021 +0800 + + 修正全文索引 + +commit 7f1a1d8406ce0e52d4bd442be09497970c398065 +Author: tyson +Date: Fri Dec 10 21:52:30 2021 +0800 + + update + +commit 30c124459fd93ca52e11b0132c0023ef4e811788 +Author: tyson +Date: Sun Nov 28 11:38:48 2021 +0800 + + Java高频面试题整理 + +commit 3960e09dd178aad0cdf39689bd6949ffb4d6d8b8 +Author: tyson +Date: Sat Nov 20 14:50:46 2021 +0800 + + update + +commit 58fb72646705dd810ad5e10b3200eabe4faba9f8 +Author: tyson +Date: Sat Nov 20 14:49:37 2021 +0800 + + update + +commit 502966a0668c3d097facf894e54060cdf76ff967 +Author: tyson +Date: Sun Nov 14 11:43:36 2021 +0800 + + update + +commit 726c05f44d61ef09568e2f51d7c4dc73e776c247 +Author: tyson +Date: Sun Oct 31 16:10:31 2021 +0800 + + 赞赏码 + +commit a3d77949ed8cfa668c9cf08825d2e409cd8292d8 +Author: tyson +Date: Sun Oct 24 17:25:34 2021 +0800 + + add Spring高频面试题 + +commit 07ec6477f03d0d5db3debd435e06965827423a82 +Author: tyson +Date: Mon Oct 18 23:36:43 2021 +0800 + + update docker + +commit 24d97d67e88a59d9bc46118146bc9ea547ad9b19 +Author: tyson +Date: Sun Oct 17 21:12:57 2021 +0800 + + update + +commit e490fac7c8ea513c8691cd20a7a7026544957580 +Author: tyson +Date: Sun Oct 17 21:04:19 2021 +0800 + + 更新计算机网络面试题 + +commit 2d6f950b5720ad4488821d09964cd9a0898a2720 +Author: tyson +Date: Sun Oct 17 00:08:50 2021 +0800 + + 更新MySQL高频面试题 + +commit df5781a5a2376898940467ac72bf9c5472bfe1ac +Author: tyson +Date: Tue Oct 12 08:23:41 2021 +0800 + + update + +commit 49a4cc1062de088de6bc66a4005243afd3011709 +Author: tyson +Date: Sun Oct 10 16:05:53 2021 +0800 + + 更新jvm面试题 + +commit 8ac00f25b4e19bbfc90c8c0fdb806467cdbb10ee +Author: tyson +Date: Fri Oct 8 21:52:59 2021 +0800 + + update + +commit 62388cc28ce04538b2fed5bb97b4df50746631d5 +Author: tyson +Date: Thu Oct 7 15:41:32 2021 +0800 + + Redis面试题 + +commit edb782cf57b9c75981afe0ca18bf56ae31424264 +Author: tyson +Date: Tue Oct 5 17:18:11 2021 +0800 + + update + +commit 8f8177c756c86b7a9ba5969758bf39793bfde00a +Author: tyson +Date: Tue Oct 5 16:22:19 2021 +0800 + + update + +commit 6865c23a9bb699b50a5124e65a178c38cf019ef7 +Author: tyson +Date: Tue Oct 5 13:38:21 2021 +0800 + + 更新目录 + +commit 503df1e37adee3eda71fe8655a6bcc58a9dd8cf2 +Author: tyson +Date: Mon Oct 4 23:58:44 2021 +0800 + + 增加jvm、集合、redis面试题 + +commit 2898273138bc88c42b5ec430dfd206c8543cd88f +Author: tyson +Date: Sat Sep 25 16:39:49 2021 +0800 + + update + +commit 8e457121d1f23822c33432b4629323fbc917e6d0 +Author: tyson +Date: Sat Sep 25 16:07:26 2021 +0800 + + 更新MySQL高频面试题目录 + +commit 1267e3a1d4b8d435c760b8eb174d7fb621cb6401 +Author: tyson +Date: Sat Sep 25 16:03:48 2021 +0800 + + MySQL高频面试题 + +commit 952f6a814eea76cde1e3d2b37c93d63a9940e51b +Author: tyson +Date: Tue Sep 21 12:29:51 2021 +0800 + + 增加计算机网络高频面试题 + +commit a06ec7c432a9b65203a69bb9ab4cea474bcf6b31 +Author: tyson +Date: Sun Sep 19 17:16:27 2021 +0800 + + 添加Java面试题 + +commit b2a8aaf67e7d8056e3c09ac85269eec5626b6b43 +Author: tyson +Date: Sun Sep 19 13:11:35 2021 +0800 + + 添加Java并发高频面试题目(精华版) + +commit f27b1f8e5e8e6304ce23882540fa340cfff09297 +Author: tyson +Date: Wed Sep 15 08:46:20 2021 +0800 + + 更新RabbitMQ核心知识总结 + +commit 6652a883480135f80dbe37bbb25f3bd31c0995f5 +Author: tyson +Date: Tue Sep 14 00:11:03 2021 +0800 + + 更新目录 + +commit b8e9ee6b619730591f8e32e84dc8ee649ae9ad6c +Author: tyson +Date: Tue Sep 14 00:09:28 2021 +0800 + + 更新Redis基础知识 + +commit cca80d8275aca6dbee393ed201d9a4c7ea6fffc7 +Author: tyson +Date: Sun Sep 12 16:22:40 2021 +0800 + + 网络分层结构 + +commit a84159e3a46fa435c3055c695671c3551b277c5a +Author: tyson +Date: Sun Sep 12 00:44:38 2021 +0800 + + update数据结构与算法 + +commit 061a290bbee12c9a02c7a4ebff2b0f0ab4761b68 +Author: tyson +Date: Sat Sep 11 17:10:57 2021 +0800 + + github使用技巧 + +commit 77cbb099b9ce0ca2998df25cea34e835073eb891 +Author: tyson +Date: Sat Sep 11 16:20:07 2021 +0800 + + update + +commit 8b1e07d24ba1a3eb7c6214ce7f590bca29a68521 +Author: tyson +Date: Sat Sep 11 11:46:47 2021 +0800 + + 更新Java并发总结 + +commit fcae887ada18a6490c10b820252606b24c7652a7 +Author: tyson +Date: Fri Sep 10 23:33:11 2021 +0800 + + 更新Java基础知识总结 + +commit 816ea84db15fcda457ef0fbbbaa76ec0caaf6936 +Author: tyson +Date: Fri Sep 10 08:51:00 2021 +0800 + + 更新并发总结 + +commit 5e7d3ae067f1d77608cb9c052e060520886212ff +Author: tyson +Date: Wed Sep 8 23:22:34 2021 +0800 + + update + +commit ae514b24061e5c79a0589bea0223d6ad17265df4 +Author: tyson +Date: Tue Sep 7 22:29:30 2021 +0800 + + 完善Java8总结 + +commit 1168cf6dfa18254b54821446add1911f6f773d3d +Author: tyson +Date: Sun Sep 5 22:00:58 2021 +0800 + + 完善容器总结 + +commit 0e2f0bb19821c9c9a0e1b9bcc102c97cf3bf7485 +Author: tyson +Date: Sun Sep 5 16:52:30 2021 +0800 + + jvm总结 + +commit 4ef566bf0c3ac655c00d55d12da4f77be783a3f2 +Author: tyson +Date: Wed Sep 1 22:34:28 2021 +0800 + + update Git总结 + +commit 2465904ba0908d827056409e127d23076141801c +Author: tyson +Date: Wed Sep 1 22:11:04 2021 +0800 + + update README + +commit 08e663a1e642fd78f8355feb9ffdd8c2db9a567e +Author: tyson +Date: Tue Aug 31 22:22:40 2021 +0800 + + git总结 + +commit 75f8b362b17222d3e1e7b0d7be633a16b57a283a +Author: tyson +Date: Tue Aug 24 00:05:36 2021 +0800 + + update + +commit cd72e4ff0f3b39cb5193b8230fb878f618be9448 +Author: tyson +Date: Sat Aug 21 17:12:41 2021 +0800 + + 删除查询性能优化 + +commit 6bddc95b583b3c54203b4f21df9462c4c091671d +Author: tyson +Date: Sat Aug 21 16:16:23 2021 +0800 + + MySQL总结整理 + +commit f8ace0e1e3b56ea456dd39ec45f3e59ff742e99e +Author: tyson +Date: Tue Aug 17 08:37:17 2021 +0800 + + java常见关键字总结 + +commit 0c4efeba935b9a848dffaae4d4ec7b91b54fd34e +Author: tyson +Date: Sun Aug 15 23:38:19 2021 +0800 + + 删除android + +commit 4844de5e0eb31e88370cb7426dc0717c9a3e53fb +Author: tyson +Date: Wed Aug 4 21:48:42 2021 +0800 + + mysql执行计划 + +commit 635c140a06923a1a8accf06a8d309a5cad0fd366 +Author: tyson +Date: Sun Aug 1 18:20:15 2021 +0800 + + redis分布式锁 + +commit 7b65bc3027aaec3a98650d478fddc720dc831e9e +Author: tyson +Date: Sun Aug 1 11:22:36 2021 +0800 + + update + +commit e563eec7dd2ddc76d3b9d42f4cbfbf80dbdd5a9c +Author: tyson +Date: Sun Aug 1 11:18:52 2021 +0800 + + update + +commit 67e1cf7c26ce1a7ea4deb1392bd576c8896dfa10 +Author: tyson +Date: Sun Aug 1 11:02:23 2021 +0800 + + update readme + +commit 218f353cfde7094a80758908137e7f458592bf42 +Author: tyson +Date: Sun Aug 1 10:47:41 2021 +0800 + + 调整目录结构 + +commit 94283146d1620e972816ec708c85c9d208a96095 +Author: tyson +Date: Sun Aug 1 10:29:57 2021 +0800 + + 整理Java基础内容 + +commit fccdc1f4e78279472d6e653295749e941302f413 +Author: tyson +Date: Sun Jul 18 00:56:47 2021 +0800 + + update + +commit 82fbeb5b7a26a7e3f3f4be3b3025e22477e3fbd2 +Author: tyson +Date: Wed Jun 23 22:52:34 2021 +0800 + + cdn + +commit 6082ec086ad597225e7d00798de924118c8ee95b +Author: tyson +Date: Sun Jun 20 01:01:45 2021 +0800 + + 更新docker + +commit 5029123857cd2d31e0aa6b64ba6f55a1323ddaa4 +Author: tyson +Date: Wed Jun 16 08:45:43 2021 +0800 + + update grep + +commit 2cf906bcc36d977caa980d48bce9af7c945849d5 +Author: tyson +Date: Sun May 9 20:55:53 2021 +0800 + + servlet补充 + +commit e5031ffd9feac4e9d7d06e6a86f52732331183f7 +Author: tyson +Date: Thu May 6 01:39:23 2021 +0800 + + update Linux + +commit a318da0e81442d52fa758d8afb48512990545ec2 +Author: tyson +Date: Wed May 5 22:02:44 2021 +0800 + + update目录 + +commit 1304651e805a5eeacef5609ae9e6b8336c8842e9 +Author: tyson +Date: Thu Apr 29 08:31:03 2021 +0800 + + 修改图片链接 + +commit f5bc7373b8de643f661db24aa3dd37bb1b8a2fb4 +Author: tyson +Date: Thu Apr 22 23:26:05 2021 +0800 + + 单体应用和微服务的优缺点 + +commit ca3d044bd3ec0c79321a0d2e335bb91a380b7206 +Author: tyson +Date: Wed Apr 21 23:44:49 2021 +0800 + + jenkins + +commit 4b3d0a59b48f31b20d819d25559f737a845d12e7 +Author: tyson +Date: Wed Apr 21 23:41:11 2021 +0800 + + docker + +commit 3ebf1cee3ce8ba920adf91ac8f94d856a0827864 +Author: tyson +Date: Wed Apr 21 23:40:58 2021 +0800 + + nginx update + +commit 6d70fd897f613901737501278f7f471bb39a41de +Author: tyson +Date: Wed Apr 21 23:40:22 2021 +0800 + + linux命令补充 + +commit bd5c9b3d75b7b8b9f67567ad7d6fef42dc96a9a2 +Author: tyson +Date: Sat Apr 17 10:56:20 2021 +0800 + + nio/bio补充 + +commit edcc52bc57bea61f522ae3fc680494592dc3711a +Author: tyson +Date: Sat Apr 17 10:55:53 2021 +0800 + + tomcat和netty区别 + +commit 8bb882892f9e774dea8c24b71fc85097a87a2c6b +Author: tyson +Date: Fri Apr 16 09:29:29 2021 +0800 + + 补充websocket + +commit c342b4ccd786963df36f53cf7d3a5680fd5bb865 +Author: tyson +Date: Fri Apr 16 08:46:20 2021 +0800 + + spring cloud security、oauth2 + +commit 4d2059c3e09f5bfa041f49d36b4fd5cf79c46796 +Author: tyson +Date: Mon Apr 5 22:42:05 2021 +0800 + + spring cloud gateway + +commit e9d07dff524c508cca859a2de5ce40738fa27ac5 +Author: tyson +Date: Sun Apr 4 21:49:05 2021 +0800 + + spring cloud bus + +commit 44c8a250b534a3bff7b5fc53a289759c936d72b6 +Author: tyson +Date: Sun Apr 4 00:40:13 2021 +0800 + + zuul、config + +commit ef4eef6a62c481fdad1d74c41fc0e9db7c02051e +Author: tyson +Date: Mon Mar 15 13:24:51 2021 +0800 + + git rebase -i diff --git "a/\346\225\260\346\215\256\345\272\223/MySQL\351\253\230\351\242\221\351\235\242\350\257\225\351\242\230.md" "b/\346\225\260\346\215\256\345\272\223/MySQL\351\253\230\351\242\221\351\235\242\350\257\225\351\242\230.md" index 123d7cc..0b699af 100644 --- "a/\346\225\260\346\215\256\345\272\223/MySQL\351\253\230\351\242\221\351\235\242\350\257\225\351\242\230.md" +++ "b/\346\225\260\346\215\256\345\272\223/MySQL\351\253\230\351\242\221\351\235\242\350\257\225\351\242\230.md" @@ -385,6 +385,8 @@ MEMORY引擎默认使用哈希索引,将键的哈希值和指向数据行的 3. 只支持等值比较,不支持范围查询。 4. 当出现哈希冲突时,存储引擎需要遍历链表中所有的行指针,逐行进行比较,直到找到符合条件的行。 +**适用场景:**存储临时表 + **ARCHIVE存储引擎** ARCHIVE存储引擎非常适合存储大量独立的、作为历史记录的数据。ARCHIVE提供了压缩功能,拥有高效的插入速度,但是这种引擎不支持索引,所以查询性能较差。 @@ -392,14 +394,16 @@ ARCHIVE存储引擎非常适合存储大量独立的、作为历史记录的数 ## MyISAM和InnoDB的区别? 1. **是否支持行级锁** : `MyISAM` 只有表级锁,而`InnoDB` 支持行级锁和表级锁,默认为行级锁。 - 2. **是否支持事务和崩溃后的安全恢复**: `MyISAM` 不提供事务支持。而`InnoDB `提供事务支持,具有事务、回滚和崩溃修复能力。 - 3. **是否支持外键:** `MyISAM`不支持,而`InnoDB`支持。 - 4. **是否支持MVCC** :`MyISAM`不支持,`InnoDB`支持。应对高并发事务,MVCC比单纯的加锁更高效。 - 5. `MyISAM`不支持聚集索引,`InnoDB`支持聚集索引。 +6. MyISAM强调性能,执行速度比InnoDB引擎更快 +7. InnoDB不支持FULLTEXT类型的索引,MyISAM支持全文索引 +8. 清空整个表时,InnoDB是一行一行的删除,效率非常慢。MyISAM则会重建表。 +9. 是否支持热备份,InnoDB支持热备份,MyISAM可以配合锁,实现操作系统下的复制备份、迁移 + +**场景:**MyISAM适合查询以及插入为主的应用,InnoDB适合频繁修改以及涉及到安全性较高的应用 ## MVCC 实现原理? @@ -800,7 +804,7 @@ int(10)中的10表示的是显示数据的长度,而char(10)表示的是存储 ## MySQL查询 limit 1000,10 和limit 10 速度一样快吗? -两种查询方式。对应 `limit offset, size` 和 `limit size` 两种方式。 +两种查询方式。对应 `limit offset, size` 和 `limit size` 两种方式,其中offset表示偏移值,size表示需要返回的数据行数量 而其实 `limit size` ,相当于 `limit 0, size`。也就是从0开始取size条数据。 @@ -866,6 +870,35 @@ mysql 通过主键索引,每次定位到start_id的位置,然后往后遍历10个数据,这样不管数据多大,查询性能都较为稳定。 +**方法三:** + +当偏移超过一半记录数的时候,先用排序,这样偏移就反转了 + +limit偏移算法: +正向查找: (当前页 – 1) * 页长度 +反向查找: 总记录 – 当前页 * 页长度 + +```sql +SELECT * FROM `abc` WHERE `BatchID` = 123 LIMIT 839960, 40 +- 时间:1.8696 秒 - +SELECT * FROM `abc` WHERE `BatchID` = 123 ORDER BY InputDate DESC LIMIT 788775, +- 时间:1.8336 秒 - +``` + +方法1、2、3的前提都是数据主键索引有序的情况下使用 + +**方法四:** + +如果主键id是无序的,可以用inner join来优化 + +```sql +select t.* from tb_test t +inner join (select id from tb_test where val = 4 limit 100000, 5) tmp +on t.id = tmp.id; +``` + +**如果要优化limit查询的话,where条件中的字段一定要有索引。** + ## 高度为3的B+树,可以存放多少数据? InnoDB存储引擎有自己的最小储存单元——页(Page)。 diff --git "a/\346\241\206\346\236\266/Mybatis\351\235\242\350\257\225\351\242\230.md" "b/\346\241\206\346\236\266/Mybatis\351\235\242\350\257\225\351\242\230.md" index 5dddfd8..c499447 100644 --- "a/\346\241\206\346\236\266/Mybatis\351\235\242\350\257\225\351\242\230.md" +++ "b/\346\241\206\346\236\266/Mybatis\351\235\242\350\257\225\351\242\230.md" @@ -19,7 +19,7 @@ Hibernate属于全自动ORM映射工具,使用Hibernate查询关联对象或 **优点** -1. 与JDBC相比,减少了50%以上的代码量。 +1. 与JDBC相比,减少了50%以上的代码量。 2. MyBatis是易学的持久层框架,小巧并且简单易学。 3. MyBatis相当灵活,不会对应用程序或者数据库的现有设计强加任何影响,SQL写在XML文件里,从程序代码中彻底分离,降低耦合度,便于统一的管理和优化,并可重用。 4. 提供XML标签,支持编写动态的SQL,满足不同的业务需求。 @@ -45,6 +45,8 @@ MyBatis专注于SQL自身,是一个足够灵活的DAO层解决方案。对性 - 输入参数映射:输入参数类型可以是Map、List等集合类型,也可以是基本数据类型和POJO类型。输入参数映射过程类似于 JDBC对preparedStatement对象设置参数的过程。 - 输出结果映射:输出结果类型可以是Map、List等集合类型,也可以是基本数据类型和POJO类型。输出结果映射过程类似于 JDBC对结果集的解析过程。 +![http://c.biancheng.net/uploads/allimg/190704/5-1ZF4130T31N.png](http://c.biancheng.net/uploads/allimg/190704/5-1ZF4130T31N.png) + ## Mybatis都有哪些Executor执行器?它们之间的区别是什么? Mybatis有三种基本的Executor执行器,`SimpleExecutor`、`ReuseExecutor`、`BatchExecutor`。 @@ -68,10 +70,42 @@ Mybatis 使用 RowBounds 对象进行分页,它是针对 ResultSet 结果集 可以在 sql 内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。 +## 物理分页和内存分页(逻辑分页)? + +### 一 概述 + +#### 1.物理分页 + +物理分页依赖的是某一物理实体,这个物理实体就是数据库,比如MySQL数据库提供了limit关键字,程序员只需要编写带有limit关键字的SQL语句,数据库返回的就是分页结果。 + +#### 2.逻辑分页 + +逻辑分页依赖的是程序员编写的代码。数据库返回的不是分页结果,而是全部数据,然后再由程序员通过代码获取分页数据,常用的操作是一次性从数据库中查询出全部数据并存储到List集合中,因为List集合有序,再根据索引获取指定范围的数据。 + +### 二 对比 + +#### 1.数据库负担 + +物理分页每次都访问数据库,逻辑分页只访问一次数据库,物理分页对数据库造成的负担大。 + +#### 2.服务器负担 + +逻辑分页一次性将数据读取到内存,占用了较大的内容空间,物理分页每次只读取一部分数据,占用内存空间较小。 + +#### 3.实时性 + +逻辑分页一次性将数据读取到内存,数据发生改变,数据库的最新状态不能实时反映到操作中,实时性差。物理分页每次需要数据时都访问数据库,能够获取数据库的最新状态,实时性强。 + +#### 4.适用场合 + +逻辑分页主要用于数据量不大、数据稳定的场合,物理分页主要用于数据量较大、更新频繁的场合。 + ## 分页插件的基本原理是什么? 分页插件的基本原理是使用 Mybatis 提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的 sql,然后重写 sql(SQL 拼接 limit),根据 dialect 方言,添加对应的物理分页语句和物理分页参数,用到了技术 JDK 动态代理,用到了责任链设计模式。 +> 例如:PageHelper是[MyBatis](https://so.csdn.net/so/search?q=MyBatis&spm=1001.2101.3001.7020)的一个插件,内部实现了一个PageInterceptor拦截器。Mybatis会加载这个拦截器到拦截器链中。在我们使用过程中先使用PageHelper.startPage这样的语句在当前线程上下文中设置一个ThreadLocal变量,再利用PageInterceptor这个分页拦截器拦截,从ThreadLocal中拿到分页的信息,如果有分页信息拼装分页SQL(limit语句等)进行分页查询,最后再把ThreadLocal中的东西清除掉。 + ## 简述Mybatis的插件运行原理 Mybatis仅可以编写针对 `ParameterHandler`、`ResultSetHandler`、`StatementHandler`、`Executor`这4种接口的插件,Mybatis使用JDK的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这4种接口对象的方法时,就会进入拦截方法,具体就是`InvocationHandler`的invoke()方法,当然,只会拦截那些你指定需要拦截的方法。 diff --git "a/\346\241\206\346\236\266/PageHelper.md" "b/\346\241\206\346\236\266/PageHelper.md" new file mode 100644 index 0000000..ac08692 --- /dev/null +++ "b/\346\241\206\346\236\266/PageHelper.md" @@ -0,0 +1,80 @@ +# PageHelper + +## 什么是分页 + +​ 分页,是一种将所有数据分段展示给用户的技术.用户每次看到的不是全部数据,而是其中的一部分,如果在其中没有找到自习自己想要的内容,用户可以通过制定页码或是翻页的方式转换可见内容,直到找到自己想要的内容为止.其实这和我们阅读书籍很类似。可提高用户体验度,同时减少一次性加载,[内存](https://so.csdn.net/so/search?q=内存&spm=1001.2101.3001.7020)溢出风险。 + +## 分页的意义 + +​ 分页确实有效,但它一定会加大系统的复杂度,但可否不分页呢?如果数据量少的话当然可以.但是对于企业信息系统来说数据量不会限制在一个小范围内.如果不顾一切的Select * from某个表,再将返回的数据一古脑的扔给客户,即使客户能够忍受成千上万足够让人眼花缭乱的表格式数据,繁忙的网络,紧张的服务器也会提出它们无声的抗议,甚至有时会以彻底的罢工作为终结。 + +## 分页的实现 + +​ 用户发起请求,后端查询数据库返回所有的条数,并且返回用户所需要的数据,比方说用户请求的是第一页(page = 1),用户设置的第一页的数据显示条数为50条(limit=50),那么后台查询满足条件的数据,并且返回前50条给用户显示,此时用户看到的就是第一页的50条数据,加入用户请求的是第二页的数据,那么传给后台page为2,显示条数limit为50后台查询的就是符合条件的51-100条数据返回给用户。 + +## PageHelper中SQL语句怎么拼接 + +在调用PageHelper.startPage()方法后,会根据传入的分页参数生成一个Page对象,然后将Page对象设置到ThreadLocal变量中去。在组装SQL语句的时候,从ThrealLocal变量中获取分页参数,通过实现 Mybatis 的 Interceptor 接口完成对 query sql 的动态分页, + +> 简单的分页执行过程 +> +> 1. 设置 page 参数 +> 2. 执行 query 方法 +> 3. Interceptor 接口 中校验 ThreadLocal 中是否存在有设置的 page 参数 +> 4. 存在 page 参数,重新生成 `count sql` 和 `page sql`,并执行查询。不存在 page 参数,直接返回 查询结果 +> 5. 执行 `LOCAL_PAGE.remove()`清除 page 参数 + +## PageHelper并发会出现什么问题 + +​ startPage方法把分页信息Pagination存放到了ThreadLocal里。ThreadLocal是线程保护的,作用域只限于当前线程。 + +​ 观察上述的执行过程,可以发现,如果在第 1 步和第 2 步 之间发生异常,那么 LOCAL_PAGE 中当前线程对应的 page 参数并不会 remove。 + +​ 在不使用线程池的情况下,当前线程在执行完毕后会被销毁,这时 当前线程 中的 threadLocals 参数 将会被情况,也就清空 了 LOCAL_PAGE 中 当前线程的 page 参数。 + +​ 但是如果使用了线程池,当前线程执行完毕,并不会被销毁,而是会将当前线程再次存放到池中,标记为空闲状态,以便后续使用。在后续使用这个线程的时候,由于 线程 的 threadLocals 依旧存在有值,尽管我们在第 1 步时未设置 page 参数,第 3 步 的也能获取到page参数,从而生成 count sql 和 page sql,从而影响我们的正常查询。SpringBoot 项目中会使用内置的 Tomcat 作为服务器,而Tomcat会默认使用线程池来处理请求,从而便引发了上述问题。 + +### 解决方案 + +​ 因为Tomcat的线程是用来处理request请求,那么在请求完成时,清空当前线程的threadLocals 属性值,也就是执行LOCAL_PAGE.remove() 即可。 + +#### 实现方式: + +1. 使用 aop,对所有 controller 进行处理 +2. 实现 HandlerInterceptor 或者 WebRequestInterceptor 对 request 请求的拦截器接口,通过 afterCompletion 方法执行 LOCAL_PAGE.remove() 。 + +```java +public class PageLocalWebInterceptor implements HandlerInterceptor { + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { + + // PageHelper.clearPage() 内部调用 LOCAL_PAGE.remove() + PageHelper.clearPage(); + + } +} + +``` + +定义配置类,配置类需实现 WebMvcConfigurer 接口完成对于WebMvc的相关配置 ,注册 PageLocalWebInterceptor : + +```java +@Configuration +public class FrameworkAutoConfig implements WebMvcConfigurer { + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(new PageLocalWebInterceptor()); + } +} + +``` + + + +## 参考 + +1. [分页查询原理]: https://blog.csdn.net/qq_43386944/article/details/119635774 + + + diff --git "a/\346\241\206\346\236\266/Shiro.md" "b/\346\241\206\346\236\266/Shiro.md" new file mode 100644 index 0000000..01c9e1c --- /dev/null +++ "b/\346\241\206\346\236\266/Shiro.md" @@ -0,0 +1,2 @@ +# Shiro + diff --git "a/\346\241\206\346\236\266/SpringBoot\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md" "b/\346\241\206\346\236\266/SpringBoot\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md" index 7e70a4c..5c4f865 100644 --- "a/\346\241\206\346\236\266/SpringBoot\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md" +++ "b/\346\241\206\346\236\266/SpringBoot\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md" @@ -3,7 +3,7 @@ - 内置servlet容器,不需要在服务器部署 tomcat。只需要将项目打成 jar 包,使用 java -jar xxx.jar一键式启动项目 - SpringBoot提供了starter,把常用库聚合在一起,简化复杂的环境配置,快速搭建spring应用环境 - 可以快速创建独立运行的spring项目,集成主流框架 -- 准生产环境的运行应用监控 +- 准生产环境的运行应用监控 ,我们可以引入 spring-boot-start-actuator 依赖,直接使用 REST 方式来获取进程的运行期性能参数,从而达到监控的目的,比较方便。但是 Spring Boot 只是个微框架,没有提供相应的服务发现与注册的配套功能,没有外围监控集成方案,没有外围安全管理方案,所以在微服务架构中,还需要 Spring Cloud 来配合一起使用。 ## SpringBoot 中的 starter 到底是什么 ? @@ -12,8 +12,10 @@ starter提供了一个自动化配置类,一般命名为 XXXAutoConfiguration ## 运行 SpringBoot 有哪几种方式? 1. 打包用命令或者者放到容器中运行 -2. 用 Maven/Gradle 插件运行 -3. 直接执行 main 方法运行 + - 打包成jar包后,利用`java -jar xxx.jar`运行 + - 打包成war包后,利用`java -jar xxx.war`运行 +2. 用 Maven/Gradle 插件运行,如:mvn spring-boot:run +3. 直接运行启动类(main方法) ## SpringBoot 常用的 Starter 有哪些? @@ -24,6 +26,8 @@ starter提供了一个自动化配置类,一般命名为 XXXAutoConfiguration ## 自动配置原理 +[Spring Boot面试必问:自动配置原理]: https://blog.csdn.net/weixin_42556307/article/details/108405009 + SpringBoot实现自动配置原理图解: > 公众号【程序员大彬】,回复【自动配置】下载高清图片 diff --git "a/\346\241\206\346\236\266/SpringBoot\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.pdf" "b/\346\241\206\346\236\266/SpringBoot\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.pdf" new file mode 100644 index 0000000..cd40617 Binary files /dev/null and "b/\346\241\206\346\236\266/SpringBoot\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.pdf" differ diff --git "a/\346\241\206\346\236\266/Spring\351\235\242\350\257\225\351\242\230.md" "b/\346\241\206\346\236\266/Spring\351\235\242\350\257\225\351\242\230.md" index 82c11b5..272a4e9 100644 --- "a/\346\241\206\346\236\266/Spring\351\235\242\350\257\225\351\242\230.md" +++ "b/\346\241\206\346\236\266/Spring\351\235\242\350\257\225\351\242\230.md" @@ -1,9 +1,9 @@ -## Spring的优点 +## Spring的优点 - 通过控制反转和依赖注入实现**松耦合**。 - 支持**面向切面**的编程,并且把应用业务逻辑和系统服务分开。 - 通过切面和模板减少样板式代码。 -- 声明事物的支持。可以从单调繁冗的事务管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量。 +- 声明事务的支持。可以从单调繁冗的事务管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量。 - 方便集成各种优秀框架。内部提供了对各种优秀框架的直接支持(如:Hessian、Quartz、MyBatis等)。 - 方便程序的测试。Spring支持Junit4,添加注解便可以测试Spring程序。 @@ -72,10 +72,86 @@ AOP有两种实现方式:静态代理和动态代理。 **静态代理** -静态代理:代理类在编译阶段生成,在编译阶段将通知织入Java字节码中,也称编译时增强。AspectJ使用的是静态代理。 +静态代理:代理类是我们定义好的,在编译阶段生成,在编译阶段将通知织入Java字节码中,也称编译时增强。AspectJ使用的是静态代理。 缺点:代理对象需要与目标对象实现一样的接口,并且实现接口的方法,会有冗余代码。同时,一旦接口增加方法,目标对象与代理对象都要维护。 +**例子:**首先,我们创建一个Person接口。这个接口就是学生(被代理类),和班长(代理类)的公共接口,他们都有交作业的行为。这样,学生交作业就可以让班长来代理执行。 + +```java +/** + * Created by Mapei on 2018/11/7 + * 创建person接口 + */ +public interface Person { + //交作业 + void giveTask(); +} +``` + +Student类实现Person接口,Student可以具体实施交作业这个行为。 + +```java +/** + * Created by Mapei on 2018/11/7 + */ +public class Student implements Person { + private String name; + public Student(String name) { + this.name = name; + } + + public void giveTask() { + System.out.println(name + "交语文作业"); + } +} +``` + +StudentsProxy类,这个类也实现了Person接口,但是还另外持有一个学生类对象,那么他可以代理学生类对象执行交作业的行为。 + +```java +/** + * Created by Mapei on 2018/11/7 + * 学生代理类,也实现了Person接口,保存一个学生实体,这样就可以代理学生产生行为 + */ +public class StudentsProxy implements Person{ + //被代理的学生 + Student stu; + + public StudentsProxy(Person stu) { + // 只代理学生对象 + if(stu.getClass() == Student.class) { + this.stu = (Student)stu; + } + } + + //代理交作业,调用被代理学生的交作业的行为 + public void giveTask() { + stu.giveTask(); + } +} +``` + +下面测试一下,看代理模式如何使用: + +```java +/** + * Created by Mapei on 2018/11/7 + */ +public class StaticProxyTest { + public static void main(String[] args) { + //被代理的学生林浅,他的作业上交有代理对象monitor完成 + Person linqian = new Student("林浅"); + + //生成代理对象,并将林浅传给代理对象 + Person monitor = new StudentsProxy(linqian); + + //班长代理交作业 + monitor.giveTask(); + } +} +``` + **动态代理** 动态代理:代理类在程序运行时创建,AOP框架不会去修改字节码,而是在内存中临时生成一个代理对象,在运行期间对业务方法进行增强,不会生成新类。 @@ -86,7 +162,7 @@ AOP有两种实现方式:静态代理和动态代理。 ## JDK动态代理和CGLIB动态代理的区别? -Spring AOP中的动态代理主要有两种方式:JDK动态代理和CGLIB动态代理。 +Spring AOP中的动态代理主要有两种方式:JDK动态代理和CGLIB动态代理。在AOP的源码中会判断:如果目标类是接口类(目标对象实现了接口),则直接使用JDKproxy;其他情况使用CGlib动态代理。 **JDK动态代理** @@ -102,7 +178,7 @@ CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记 优点:目标类不需要实现特定的接口,更加灵活。 -什么时候采用哪种动态代理? +什么时候采用哪种动态代理?(代码底层判断) 1. 如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP 2. 如果目标对象实现了接口,可以强制使用CGLIB实现AOP @@ -111,7 +187,7 @@ CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记 **两者的区别**: 1. jdk动态代理使用jdk中的类Proxy来创建代理对象,它使用反射技术来实现,不需要导入其他依赖。cglib需要引入相关依赖:`asm.jar`,它使用字节码增强技术来实现。 -2. 当目标类实现了接口的时候Spring Aop默认使用jdk动态代理方式来增强方法,没有实现接口的时候使用cglib动态代理方式增强方法。 +2. 当目标类实现了接口的时候Spring AOP默认使用jdk动态代理方式来增强方法,没有实现接口的时候使用cglib动态代理方式增强方法。 ## Spring AOP相关术语 @@ -161,7 +237,21 @@ ioc的思想最核心的地方在于,资源不由使用资源者管理,而 ## 什么是依赖注入? -在Spring创建对象的过程中,把对象依赖的属性注入到对象中。依赖注入主要有两种方式:构造器注入和属性注入。 +在Spring创建对象的过程中,把对象依赖的属性注入到对象中。依赖注入主要有两种方式:构造器注入、Setter注入和注解注入。 + +@Autowired(自动注入)修饰符有三个属性:Constructor,byType,byName。默认按照byType注入。 + +constructor:通过构造方法进行自动注入,spring会匹配与构造方法参数类型一致的bean进行注入,如果有一个多参数的构造方法,一个只有一个参数的构造方法,在容器中查找到多个匹配多参数构造方法的bean,那么spring会优先将bean注入到多参数的构造方法中。 + +byName:被注入bean的id名必须与set方法后半截匹配,并且id名称的第一个单词首字母必须小写,这一点与手动set注入有点不同。 +byType:查找所有的set方法,将符合参数类型的bean注入。 + +主要有四种注解可以注册bean,每种注解可以任意使用,只是语义上有所差异: + +@Component:可以用于注册所有bean +@Repository:主要用于注册dao层的bean +@Controller:主要用于注册控制层的bean +@Service:主要用于注册服务层的bean ## IOC容器初始化过程? diff --git "a/\346\241\206\346\236\266/Spring\351\235\242\350\257\225\351\242\230.pdf" "b/\346\241\206\346\236\266/Spring\351\235\242\350\257\225\351\242\230.pdf" new file mode 100644 index 0000000..ce96450 Binary files /dev/null and "b/\346\241\206\346\236\266/Spring\351\235\242\350\257\225\351\242\230.pdf" differ diff --git "a/\350\256\241\347\256\227\346\234\272\345\237\272\347\241\200/\347\275\221\347\273\234/session\345\222\214cookie.md" "b/\350\256\241\347\256\227\346\234\272\345\237\272\347\241\200/\347\275\221\347\273\234/session\345\222\214cookie.md" index 6cc4584..cbbcd43 100644 --- "a/\350\256\241\347\256\227\346\234\272\345\237\272\347\241\200/\347\275\221\347\273\234/session\345\222\214cookie.md" +++ "b/\350\256\241\347\256\227\346\234\272\345\237\272\347\241\200/\347\275\221\347\273\234/session\345\222\214cookie.md" @@ -1,3 +1,5 @@ +# Session、Cookie、Token + 由于HTTP协议是无状态的协议,需要用某种机制来识具体的用户身份,用来跟踪用户的整个会话。常用的会话跟踪技术是cookie与session。 ## cookie @@ -17,7 +19,73 @@ session原理:首先浏览器请求服务器访问web站点时,服务器首 session的工作原理就是依靠cookie来做支撑,第一次使用request.getsession()时session被创建 ![](https://img-blog.csdn.net/20180924195247106?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1R5c29uMDMxNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) +## Token + +### token定义 + +​ token 也称作令牌,由uid+time+sign[+固定参数]组成,token 的认证方式类似于临时的证书签名, 并且是一种服务端无状态的认证方式, 非常适合于 REST API 的场景. 所谓无状态就是服务端并不会保存[身份认证](https://cloud.tencent.com/solution/tb-digitalid?from=10680)相关的数据。 + +### token组成 + +- uid: 用户唯一身份标识 +- time: 当前时间的时间戳 +- sign: 签名, 使用 hash/encrypt 压缩成定长的十六进制字符串,以防止第三方恶意拼接 +- 固定参数(可选): 将一些常用的固定参数加入到 token 中是为了避免重复查库 + +### 存放 + +oken在客户端一般存放于localStorage,cookie,或sessionStorage中。在服务器一般存于[数据库](https://cloud.tencent.com/solution/database?from=10680)中 + +### **token认证流程** + +token 的认证流程与cookie很相似 + +- 用户登录,成功后服务器返回Token给客户端。 +- 客户端收到数据后保存在客户端 +- 客户端再次访问服务器,将token放入headers中 +- 服务器端采用filter过滤器校验。校验成功则返回请求数据,校验失败则返回错误码 + ## 区别 -session是**服务器端**记录用户信息的一种机制,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中;cookie是**客户端**保存用户信息的一种机制,用来记录用户的一些信息,也是实现session的一种方式。 +### Cookie和Session的区别? + +- 作用范围不同,Cookie 保存在客户端(浏览器),Session 保存在服务器端。 +- 存取方式的不同,Cookie 只能保存 ASCII,Session 可以存任意数据类型,一般情况下我们可以在 Session 中保持一些常用变量信息,比如说 UserId 等。 +- 有效期不同,Cookie 可设置为长时间保持,比如我们经常使用的默认登录功能,Session 一般失效时间较短,客户端关闭或者 Session 超时都会失效。 +- 隐私策略不同,Cookie 存储在客户端,比较容易遭到不法获取,早期有人将用户的登录名和密码存储在 Cookie 中导致信息被窃取;Session 存储在服务端,安全性相对 Cookie 要好一些。 +- 存储大小不同, 单个 Cookie 保存的数据不能超过 4K,Session 可存储数据远高于 Cookie。 + +### **token可以抵抗csrf,cookie+session不行** + +因为form 发起的 POST 请求并不受到浏览器同源策略的限制,因此可以任意地使用其他域的 Cookie 向其他域发送 POST 请求,形成 CSRF 攻击。在post请求的瞬间,cookie会被浏览器自动添加到请求头中。但token不同,token是开发者为了防范csrf而特别设计的令牌,浏览器不会自动添加到headers里,攻击者也无法访问用户的token,所以提交的表单无法通过服务器过滤,也就无法形成攻击。 + +### **分布式情况下的session和token** + +我们已经知道session时有状态的,一般存于服务器内存或硬盘中,当服务器采用分布式或集群时,session就会面对[负载均衡](https://cloud.tencent.com/product/clb?from=10680)问题。 + +- 负载均衡多服务器的情况,不好确认当前用户是否登录,因为多服务器不共享session。这个问题也可以将session存在一个服务器中来解决,但是就不能完全达到负载均衡的效果。当今的几种解决session负载均衡的方法。 + +而token是无状态的,token字符串里就保存了所有的用户信息 + +- 客户端登陆传递信息给服务端,服务端收到后把用户信息加密(token)传给客户端,客户端将token存放于localStroage等容器中。客户端每次访问都传递token,服务端解密token,就知道这个用户是谁了。通过cpu加解密,服务端就不需要存储session占用存储空间,就很好的解决负载均衡多服务器的问题了。这个方法叫做JWT(Json Web Token) + +## **总结** + +- session存储于服务器,可以理解为一个状态列表,拥有一个唯一识别符号sessionId,通常存放于cookie中。服务器收到cookie后解析出sessionId,再去session列表中查找,才能找到相应session。依赖cookie +- cookie类似一个令牌,装有sessionId,存储在客户端,浏览器通常会自动添加。 +- token也类似一个令牌,无状态,用户信息都被加密到token中,服务器收到token后解密就可知道是哪个用户。需要开发者手动添加。 +- jwt只是一个跨域认证的方案 + +**补充:JWT** + +JWT就是token的一种实现方式,并且基本是java web领域的事实标准。 + +JWT全称是JSON Web Token。基本可以看出是使用JSON格式传输token + +JWT 由 3 部分构成: + +Header :描述 JWT 的元数据。定义了生成签名的算法以及 Token 的类型。Payload(负载):用来存放实际需要传递的数据Signature(签名):服务器通过Payload、Header和一个密钥(secret)使用 Header 里面指定的签名算法(默认是 HMAC SHA256)生成。流程: + +在基于 Token 进行身份验证的的应用程序中,用户登录时,服务器通过Payload、Header和一个密钥(secret)创建令牌(Token)并将 Token 发送给客户端, +然后客户端将 Token 保存在 Cookie 或者 localStorage 里面,以后客户端发出的所有请求都会携带这个令牌。你可以把它放在 Cookie 里面自动发送,但是这样不能跨域,所以更好的做法是放在 HTTP Header 的 Authorization字段中:Authorization: 你的Token。 diff --git "a/\350\256\241\347\256\227\346\234\272\345\237\272\347\241\200/\347\275\221\347\273\234/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234\351\253\230\351\242\221\351\235\242\350\257\225\351\242\230.md" "b/\350\256\241\347\256\227\346\234\272\345\237\272\347\241\200/\347\275\221\347\273\234/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234\351\253\230\351\242\221\351\235\242\350\257\225\351\242\230.md" index 3d82083..43210c6 100644 --- "a/\350\256\241\347\256\227\346\234\272\345\237\272\347\241\200/\347\275\221\347\273\234/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234\351\253\230\351\242\221\351\235\242\350\257\225\351\242\230.md" +++ "b/\350\256\241\347\256\227\346\234\272\345\237\272\347\241\200/\347\275\221\347\273\234/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234\351\253\230\351\242\221\351\235\242\350\257\225\351\242\230.md" @@ -249,6 +249,20 @@ HTTP2.0相比HTTP1.1支持的特性: - **隐私策略不同**,Cookie 存储在客户端,容易被窃取;Session 存储在服务端,安全性相对 Cookie 要好一些。 - **存储大小不同**, 单个 Cookie 保存的数据不能超过 4K;对于 Session 来说存储没有上限,但出于对服务器的性能考虑,Session 内不要存放过多的数据,并且需要设置 Session 删除机制。 +## 如何考虑分布式 Session 问题? + +在互联网公司为了可以支撑更大的流量,后端往往需要多台服务器共同来支撑前端用户请求,那如果用户在 A 服务器登录了,第二次请求跑到服务 B 就会出现登录失效问题。 + +分布式 Session 一般会有以下几种解决方案: + +* **客户端存储**:直接将信息存储在cookie中,cookie是存储在客户端上的一小段数据,客户端通过http协议和服务器进行cookie交互,通常用来存储一些不敏感信息 + +- **Nginx ip_hash 策略**:服务端使用 Nginx 代理,每个请求按访问 IP 的 hash 分配,这样来自同一 IP 固定访问一个后台服务器,避免了在服务器 A 创建 Session,第二次分发到服务器 B 的现象。 +- **Session 复制**:任何一个服务器上的 Session 发生改变(增删改),该节点会把这个 Session 的所有内容序列化,然后广播给所有其它节点。 +- **共享 Session**:服务端无状态话,将用户的 Session 等信息使用缓存中间件(如Redis)来统一管理,保障分发到每一个服务器的响应结果都一致。 + +建议采用共享 Session的方案。 + ## 什么是对称加密和非对称加密? **对称加密**:通信双方使用**相同的密钥**进行加密。特点是加密速度快,但是缺点是密钥泄露会导致密文数据被破解。常见的对称加密有`AES`和`DES`算法。