From bfb434457199a0fc7f9988da081f449a7b88f2ba Mon Sep 17 00:00:00 2001 From: whx123 <327658337@qq.com> Date: Sun, 16 May 2021 17:40:57 +0800 Subject: [PATCH 01/52] =?UTF-8?q?=E5=B7=A5=E4=BD=9C=E6=80=BB=E7=BB=93?= =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...04\345\210\222\350\257\246\350\247\243.md" | 440 +++++ ...45\210\222\350\257\246\350\247\243.md.bak" | 0 ...42\346\223\215\344\275\234\357\274\237.md" | 246 +++ ...04\345\260\217\345\273\272\350\256\256.md" | 1478 +++++++++++++++++ ...50\346\210\267\345\257\206\347\240\201.md" | 123 ++ ...46\210\267\345\257\206\347\240\201.md.bak" | 0 ...06\345\270\203\345\274\217\351\224\201.md" | 225 +++ ...52\346\263\250\346\204\217\347\202\271.md" | 386 +++++ 8 files changed, 2898 insertions(+) create mode 100644 "\345\210\267leetcode\345\277\205\345\244\207\347\256\227\346\263\225/\347\234\213\344\270\200\351\201\215\345\260\261\347\220\206\350\247\243\357\274\232\345\212\250\346\200\201\350\247\204\345\210\222\350\257\246\350\247\243.md" create mode 100644 "\345\210\267leetcode\345\277\205\345\244\207\347\256\227\346\263\225/\347\234\213\344\270\200\351\201\215\345\260\261\347\220\206\350\247\243\357\274\232\345\212\250\346\200\201\350\247\204\345\210\222\350\257\246\350\247\243.md.bak" create mode 100644 "\345\244\247\345\216\202\351\235\242\350\257\225\347\234\237\351\242\230/\351\230\277\351\207\214\344\270\200\351\235\242\357\274\214\347\273\231\344\272\206\345\207\240\346\235\241SQL\357\274\214\351\227\256\351\234\200\350\246\201\346\211\247\350\241\214\345\207\240\346\254\241\346\240\221\346\220\234\347\264\242\346\223\215\344\275\234\357\274\237.md" create mode 100644 "\345\267\245\344\275\234\346\200\273\347\273\223/\345\267\245\344\275\234\345\233\233\345\271\264\357\274\21450\344\270\252\350\256\251\344\275\240\344\273\243\347\240\201\346\233\264\345\245\275\347\232\204\345\260\217\345\273\272\350\256\256.md" create mode 100644 "\345\267\245\344\275\234\346\200\273\347\273\223/\347\250\213\345\272\217\345\221\230\345\277\205\345\244\207\345\237\272\347\241\200\357\274\232\345\246\202\344\275\225\345\256\211\345\205\250\344\274\240\350\276\223\345\255\230\345\202\250\347\224\250\346\210\267\345\257\206\347\240\201.md" create mode 100644 "\345\267\245\344\275\234\346\200\273\347\273\223/\347\250\213\345\272\217\345\221\230\345\277\205\345\244\207\345\237\272\347\241\200\357\274\232\345\246\202\344\275\225\345\256\211\345\205\250\344\274\240\350\276\223\345\255\230\345\202\250\347\224\250\346\210\267\345\257\206\347\240\201.md.bak" create mode 100644 "\347\274\223\345\255\230Redis\346\200\273\347\273\223/\344\270\203\347\247\215\346\226\271\346\241\210\345\257\271\346\257\224\345\210\206\345\270\203\345\274\217\351\224\201.md" create mode 100644 "\347\274\223\345\255\230Redis\346\200\273\347\273\223/\344\275\277\347\224\250Redis\347\232\20421\344\270\252\346\263\250\346\204\217\347\202\271.md" diff --git "a/\345\210\267leetcode\345\277\205\345\244\207\347\256\227\346\263\225/\347\234\213\344\270\200\351\201\215\345\260\261\347\220\206\350\247\243\357\274\232\345\212\250\346\200\201\350\247\204\345\210\222\350\257\246\350\247\243.md" "b/\345\210\267leetcode\345\277\205\345\244\207\347\256\227\346\263\225/\347\234\213\344\270\200\351\201\215\345\260\261\347\220\206\350\247\243\357\274\232\345\212\250\346\200\201\350\247\204\345\210\222\350\257\246\350\247\243.md" new file mode 100644 index 0000000..e8cc9b4 --- /dev/null +++ "b/\345\210\267leetcode\345\277\205\345\244\207\347\256\227\346\263\225/\347\234\213\344\270\200\351\201\215\345\260\261\347\220\206\350\247\243\357\274\232\345\212\250\346\200\201\350\247\204\345\210\222\350\257\246\350\247\243.md" @@ -0,0 +1,440 @@ + +### 前言 + +我们刷leetcode的时候,经常会遇到动态规划类型题目。动态规划问题非常非常经典,也很有技巧性,一般大厂都非常喜欢问。今天跟大家一起来学习动态规划的套路,文章如果有不正确的地方,欢迎大家指出哈,感谢感谢~ + +- 什么是动态规划? +- 动态规划的核心思想 +- 一个例子走进动态规划 +- 动态规划的解题套路 +- leetcode案例分析 + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/01fdad6c74864d7da07193203c2dcbf4~tplv-k3u1fbpfcp-zoom-1.image) + + +公众号:**捡田螺的小男孩** + +### 什么是动态规划? + + +动态规划(英语:Dynamic programming,简称 DP),是一种在数学、管理科学、计算机科学、经济学和生物信息学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划常常适用于有重叠子问题和最优子结构性质的问题。 + +> dynamic programming is a method for solving a complex problem by breaking it down into a collection of simpler subproblems. + +以上定义来自维基百科,看定义感觉还是有点抽象。简单来说,动态规划其实就是,给定一个问题,我们把它拆成一个个子问题,直到子问题可以直接解决。然后呢,把子问题答案保存起来,以减少重复计算。再根据子问题答案反推,得出原问题解的一种方法。 +> 一般这些子问题很相似,可以通过函数关系式递推出来。然后呢,动态规划就致力于解决每个子问题一次,减少重复计算,比如斐波那契数列就可以看做入门级的经典动态规划问题。 + + +### 动态规划核心思想 + +动态规划最核心的思想,就在于**拆分子问题,记住过往,减少重复计算**。 + +![动态规划在于记住过往](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d26f967ff6e447d291b0b196c4edaa07~tplv-k3u1fbpfcp-watermark.image) + +我们来看下,网上比较流行的一个例子: +> - A : "1+1+1+1+1+1+1+1 =?" +> - A : "上面等式的值是多少" +> - B : 计算 "8" +> - A : 在上面等式的左边写上 "1+" 呢? +> - A : "此时等式的值为多少" +> - B : 很快得出答案 "9" +> - A : "你怎么这么快就知道答案了" +> - A : "只要在8的基础上加1就行了" +> - A : "所以你不用重新计算,因为你记住了第一个等式的值为8!动态规划算法也可以说是 '记住求过的解来节省时间'" + +### 一个例子带你走进动态规划 -- 青蛙跳阶问题 + +#### 暴力递归 + +> leetcode原题:一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 10 级的台阶总共有多少种跳法。 + +有些小伙伴第一次见这个题的时候,可能会有点蒙圈,不知道怎么解决。其实可以试想: +> - 要想跳到第10级台阶,要么是先跳到第9级,然后再跳1级台阶上去;要么是先跳到第8级,然后一次迈2级台阶上去。 +> - 同理,要想跳到第9级台阶,要么是先跳到第8级,然后再跳1级台阶上去;要么是先跳到第7级,然后一次迈2级台阶上去。 +> - 要想跳到第8级台阶,要么是先跳到第7级,然后再跳1级台阶上去;要么是先跳到第6级,然后一次迈2级台阶上去。 + +假设跳到第n级台阶的跳数我们定义为f(n),很显然就可以得出以下公式: + +``` +f(10) = f(9)+f(8) +f (9) = f(8) + f(7) +f (8) = f(7) + f(6) +... +f(3) = f(2) + f(1) + +即通用公式为: f(n) = f(n-1) + f(n-2) +``` + +那f(2) 或者 f(1) 等于多少呢? +- 当只有2级台阶时,有两种跳法,第一种是直接跳两级,第二种是先跳一级,然后再跳一级。即f(2) = 2; +- 当只有1级台阶时,只有一种跳法,即f(1)= 1; + + +因此可以用递归去解决这个问题: +``` +class Solution { + public int numWays(int n) { + if(n == 1){ + return 1; + } + if(n == 2){ + return 2; + } + return numWays(n-1) + numWays(n-2); + } +} +``` + +去leetcode提交一下,发现有问题,超出时间限制了 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3e0608ec89a246568e01c7ba4b8f50d8~tplv-k3u1fbpfcp-zoom-1.image) + + +为什么超时了呢?递归耗时在哪里呢?先画出**递归树**看看: + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2dd95840552e4a7db9536884b7a9b558~tplv-k3u1fbpfcp-zoom-1.image) + +- 要计算原问题 f(10),就需要先计算出子问题 f(9) 和 f(8) +- 然后要计算 f(9),又要先算出子问题 f(8) 和 f(7),以此类推。 +- 一直到 f(2) 和 f(1),递归树才终止。 + +我们先来看看这个递归的时间复杂度吧: + + +``` +递归时间复杂度 = 解决一个子问题时间*子问题个数 +``` + +- 一个子问题时间 = f(n-1)+f(n-2),也就是一个加法的操作,所以复杂度是 O(1); +- 问题个数 = 递归树节点的总数,递归树的总节点 = 2^n-1,所以是复杂度O(2^n)。 + +因此,青蛙跳阶,递归解法的时间复杂度 = O(1) * O(2^n) = O(2^n),就是指数级别的,爆炸增长的,如果n比较大的话,超时很正常的了。 + +回过头来,你仔细观察这颗递归树,你会发现存在大量重复计算,比如f(8)被计算了两次,f(7)被重复计算了3次...所以这个递归算法低效的原因,就是**存在大量的重复计算**! + +既然存在大量重复计算,那么我们可以先把计算好的答案存下来,即造一个备忘录,等到下次需要的话,先去备忘录查一下,如果有,就直接取就好了,备忘录没有才开始计算,那就可以省去重新重复计算的耗时啦!这就是带备忘录的解法。 + + + +#### 带备忘录的递归解法(自顶向下) + +一般使用一个数组或者一个哈希map充当这个**备忘录**。 +- 第一步,f(10)= f(9) + f(8),f(9) 和f(8)都需要计算出来,然后再加到备忘录中,如下: + + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/94484290462e45c799609b0a581b14b0~tplv-k3u1fbpfcp-zoom-1.image) + +- 第二步, f(9) = f(8)+ f(7),f(8)= f(7)+ f(6), 因为 f(8) 已经在备忘录中啦,所以可以省掉,f(7),f(6)都需要计算出来,加到备忘录中~ + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/12900b17d77f4adfbdb71920f729d61a~tplv-k3u1fbpfcp-zoom-1.image) + + +第三步, f(8) = f(7)+ f(6),发现f(8),f(7),f(6)全部都在备忘录上了,所以都可以剪掉。 + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9a8c7ba6b5ae413799c6a33490bb1f8f~tplv-k3u1fbpfcp-zoom-1.image) + +所以呢,用了备忘录递归算法,递归树变成光秃秃的树干咯,如下: + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/18a78d6b99a84ff8a1df834f3c085014~tplv-k3u1fbpfcp-zoom-1.image) + +带**备忘录**的递归算法,子问题个数=树节点数=n,解决一个子问题还是O(1),所以带**备忘录**的递归算法的时间复杂度是O(n)。接下来呢,我们用带**备忘录**的递归算法去撸代码,解决这个青蛙跳阶问题的超时问题咯~,代码如下: + + + +``` +public class Solution { + //使用哈希map,充当备忘录的作用 + Map tempMap = new HashMap(); + public int numWays(int n) { + // n = 0 也算1种 + if (n == 0) { + return 1; + } + if (n <= 2) { + return n; + } + //先判断有没计算过,即看看备忘录有没有 + if (tempMap.containsKey(n)) { + //备忘录有,即计算过,直接返回 + return tempMap.get(n); + } else { + // 备忘录没有,即没有计算过,执行递归计算,并且把结果保存到备忘录map中,对1000000007取余(这个是leetcode题目规定的) + tempMap.put(n, (numWays(n - 1) + numWays(n - 2)) % 1000000007); + return tempMap.get(n); + } + } +} +``` +去leetcode提交一下,如图,稳了: + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e5f0fb1998c542dc8cb3826de800f443~tplv-k3u1fbpfcp-zoom-1.image) + +其实,还可以用动态规划解决这道题。 + +#### 自底向上的动态规划 + +动态规划跟带备忘录的递归解法基本思想是一致的,都是减少重复计算,时间复杂度也都是差不多。但是呢: +- 带备忘录的递归,是从f(10)往f(1)方向延伸求解的,所以也称为**自顶向下**的解法。 +- 动态规划从较小问题的解,由交叠性质,逐步决策出较大问题的解,它是从f(1)往f(10)方向,往上推求解,所以称为**自底向上**的解法。 + + +动态规划有几个典型特征,**最优子结构、状态转移方程、边界、重叠子问题**。在青蛙跳阶问题中: +- f(n-1)和f(n-2) 称为 f(n) 的最优子结构 +- f(n)= f(n-1)+f(n-2)就称为状态转移方程 +- f(1) = 1, f(2) = 2 就是边界啦 +- 比如f(10)= f(9)+f(8),f(9) = f(8) + f(7) ,f(8)就是重叠子问题。 + +我们来看下自底向上的解法,从f(1)往f(10)方向,想想是不是直接一个for循环就可以解决啦,如下: + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8e21b14d47e64afa958506d49972827b~tplv-k3u1fbpfcp-zoom-1.image) + +带备忘录的递归解法,空间复杂度是O(n),但是呢,仔细观察上图,可以发现,f(n)只依赖前面两个数,所以只需要两个变量a和b来存储,就可以满足需求了,因此空间复杂度是O(1)就可以啦 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8b202b2364eb4aae9122cfa8474c045e~tplv-k3u1fbpfcp-zoom-1.image) + +动态规划实现代码如下: + +``` +public class Solution { + public int numWays(int n) { + if (n<= 1) { + return 1; + } + if (n == 2) { + return 2; + } + int a = 1; + int b = 2; + int temp = 0; + for (int i = 3; i <= n; i++) { + temp = (a + b)% 1000000007; + a = b; + b = temp; + } + return temp; + } + } +``` + +### 动态规划的解题套路 + +#### 什么样的问题可以考虑使用动态规划解决呢? + +> 如果一个问题,可以把所有可能的答案穷举出来,并且穷举出来后,发现存在重叠子问题,就可以考虑使用动态规划。 + +比如一些求最值的场景,如**最长递增子序列、最小编辑距离、背包问题、凑零钱问题**等等,都是动态规划的经典应用场景。 + + +### 动态规划的解题思路 + + +动态规划的核心思想就是**拆分子问题,记住过往,减少重复计算。** 并且动态规划一般都是自底向上的,因此到这里,基于**青蛙跳阶**问题,我总结了一下我做动态规划的思路: + +- 穷举分析 +- 确定边界 +- 找出规律,确定最优子结构 +- 写出状态转移方程 + + +#### 1. 穷举分析 + + +- 当台阶数是1的时候,有一种跳法,f(1) =1 +- 当只有2级台阶时,有两种跳法,第一种是直接跳两级,第二种是先跳一级,然后再跳一级。即f(2) = 2; +- 当台阶是3级时,想跳到第3级台阶,要么是先跳到第2级,然后再跳1级台阶上去,要么是先跳到第 1级,然后一次迈 2 级台阶上去。所以f(3) = f(2) + f(1) =3 +- 当台阶是4级时,想跳到第3级台阶,要么是先跳到第3级,然后再跳1级台阶上去,要么是先跳到第 2级,然后一次迈 2 级台阶上去。所以f(4) = f(3) + f(2) =5 +- 当台阶是5级时...... + +![自底向上的动态规划](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/29cd6d0d31514336baf9905f8084a624~tplv-k3u1fbpfcp-zoom-1.image) + + + +#### 2. 确定边界 + +通过穷举分析,我们发现,当台阶数是1的时候或者2的时候,可以明确知道青蛙跳法。f(1) =1,f(2) = 2,当台阶n>=3时,已经呈现出规律f(3) = f(2) + f(1) =3,因此f(1) =1,f(2) = 2就是青蛙跳阶的边界。 + + +#### 3. 找规律,确定最优子结构 + +n>=3时,已经呈现出规律 f(n) = f(n-1) + f(n-2) ,因此,f(n-1)和f(n-2) 称为 f(n) 的最优子结构。什么是最优子结构?有这么一个解释: + +> 一道动态规划问题,其实就是一个递推问题。假设当前决策结果是f(n),则最优子结构就是要让 f(n-k) 最优,最优子结构性质就是能让转移到n的状态是最优的,并且与后面的决策没有关系,即让后面的决策安心地使用前面的局部最优解的一种性质 + + +#### 4, 写出状态转移方程 + +通过前面3步,穷举分析,确定边界,最优子结构,我们就可以得出状态转移方程啦: + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4fb4cd7257ff4fcbac9d87be96f353bd~tplv-k3u1fbpfcp-zoom-1.image) + +#### 5. 代码实现 + +我们实现代码的时候,一般注意从底往上遍历哈,然后关注下边界情况,空间复杂度,也就差不多啦。动态规划有个框架的,大家实现的时候,可以考虑适当参考一下: + + +``` +dp[0][0][...] = 边界值 +for(状态1 :所有状态1的值){ + for(状态2 :所有状态2的值){ + for(...){ + //状态转移方程 + dp[状态1][状态2][...] = 求最值 + } + } +} +``` + + +### leetcode案例分析 + +我们一起来分析一道经典leetcode题目吧 + +> 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。 + +示例 1: + +``` +输入:nums = [10,9,2,5,3,7,101,18] +输出:4 +解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。 +``` + +示例 2: + + +``` +输入:nums = [0,1,0,3,2,3] +输出:4 +``` + +我们按照以上动态规划的解题思路, + +- 穷举分析 +- 确定边界 +- 找规律,确定最优子结构 +- 状态转移方程 + + +#### 1.穷举分析 + + +因为动态规划,核心思想包括**拆分子问题,记住过往,减少重复计算。** 所以我们在思考原问题:**数组num[i]的最长递增子序列长度时**,可以思考下**相关子问题**,比如原问题是否跟**子问题**num[i-1]的最长递增子序列长度有关呢? + +##### 自顶向上的穷举 + +这里观察规律,显然是有关系的,我们还是遵循动态规划**自底向上**的原则,基于示例1的数据,从数组只有一个元素开始分析。 + +- 当nums只有一个元素10时,最长递增子序列是[10],长度是1. +- 当nums需要加入一个元素9时,最长递增子序列是[10]或者[9],长度是1。 +- 当nums再加入一个元素2时,最长递增子序列是[10]或者[9]或者[2],长度是1。 +- 当nums再加入一个元素5时,最长递增子序列是[2,5],长度是2。 +- 当nums再加入一个元素3时,最长递增子序列是[2,5]或者[2,3],长度是2。 +- 当nums再加入一个元素7时,,最长递增子序列是[2,5,7]或者[2,3,7],长度是3。 +- 当nums再加入一个元素101时,最长递增子序列是[2,5,7,101]或者[2,3,7,101],长度是4。 +- 当nums再加入一个元素18时,最长递增子序列是[2,5,7,101]或者[2,3,7,101]或者[2,5,7,18]或者[2,3,7,18],长度是4。 +- 当nums再加入一个元素7时,最长递增子序列是[2,5,7,101]或者[2,3,7,101]或者[2,5,7,18]或者[2,3,7,18],长度是4. + +##### 分析找规律,拆分子问题 +通过上面分析,我们可以**发现一个规律**: + +如果新加入一个元素nums[i], 最长递增子序列要么**是以nums[i]结尾的递增子序列**,要么就是**nums[i-1]的最长递增子序列**。看到这个,是不是很开心,nums[i]的最长递增子序列已经跟**子问题** nums[i-1]的最长递增子序列有关联了。 + +``` +原问题数组nums[i]的最长递增子序列 = 子问题数组nums[i-1]的最长递增子序列/nums[i]结尾的最长递增子序列 +``` + +是不是感觉成功了一半呢?但是**如何把nums[i]结尾的递增子序列也转化为对应的子问题**呢?要是nums[i]结尾的递增子序列也跟nums[i-1]的最长递增子序列有关就好了。又或者nums[i]结尾的最长递增子序列,跟前面子问题num[j](0= - nums[3]=5,以```5```结尾的最长子序列就是```[2,5]```,因为从数组下标```0到3```遍历,只找到了子序列```[2]```比```5```小,所以就是```[2]+[5]```啦,即```dp[4]=2``` +> - nums[4]=3,以```3```结尾的最长子序列就是```[2,3]```,因为从数组下标```0到4```遍历,只找到了子序列```[2]```比```3```小,所以就是```[2]+[3]```啦,即```dp[4]=2``` +> - nums[5]=7,以```7```结尾的最长子序列就是```[2,5,7]```和```[2,3,7]```,因为从数组下标```0到5```遍历,找到```2,5和3```都比7小,所以就有```[2,7],[5,7],[3,7],[2,5,7]和[2,3,7]```这些子序列,最长子序列就是```[2,5,7]和[2,3,7]```,它俩不就是以```5```结尾和```3```结尾的最长递增子序列+[7]来的嘛!所以,**```dp[5]=3 =dp[3]+1=dp[4]+1```**。 + + +很显然有这个规律:一个以nums[i]结尾的数组nums +- 如果存在j属于区间[0,i-1],并且num[i]>num[j]的话,则有,dp(i) =max(dp(j))+1, + +#### 最简单的边界情况 + +当nums数组只有一个元素时,最长递增子序列的长度dp(1)=1,当nums数组有两个元素时,dp(2) =2或者1, +因此边界就是dp(1)=1。 + +#### 确定最优子结构 + +从穷举分析,我们可以得出,以下的最优结构: + +``` +dp(i) =max(dp(j))+1,存在j属于区间[0,i-1],并且num[i]>num[j]。 +``` +**max(dp(j))** 就是最优子结构。 + +#### 状态转移方程 + +通过前面分析,我们就可以得出状态转移方程啦: + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/457ce281c1ec4e91b8c868aa593e41b6~tplv-k3u1fbpfcp-zoom-1.image) + +所以数组num[i]的最长递增子序列就是: +``` +最长递增子序列 =max(dp[i]) +``` + + + + +#### 代码实现 + +``` +class Solution { + public int lengthOfLIS(int[] nums) { + if (nums.length == 0) { + return 0; + } + int[] dp = new int[nums.length]; + //初始化就是边界情况 + dp[0] = 1; + int maxans = 1; + //自底向上遍历 + for (int i = 1; i < nums.length; i++) { + dp[i] = 1; + //从下标0到i遍历 + for (int j = 0; j < i; j++) { + //找到前面比nums[i]小的数nums[j],即有dp[i]= dp[j]+1 + if (nums[j] < nums[i]) { + //因为会有多个小于nums[i]的数,也就是会存在多种组合了嘛,我们就取最大放到dp[i] + dp[i] = Math.max(dp[i], dp[j] + 1); + } + } + //求出dp[i]后,dp最大那个就是nums的最长递增子序列啦 + maxans = Math.max(maxans, dp[i]); + } + return maxans; + } +} +``` + + + + + + + + + + + + + diff --git "a/\345\210\267leetcode\345\277\205\345\244\207\347\256\227\346\263\225/\347\234\213\344\270\200\351\201\215\345\260\261\347\220\206\350\247\243\357\274\232\345\212\250\346\200\201\350\247\204\345\210\222\350\257\246\350\247\243.md.bak" "b/\345\210\267leetcode\345\277\205\345\244\207\347\256\227\346\263\225/\347\234\213\344\270\200\351\201\215\345\260\261\347\220\206\350\247\243\357\274\232\345\212\250\346\200\201\350\247\204\345\210\222\350\257\246\350\247\243.md.bak" new file mode 100644 index 0000000..e69de29 diff --git "a/\345\244\247\345\216\202\351\235\242\350\257\225\347\234\237\351\242\230/\351\230\277\351\207\214\344\270\200\351\235\242\357\274\214\347\273\231\344\272\206\345\207\240\346\235\241SQL\357\274\214\351\227\256\351\234\200\350\246\201\346\211\247\350\241\214\345\207\240\346\254\241\346\240\221\346\220\234\347\264\242\346\223\215\344\275\234\357\274\237.md" "b/\345\244\247\345\216\202\351\235\242\350\257\225\347\234\237\351\242\230/\351\230\277\351\207\214\344\270\200\351\235\242\357\274\214\347\273\231\344\272\206\345\207\240\346\235\241SQL\357\274\214\351\227\256\351\234\200\350\246\201\346\211\247\350\241\214\345\207\240\346\254\241\346\240\221\346\220\234\347\264\242\346\223\215\344\275\234\357\274\237.md" new file mode 100644 index 0000000..a695048 --- /dev/null +++ "b/\345\244\247\345\216\202\351\235\242\350\257\225\347\234\237\351\242\230/\351\230\277\351\207\214\344\270\200\351\235\242\357\274\214\347\273\231\344\272\206\345\207\240\346\235\241SQL\357\274\214\351\227\256\351\234\200\350\246\201\346\211\247\350\241\214\345\207\240\346\254\241\346\240\221\346\220\234\347\264\242\346\223\215\344\275\234\357\274\237.md" @@ -0,0 +1,246 @@ +### 前言 + +有位朋友去阿里面试,他说面试官给了几条查询SQL,问:需要执行几次树搜索操作?我朋友当时是有点懵的,后来冷静思考,才发现就是考索引的几个基础知识点~~ 本文我们分九个索引知识点,一起来探讨一下。如果有不正确的话,欢迎指出哈,一起学习~ + +- 公众号:**捡田螺的小男孩** +- github地址,感谢每颗star +> https://github.com/whx123/JavaHome + +- 面试官考点之索引是什么? +- 面试官考点之索引类型 +- 面试官考点之为什么选择B+树作为索引结构 +- 面试官考点之一次索引搜索过程 +- 面试官考点之覆盖索引 +- 面试官考点之索引失效场景 +- 面试官考点之最左前缀 +- 面试官考点之索引下推 +- 面试官考点之大表添加索引 + +### 一、面试官考点之索引是什么? + +![](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/21eed26e34534b51aadf28d5defaed7e~tplv-k3u1fbpfcp-watermark.image) + +- 索引是一种能提高数据库查询效率的数据结构。它可以比作一本字典的目录,可以帮你快速找到对应的记录。 +- 索引一般存储在磁盘的文件中,它是占用物理空间的。 +- 正所谓水能载舟,也能覆舟。适当的索引能提高查询效率,过多的索引会影响数据库表的插入和更新功能。 + +### 二、索引有哪些类型类型 + +![](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cf6725e1a8cb44b496cca8fa45e15c2f~tplv-k3u1fbpfcp-watermark.image) + +#### 数据结构维度 + +- B+树索引:所有数据存储在叶子节点,复杂度为O(logn),适合范围查询。 +- 哈希索引: 适合等值查询,检索效率高,一次到位。 +- 全文索引:MyISAM和InnoDB中都支持使用全文索引,一般在文本类型char,text,varchar类型上创建。 +- R-Tree索引: 用来对GIS数据类型创建SPATIAL索引 + +#### 物理存储维度 + +- 聚集索引:聚集索引就是以主键创建的索引,在叶子节点存储的是表中的数据。 +- 非聚集索引:非聚集索引就是以非主键创建的索引,在叶子节点存储的是主键和索引列。 + +#### 逻辑维度 + +- 主键索引:一种特殊的唯一索引,不允许有空值。 +- 普通索引:MySQL中基本索引类型,允许空值和重复值。 +- 联合索引:多个字段创建的索引,使用时遵循最左前缀原则。 +- 唯一索引:索引列中的值必须是唯一的,但是允许为空值。 +- 空间索引:MySQL5.7之后支持空间索引,在空间索引这方面遵循OpenGIS几何数据模型规则。 + +### 三、面试官考点之为什么选择B+树作为索引结构 + +可以从几个维度去看这个问题,查询是否够快,效率是否稳定,存储数据多少,以及查找磁盘次数等等。为什么不是哈希结构?为什么不是二叉树,为什么不是平衡二叉树,为什么不是B树,而偏偏是B+树呢? + +我们写业务SQL查询时,大多数情况下,都是范围查询的,如一下SQL +``` +select * from employee where age between 18 and 28; +``` +#### 为什么不使用哈希结构? +我们知道哈希结构,类似k-v结构,也就是,key和value是一对一关系。它用于**等值查询**还可以,但是范围查询它是无能为力的哦。 + +#### 为什么不使用二叉树呢? + +先回忆下二叉树相关知识啦~ 所谓**二叉树,特点如下:** +- 每个结点最多两个子树,分别称为左子树和右子树。 +- 左子节点的值小于当前节点的值,当前节点值小于右子节点值 +- 顶端的节点称为跟节点,没有子节点的节点值称为叶子节点。 + +我们脑海中,很容易就浮现出这种二叉树结构图: +![](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8d4c349a7bda4b3db1791f9cff9c093e~tplv-k3u1fbpfcp-watermark.image) + +但是呢,有些特殊二叉树,它可能这样的哦: +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/97b71a48d43545a0bc20a55adf2be207~tplv-k3u1fbpfcp-watermark.image) + +如果二叉树特殊化为一个链表,相当于全表扫描。那么还要索引干嘛呀?因此,一般二叉树不适合作为索引结构。 + +#### 为什么不使用平衡二叉树呢? + +平衡二叉树特点:它也是一颗二叉查找树,任何节点的两个子树高度最大差为1。所以就不会出现特殊化一个链表的情况啦。 + +![](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/74afa9b54e7f4c0996ff83e66016c09a~tplv-k3u1fbpfcp-watermark.image) + +但是呢: +- 平衡二叉树插入或者更新是,需要左旋右旋维持平衡,维护代价大 +- 如果数量多的话,树的高度会很高。因为数据是存在磁盘的,以它作为索引结构,每次从磁盘读取一个节点,操作IO的次数就多啦。 + + +#### 为什么不使用B树呢? + + +数据量大的话,平衡二叉树的高度会很高,会增加IO嘛。那为什么不选择同样数据量,**高度更矮的B树**呢? + +![](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/acc8f2e2cfb54092b4fb131e500334a3~tplv-k3u1fbpfcp-watermark.image) + +B树相对于平衡二叉树,就可以存储更多的数据,高度更低。但是最后为甚选择B+树呢?因为B+树是B树的升级版: +- B+树非叶子节点上是不存储数据的,仅存储键值,而B树节点中不仅存储键值,也会存储数据。innodb中页的默认大小是16KB,如果不存储数据,那么就会存储更多的键值,相应的树的阶数(节点的子节点树)就会更大,树就会更矮更胖,如此一来我们查找数据进行磁盘的IO次数有会再次减少,数据查询的效率也会更快。 +- B+树索引的所有数据均存储在叶子节点,而且数据是按照顺序排列的,链表连着的。那么B+树使得范围查找,排序查找,分组查找以及去重查找变得异常简单。 + +### 四、面试官考点之一次B+树索引搜索过程 + +**面试官:** 假设有以下表结构,并且有这几条数据 +``` +CREATE TABLE `employee` ( + `id` int(11) NOT NULL, + `name` varchar(255) DEFAULT NULL, + `age` int(11) DEFAULT NULL, + `date` datetime DEFAULT NULL, + `sex` int(1) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `idx_age` (`age`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +insert into employee values(100,'小伦',43,'2021-01-20','0'); +insert into employee values(200,'俊杰',48,'2021-01-21','0'); +insert into employee values(300,'紫琪',36,'2020-01-21','1'); +insert into employee values(400,'立红',32,'2020-01-21','0'); +insert into employee values(500,'易迅',37,'2020-01-21','1'); +insert into employee values(600,'小军',49,'2021-01-21','0'); +insert into employee values(700,'小燕',28,'2021-01-21','1'); +``` + +**面试官:** 如果执行以下的查询SQL,需要执行几次的树搜索操作?可以画下对应的索引结构图~ +``` +select * from Temployee where age=32; +``` + +**解析:** 其实这个,面试官就是考察候选人是否熟悉B+树索引结构图。可以像酱紫回答~ + +- 先画出`idx_age`索引的索引结构图,大概如下: + +![](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f88457b43e354ca18795fa0033ad075f~tplv-k3u1fbpfcp-watermark.image) + +- 再画出id主键索引,我们先画出聚族索引结构图,如下: + +![](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/963a8dacb39345008c93b1d0ea079eec~tplv-k3u1fbpfcp-watermark.image) + + +因此,这条 SQL 查询语句执行大概流程就是酱紫: +- 1. 搜索`idx_age`索引树,将磁盘块1加载到内存,由于32<37,搜索左路分支,到磁盘寻址磁盘块2。 +- 2. 将磁盘块2加载到内存中,在内存继续遍历,找到age=32的记录,取得id = 400. +- 3. 拿到id=400后,回到id主键索引树。 +- 4. 搜索`id主键`索引树,将磁盘块1加载内存,在内存遍历,找到了400,但是B+树索引非叶子节点是不保存数据的。索引会继续搜索400的右分支,到磁盘寻址磁盘块3. +- 5. 将磁盘块3加载内存,在内存遍历,找到id=400的记录,拿到R4这一行的数据,好的,大功告成。 + +因此,这个SQL查询,执行了几次树的搜索操作,是不是一步了然了呀。**特别的**,在`idx_age`二级索引树找到主键`id`后,回到id主键索引搜索的过程,就称为回表。 +> 什么是回表?拿到主键再回到主键索引查询的过程,就叫做**回表** + +### 五、面试官考点之覆盖索引 + +**面试官:** 如果不用`select *`, 而是使用`select id,age`,以上的题目执行了几次树搜索操作呢? + +**解析:** 这个问题,主要考察候选人的覆盖索引知识点。回到`idx_age`索引树,你可以发现查询选项id和age都在叶子节点上了。因此,可以直接提供查询结果啦,根本就不需要再回表了~ + +![](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/629b6cfd08614adcbb20154707c0c8e0~tplv-k3u1fbpfcp-watermark.image) + +> 覆盖索引:在查询的数据列里面,不需要回表去查,直接从索引列就能取到想要的结果。换句话说,你SQL用到的索引列数据,覆盖了查询结果的列,就算上覆盖索引了。 + +所以,相对于上个问题,就是省去了回表的树搜索操作。 + +### 六、面试官考点之索引失效 + +**面试官:** 如果我现在给`name`字段加上普通索引,然后用个like模糊搜索,那会执行多少次查询呢?SQL如下: +``` +select * from employee where name like '%杰伦%'; +``` +**解析:** 这里考察的知识点就是,like是否会导致不走索引,看先该SQL的explain执行计划吧。其实like 模糊搜索,会导致不走索引的,如下: + +![](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3b01bb44ff5744729e55939cc88bd424~tplv-k3u1fbpfcp-watermark.image) + +因此,这条SQL最后就全表扫描啦~日常开发中,这几种骚操作都可能会导致索引失效,如下: +- 查询条件包含or,可能导致索引失效 +- 如何字段类型是字符串,where时一定用引号括起来,否则索引失效 +- like通配符可能导致索引失效。 +- 联合索引,查询时的条件列不是联合索引中的第一个列,索引失效。 +- 在索引列上使用mysql的内置函数,索引失效。 +- 对索引列运算(如,+、-、*、/),索引失效。 +- 索引字段上使用(!= 或者 < >,not in)时,可能会导致索引失效。 +- 索引字段上使用is null, is not null,可能导致索引失效。 +- 左连接查询或者右连接查询查询关联的字段编码格式不一样,可能导致索引失效。 +- mysql估计使用全表扫描要比使用索引快,则不使用索引。 + +### 七、面试官考点联合索引之最左前缀原则 + +**面试官:** 如果我现在给name,age字段加上联合索引索引,以下SQL执行多少次树搜索呢?先画下索引树? +``` +select * from employee where name like '小%' order by age desc; +``` +**解析:** 这里考察联合索引的最左前缀原则以及like是否中索引的知识点。组合索引树示意图大概如下: + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/29df075df94549b693a6a0ee06730666~tplv-k3u1fbpfcp-watermark.image) + +联合索引项是先按姓名name从小到大排序,如果名字name相同,则按年龄age从小到大排序。面试官要求查所有名字第一个字是“小”的人,SQL的like '小%'是可以用上```idx_name_age```联合索引的。 + +![](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/58b49f88f75f48be873deb395431c2fa~tplv-k3u1fbpfcp-watermark.image) + +该查询会沿着idx_name_age索引树,找到第一个字是小的索引值,因此依次找到```小军、小伦、小燕、```,分别拿到Id=```600、100、700```,然后回三次表,去找对应的记录。 这里面的最左前缀```小```,就是字符串索引的最左M个字符。实际上, +- 这个最左前缀可以是联合索引的最左N个字段。比如组合索引(a,b,c)可以相当于建了(a),(a,b),(a,b,c)三个索引,大大提高了索引复用能力。 +- 最左前缀也可以是字符串索引的最左M个字符。 + +### 八、面试官考点之索引下推 + +**面试官:** 我们还是居于组合索引 idx_name_age,以下这个SQL执行几次树搜索呢? + +``` +select * from employee where name like '小%' and age=28 and sex='0'; +``` + +**解析:** 这里考察索引下推的知识点,如果是**Mysql5.6之前**,在idx_name_age索引树,找出所有名字第一个字是“小”的人,拿到它们的主键id,然后回表找出数据行,再去对比年龄和性别等其他字段。如图: + +![](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c5729b1a84fd4ee9b872717903ca6f75~tplv-k3u1fbpfcp-watermark.image) + +有些朋友可能觉得奇怪,(name,age)不是联合索引嘛?为什么选出包含“小”字后,不再顺便看下年龄age再回表呢,不是更高效嘛?所以呀,MySQL 5.6 就引入了**索引下推优化**,可以在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数。 + + +因此,MySQL5.6版本之后,选出包含“小”字后,顺表过滤age=28,,所以就只需一次回表。 + +![](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/168aecb4709d4c30bc93c489ad76d712~tplv-k3u1fbpfcp-watermark.image) + +### 九、 面试官考点之大表添加索引 + +**面试官:** 如果一张表数据量级是千万级别以上的,那么,给这张表添加索引,你需要怎么做呢? + +**解析:** 我们需要知道一点,给表添加索引的时候,是会对表加锁的。如果不谨慎操作,有可能出现生产事故的。可以参考以下方法: + +- 1.先创建一张跟原表A数据结构相同的新表B。 +- 2.在新表B添加需要加上的新索引。 +- 3.把原表A数据导到新表B +- 4.rename新表B为原表的表名A,原表A换别的表名; + +### 总结与练习 + +本文主要讲解了索引的9大关键知识点,希望对大家有帮助。接下来呢,给大家出一道,有关于我最近业务开发遇到的加索引SQL,看下大家是怎么回答的,有兴趣可以联系我哈~题目如下: +``` + +select * from A where type ='1' and status ='s' order by create_time desc; +``` +假设type有9种类型,区分度性还算可以,status的区分度不高(有3种类型),那么你是如何加索引呢? +- 是给type加单索引 +- 还是(type,status,create_time)联合索引 +- 还是(type,create_time)联合索引呢? + +### 参看与感谢 +- [ MySQL有哪些索引类型 ?](https://segmentfault.com/q/1010000003832312) +- [大表加索引方案](https://zhuanlan.zhihu.com/p/151460679) +- [MySQL实战45讲](https://time.geekbang.org/column/article/69636) + diff --git "a/\345\267\245\344\275\234\346\200\273\347\273\223/\345\267\245\344\275\234\345\233\233\345\271\264\357\274\21450\344\270\252\350\256\251\344\275\240\344\273\243\347\240\201\346\233\264\345\245\275\347\232\204\345\260\217\345\273\272\350\256\256.md" "b/\345\267\245\344\275\234\346\200\273\347\273\223/\345\267\245\344\275\234\345\233\233\345\271\264\357\274\21450\344\270\252\350\256\251\344\275\240\344\273\243\347\240\201\346\233\264\345\245\275\347\232\204\345\260\217\345\273\272\350\256\256.md" new file mode 100644 index 0000000..e47a0ba --- /dev/null +++ "b/\345\267\245\344\275\234\346\200\273\347\273\223/\345\267\245\344\275\234\345\233\233\345\271\264\357\274\21450\344\270\252\350\256\251\344\275\240\344\273\243\347\240\201\346\233\264\345\245\275\347\232\204\345\260\217\345\273\272\350\256\256.md" @@ -0,0 +1,1478 @@ +### 前言 +工作了四年,看过很多思考不够深入的代码,因此写一下总结吧,50个让你代码更好的建议。其中的一些点,我以前的文章也写过啦,这次主要汇总一下。希望大家日常写代码多点思考,多点总结,加油!同时哪里有不对的,也望指出,感谢哈~ + +- 公众号:**捡田螺的小男孩** +- github地址:https://github.com/whx123/JavaHome + +### 1. 仅是判断是否存在时,select count 比 select 具体的列,更好。 + +我们经常遇到类似的业务场景,如,判断某个用户```userId```是否是会员。 + +**(反例):** 一些小伙伴会这样实现,先查从用户信息表查出用户记录,然后再去判断是否是会员: +``` + + +boolean isVip (String userId){ + UserInfo userInfo = userInfoDAp.selectUserByUserId(userId); + return UserInfo!=null && "Y".equals(userInfo.getVipFlag()) +} +``` + +**(正例):** 针对这种业务场景,其实更好的实现,是直接```select count```一下,如下: + +``` + + + boolean isVip (String userId){ + int vipNum = userInfoDAp.countVipUserByUserId(userId); + return vipNum>0 +} +``` + + +### 2. 复杂的if逻辑条件,可以调整顺序,让程序更高效 + + +假设业务需求是这样:如果用户是会员,并且第一次登陆时,需要发一条通知的短信。假如没有经过思考,代码很可能直接这样写了。 + +``` +if(isUserVip && isFirstLogin){ + sendMsgNotify(); +} +``` + +假设总共有5个请求进来,isUserVip通过的有3个请求,isFirstLogin通过的有1个请求。 那么以上代码,isUserVip执行的次数为5次,isFirstLogin执行的次数也是3次,如下: + +![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b30c2899d10f4258bf1fc94a9ebf324c~tplv-k3u1fbpfcp-watermark.image) + + +如果调整一下isUserVip和isFirstLogin的顺序呢? +``` +if(isFirstLogin && isUserVip ){ + sendMsg(); +} +``` +isFirstLogin执行的次数是5次,isUserVip执行的次数是1次,如下: + +![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/103a20c642e04ea899d74c4cb8187b28~tplv-k3u1fbpfcp-watermark.image) + +如果你的isFirstLogin,判断逻辑只是select count 一下数据库表,isUserVip也是select count 一下数据库表的话,显然,把isFirstLogin放在前面更高效。 + + +### 3. 写查询Sql的时候,只查你需要用到的字段,还有通用的字段,拒绝反手的select * + +**反例:** + +``` +select * from user_info where user_id =#{userId}; +``` + +**正例:** + + +``` + selct user_id , vip_flag from user_info where user_id =#{userId}; +``` + +**理由:** + +- 节省资源、减少网络开销。 +- 可能用到覆盖索引,减少回表,提高查询效率。 + +### 4. 优化你的程序,拒绝创建不必要的对象 + + +如果你的变量,后面的逻辑判断,一定会被赋值;或者说,只是一个字符串变量,直接初始化字符串常量就可以了,没有必要愣是要new String(). + + +反例: +``` +String s = new String ("欢迎关注公众号:捡田螺的小男孩"); +``` + +正例: + +``` +String s= "欢迎关注公众号:捡田螺的小男孩 ”; +``` + + +### 5. 初始化集合时,指定容量 + + +阿里的开发手册,也明确提到这个点: +![image.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2ac43ab291794c608537f1c4da6a9caa~tplv-k3u1fbpfcp-watermark.image) + + +假设你的map要存储的元素个数是15个左右,最优写法如下 +``` + //initialCapacity = 15/0.75+1=21 + Map map = new HashMap(21); + 又因为hashMap的容量跟2的幂有关,所以可以取32的容量 + Map map = new HashMap(32); +``` + +### 6.catch了异常,需要打印出具体的exception,方便更好定位问题 + +**反例:** +``` +try{ + // do something +}catch(Exception e){ + log.info("捡田螺的小男孩,你的程序有异常啦"); +} +``` + +**正例:** + +``` +try{ + // do something +}catch(Exception e){ + log.info("捡田螺的小男孩,你的程序有异常啦:",e); //把exception打印出来 +} +``` + +**理由:** +- 反例中,并没有把exception出来,到时候排查问题就不好查了啦,到底是SQl写错的异常还是IO异常,还是其他呢?所以应该把exception打印到日志中哦~ + +### 7. 打印日志的时候,对象没有覆盖Object的toString的方法,直接把类名打印出来了。 + + +我们在打印日志的时候,经常想看下一个请求参数对象request是什么。于是很容易有类似以下这些代码: + + +``` +publick Response dealWithRequest(Request request){ + log.info("请求参数是:".request.toString) +} +``` +打印结果如下: + +``` +请求参数是:local.Request@49476842 +``` + +这是因为对象的toString方法,默认的实现是“类名@散列码的无符号十六进制”。所以你看吧,这样子打印日志就没啥意思啦,你都不知道打印的是什么内容。 + +所以一般对象(尤其作为传参的对象),**都覆盖重写toString()方法**: + +``` +class Request { + + private String age; + + private String name; + + @Override + public String toString() { + return "Request{" + + "age='" + age + '\'' + + ", name='" + name + '\'' + + '}'; + } +} + +publick Response dealWithRequest(Request request){ + log.info("请求参数是:".request.toString) +} + + +``` +打印结果如下: + +``` +请求参数是:Request{age='26', name='公众号:捡田螺的小男孩'} +``` + +### 8. 一个方法,拒绝过长的参数列表。 + +假设有这么一个公有方法,形参有四个。。。 + +``` +public void getUserInfo(String name,String age,String sex,String mobile){ + // do something ... +} +``` + +如果现在需要多传一个version参数进来,并且你的公有方法是类似dubbo这种对外提供的接口的话,那么你的接口是不是需要兼容老版本啦? + +``` +public void getUserInfo(String name,String age,String sex,String mobile){ + // do something ... +} + +/** + * 新接口调这里 + */ +public void getNewUserInfo(String name,String age,String sex,String mobile,String version){ + // do something ... +} +``` + +所以呢,一般一个方法的参数,一般不宜过长。过长的参数列表,不仅看起来不优雅,并且接口升级时,可能还要考虑新老版本兼容。如果参数实在是多怎么办呢?可以用个DTO对象包装一下这些参数呢~如下: + +``` +public void getUserInfo(UserInfoParamDTO userInfoParamDTO){ + // do something ... +} + +class UserInfoParamDTO{ + private String name; + private String age; + private String sex; + private String mobile; +} +``` +用个DTO对象包装一下,即使后面有参数变动,也可以不用动对外接口了,好处杠杠的。 + +### 9. 使用缓冲流,减少IO操作 + +**反例:** + +``` +/** + * 公众号:捡田螺的小男孩 + * @desc: 复制一张图片文件 + */ +public class MainTest { + public static void main(String[] args) throws FileNotFoundException { + long begin = System.currentTimeMillis(); + try (FileInputStream input = new FileInputStream("C:/456.png"); + FileOutputStream output = new FileOutputStream("C:/789.png")) { + byte[] bytes = new byte[1024]; + int i; + while ((i = input.read(bytes)) != -1) { + output.write(bytes,0,i); + } + } catch (IOException e) { + log.error("复制文件发生异常",e); + } + log.info("常规流读写,总共耗时ms:"+(System.currentTimeMillis() - begin)); + } +} +``` + +运行结果: + +``` +常规流读写,总共耗时ms:52 +``` + + + +使用```FileInputStream```、```FileOutputStream```实现文件读写功能,是没有什么问题的。但是呢,可以使用缓冲流```BufferedReader```、```BufferedWriter```、```BufferedInputStream```、```BufferedOutputStream```等,减少IO次数,提高读写效率。 +> 如果是不带缓冲的流,读取到一个字节或者字符的,就会直接输出数据了。而带缓冲的流,读取到一个字节或者字符时,先不输出,而是等达到缓冲区的最大容量,才一次性输出。 + +**正例:** + + +``` +/** + * 公众号:捡田螺的小男孩 + * @desc: 复制一张图片文件 + */ +public class MainTest { + public static void main(String[] args) throws FileNotFoundException { + long begin = System.currentTimeMillis(); + try (BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("C:/456.png")); + BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("C:/789.png"))) { + byte[] bytes = new byte[1024]; + int i; + while ((i = input.read(bytes)) != -1) { + output.write(bytes,0,i); + } + } catch (IOException e) { + log.error("复制文件发生异常",e); + } + log.info("总共耗时ms"+(System.currentTimeMillis() - begin)); + } +} +``` +运行结果: + +``` +缓冲流读写,总共耗时ms:12 +``` + +### 10. 优化你的程序逻辑,比如前面已经查到的数据,在后面的方法也用到的话,是可以把往下传参的,减少方法调用/查表 + +**反例:** +``` +public Response dealRequest(Request request){ + + UserInfo userInfo = userInfoDao.selectUserByUserId(request.getUserId); + if(Objects.isNull(request)){ + return ; + } + + insertUserVip(request.getUserId); + +} + +private int insertUserVip(String userId){ + //又查了一次 + UserInfo userInfo = userInfoDao.selectUserByUserId(request.getUserId); + //插入用户vip流水 + insertUserVipFlow(userInfo); + .... +} + +``` + +很显然,以上程序代码,已经查到 userInfo,然后又把userId传下去,又查多了一次。。。实际上,可以把userInfo传下去的,这样可以省去一次查表操作,程序更高效。 + +**正例:** + +``` +public Response dealRequest(Request request){ + + UserInfo userInfo = userInfoDao.selectUserByUserId(request.getUserId); + if(Objects.isNull(request)){ + return ; + } + + insertUserVip(userInfo); +} + +private int insertUserVip(UserInfo userInfo){ + //插入用户vip流水 + insertUserVipFlow(userInfo); + .... +} +``` + + +### 11. 不要为了方便,直接在代码中使用0,1等魔法值,应该要用enum枚举代替。 + + +**反例:** + +``` +if("0".equals(userInfo.getVipFlag)){ + //非会员,提示去开通会员 + tipOpenVip(userInfo); +}else if("1".equals(userInfo.getVipFlag)){ + //会员,加勋章返回 + addMedal(userInfo); +} +``` + +**正例:** + + +``` +if(UserVipEnum.NOT_VIP.getCode.equals(userInfo.getVipFlag)){ + //非会员,提示去开通会员 + tipOpenVip(userInfo); +}else if(UserVipEnum.VIP.getCode.equals(userInfo.getVipFlag)){ + //会员,加勋章返回 + addMedal(userInfo); +} + +public enum UserVipEnum { + + VIP("1","会员"), + NOT_VIP("0","非会员"),:; + + private String code; + private String desc; + + UserVipEnum(String code, String desc) { + this.code = code; + this.desc = desc; + } +} +``` + +写代码的时候,不要一时兴起,就直接使用魔法值哈。使用魔法值,维护代码起来很难受的。 + +### 12. 当成员变量值不会改变时,优先定义为静态常量 + +**反例:** + + +``` +public class Task { + private final long timeout = 10L; + ... +} +``` + +**正例:** + +``` +public class Task { + private static final long TIMEOUT = 10L; + ... +} +``` + +> 因为如果定义为static,即类静态常量,在每个实例对象中,它只有一份副本。如果是成员变量,每个实例对象中,都各有一份副本。显然,如果这个变量不会变的话,定义为静态常量更好一些。 + +### 13. 注意检验空指针,不要轻易相信业务,说正常逻辑某个参数不可能为空。 + +NullPointerException 在我们日常开发中非常常见,我们代码开发过程中,一定要对空指针保持灵敏的嗅觉。 + +主要有这几类空指针问题: + +- 包装类型的空指针问题 +- 级联调用的空指针问题 +- Equals方法左边的空指针问题 +- ConcurrentHashMap 类似容器不支持 k-v为 null。 +- 集合,数组直接获取元素 +- 对象直接获取属性 + +**反例:** +``` +public class NullPointTest { + public static void main(String[] args) { + String s = null; + if (s.equals("666")) { //s可能为空,会导致空指针问题 + System.out.println("公众号:捡田螺的小男孩,干货满满"); + } + } +} + +``` + +### 14,捕获到的异常,不能忽略它,至少打点日志。 + +**反例:** + +``` +public static void testIgnoreException() throws Exception { + try { + // 搞事情 + } catch (Exception e) { + //捕获了异常,啥事情不做,日志也不打?? + } +} + +``` + +**正例:** + +``` +public static void testIgnoreException() { + try { + // 搞事情 + } catch (Exception e) { + log.error("异常了,联系开发小哥哥看看哈",e); + } +} +``` + +### 15. 采用Lambda表达式替换内部匿名类,使代码更优雅 + +JDK8出现了新特性-Lambda表达式。Lambda表达式不仅比匿名内部类更加优雅,并且在大多数虚拟机中,都是采用invokeDynamic指令实现,相对于匿名内部类,效率也更高 + + +**反例:** +``` + public void sortUserInfoList(List userInfoList){ + userInfoList.sort(new Comparator() { + @Override + public int compare(UserInfo user1, UserInfo user2) { + Long userId1 = user1.getUserId(); + Long userId2 = user2.getUserId(); + return userId1.compareTo(userId2); + }}); + } +``` + +**正例:** + +``` + public void sortUserInfoList(List userInfoList){ + userInfoList.sort((user1, user2) -> { + Long userId1 = user1.getUserId(); + Long userId2 = user2.getUserId(); + return userId1.compareTo(userId2); + }); + } +``` + +### 16. 通知类(如发邮件,有短信)的代码,建议异步处理。 + +假设业务流程这样:需要在用户登陆时,添加个短信通知它的粉丝。 很容易想到的实现流程如下: + + +![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ed6daf4932b34452b1aacdb98aa2dcc8~tplv-k3u1fbpfcp-watermark.image) + +假设提供sendMsgNotify服务的系统挂了,或者调用sendMsgNotify失败了,那么用户登陆就失败了。。。 +一个通知功能导致了登陆主流程不可用,明显的捡了芝麻丢西瓜。那么有没有鱼鱼熊掌兼得的方法呢?有的,给发短信接口捕获异常处理,或者另开线程异步处理,如下: + + +![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/58a956dc04c6456395b39d02afe3187e~tplv-k3u1fbpfcp-watermark.image) + +因此,添加通知类等不是非主要,可降级的接口时,应该静下心来考虑是否会影响主要流程,思考怎么处理最好。 + +### 17. 处理Java日期时,当心YYYY格式设置的问题。 + +日常开发中,我们经常需要处理日期。我们要当时日期格式化的时候,年份是大写```YYYY```的坑。 + + +``` +Calendar calendar = Calendar.getInstance(); +calendar.set(2019, Calendar.DECEMBER, 31); + +Date testDate = calendar.getTime(); + +SimpleDateFormat dtf = new SimpleDateFormat("YYYY-MM-dd"); +System.out.println("2019-12-31 转 YYYY-MM-dd 格式后 " + dtf.format(testDate)); +``` +运行结果: + +``` +2019-12-31 转 YYYY-MM-dd 格式后 2020-12-31 +``` + +> 为什么明明是2019年12月31号,就转了一下格式,就变成了2020年12月31号了?因为YYYY是基于周来计算年的,它指向当天所在周属于的年份,一周从周日开始算起,周六结束,只要本周跨年,那么这一周就算下一年的了。正确姿势是使用yyyy格式。 + + +![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d2e3654c06cd4727b203ea5710cc8410~tplv-k3u1fbpfcp-watermark.image) + +### 18. 如果一个类确定不会被继承,不会拿来搞AOP骚操作,可以指定final修饰符,如用final修饰一个工具类。 + +**正例:** +``` +public final class Tools { + public static void testFinal(){ + System.out.println("工具类方法"); + } +} +``` + +一个类指定了final修饰符,它不会被继承了,并且其所有方法都是final的了。Java编译器会找机会内联所有的final方法,提升了Java运行效率。 + + +### 19. static静态变量不要依赖spring实例化变量,可能会导致初始化出错 + +之前看到项目有类似的代码。静态变量依赖于spring容器的bean。 +``` + private static SmsService smsService = SpringContextUtils.getBean(SmsService.class); +``` + +这个静态的smsService有可能获取不到的,因为类加载顺序不是确定的,而以上的代码,静态的smsService初始化强制依赖spring容器的实例了。正确的写法可以这样,如下: + + +``` + private static SmsService smsService =null; + + //使用到的时候采取获取 + public static SmsService getSmsService(){ + if(smsService==null){ + smsService = SpringContextUtils.getBean(SmsService.class); + } + return smsService; + } + +``` + +### 20. 与类成员变量无关的方法,应当声明成静态方法 + + + +有些方法,与实例成员变量无关,就可以声明为静态方法。这一点,工具类用得很多。**反例如下**: + +``` +/** + * BigDecimal的工具类 + */ +public class BigDecimalUtils { + + public BigDecimal ifNullSetZERO(BigDecimal in) { + return in != null ? in : BigDecimal.ZERO; + } + + public BigDecimal sum(BigDecimal ...in){ + BigDecimal result = BigDecimal.ZERO; + for (int i = 0; i < in.length; i++){ + result = result.add(ifNullSetZERO(in[i])); + } + return result; + } +``` + +因为BigDecimalUtils工具类的方法都没有static修饰,所以,你要使用的时候,每次都要new一下啦,那不就耗资源去**反复创建对象**了嘛!! + +``` +BigDecimalUtils bigDecimalUtils = new BigDecimalUtils(); +bigDecimalUtils.sum(a,b); +``` +所以可以声明成静态变量,使用的时候,直接```类名.方法```调用即可,正例如下: + + +``` +/** + * BigDecimal的工具类 + */ +public class BigDecimalUtils { + + public static BigDecimal ifNullSetZERO(BigDecimal in) { + return in != null ? in : BigDecimal.ZERO; + } + + public static BigDecimal sum(BigDecimal ...in){ + BigDecimal result = BigDecimal.ZERO; + for (int i = 0; i < in.length; i++){ + result = result.add(ifNullSetZERO(in[i])); + } + return result; + } +``` + +### 21. 不要用一个Exception捕捉所有可能的异常。 + +**反例:** + +``` + +public void test(){ + try{ + //…抛出 IOException 的代码调用 + //…抛出 SQLException 的代码调用 + }catch(Exception e){ + //用基类 Exception 捕捉的所有可能的异常,如果多个层次都这样捕捉,会丢失原始异常的有效信息哦 + log.info(“Exception in test,exception:{}”, e); + } +} + +``` + +**正例:** + + +``` +public void test(){ + try{ + //…抛出 IOException 的代码调用 + //…抛出 SQLException 的代码调用 + }catch(IOException e){ + //仅仅捕捉 IOException + log.info(“IOException in test,exception:{}”, e); + }catch(SQLException e){ + //仅仅捕捉 SQLException + log.info(“SQLException in test,exception:{}”, e); + } +} +``` + +### 22. 函数不要过度封装,言简意赅即可。 + +**反例:** + +``` +// 函数封装 +public static boolean isUserVip(Boolean isVip) { + return Boolean.TRUE.equals(isVip); +} + +// 使用代码 +boolean isVip = isVip(user.getUserVip()); +``` + +**正例:** + + +``` +boolean isVip = Boolean.TRUE.equals(user.getUserVip()); +``` + +函数不要过度封装,把意思表达清楚即可。并且,方法调用会引起入栈和出栈,导致消耗更多的CPU和内存,过度封装,会损耗性能的! + + +### 23. 如果变量的初值一定会被覆盖,就没有必要给变量赋初值。 + +**反例:** + +``` +List userList = new ArrayList<>(); +if (isAll) { + userList = userInfoDAO.queryAll(); +} else { + userList = userInfoDAO.queryActive(); +} + +``` +**正例:** + + +``` +List userList ; +if (isAll) { + userList = userInfoDAO.queryAll(); +} else { + userList = userInfoDAO.queryActive(); +} + +``` + + +### 24.金额数值计算要使用BigDecimal + +看下这个浮点数计算的例子吧: +``` +public class DoubleTest { + public static void main(String[] args) { + System.out.println(0.1+0.2); + System.out.println(1.0-0.8); + System.out.println(4.015*100); + System.out.println(123.3/100); + + double amount1 = 3.15; + double amount2 = 2.10; + if (amount1 - amount2 == 1.05){ + System.out.println("OK"); + } + } +} +``` +运行结果: + +``` +0.30000000000000004 +0.19999999999999996 +401.49999999999994 +1.2329999999999999 +``` +> 因为计算机是以二进制存储数值的,对于浮点数也是。对于计算机而言,0.1无法精确表达,这就是为什么浮点数会导致精确度缺失的。因此,金额计算,一般都是用BigDecimal 类型 + + +``` +System.out.println(new BigDecimal(0.1).add(new BigDecimal(0.2))); +//output: +0.3000000000000000166533453693773481063544750213623046875 +``` +其实,使用 BigDecimal 表示和计算浮点数,必须使用字符串的构造方法来初始化 BigDecimal,并且,还要关注BigDecimal的几位小数点,它有八种舍入模式等 + +### 25. 注意Arrays.asList的几个坑 + +- **基本类型不能作为 Arrays.asList方法的参数,否则会被当做一个参数。** + +``` +public class ArrayAsListTest { + public static void main(String[] args) { + int[] array = {1, 2, 3}; + List list = Arrays.asList(array); + System.out.println(list.size()); + } +} +//运行结果 +1 +``` +- **Arrays.asList 返回的 List 不支持增删操作。** + + +``` +public class ArrayAsListTest { + public static void main(String[] args) { + String[] array = {"1", "2", "3"}; + List list = Arrays.asList(array); + list.add("5"); + System.out.println(list.size()); + } +} + +// 运行结果 +Exception in thread "main" java.lang.UnsupportedOperationException + at java.util.AbstractList.add(AbstractList.java:148) + at java.util.AbstractList.add(AbstractList.java:108) + at object.ArrayAsListTest.main(ArrayAsListTest.java:11) + +``` + Arrays.asList 返回的 List 并不是我们期望的 java.util.ArrayList,而是 Arrays 的内部类ArrayList。内部类的ArrayList没有实现add方法,而是父类的add方法的实现,是会抛出异常的呢。 + +- **使用Arrays.asLis的时候,对原始数组的修改会影响到我们获得的那个List** + +``` +public class ArrayAsListTest { + public static void main(String[] args) { + String[] arr = {"1", "2", "3"}; + List list = Arrays.asList(arr); + arr[1] = "4"; + System.out.println("原始数组"+Arrays.toString(arr)); + System.out.println("list数组" + list); + } +} + +//运行结果 +原始数组[1, 4, 3] +list数组[1, 4, 3] +``` + +### 26,及时关闭IO资源流 + +应该大家都有过这样的经历,windows系统桌面如果打开太多文件或者系统软件,就会觉得电脑很卡。当然,我们linux服务器也一样,平时操作文件,或者数据库连接,IO资源流如果没关闭,那么这个IO资源就会被它占着,这样别人就没有办法用了,这就造成资源浪费。 + + +所以使用完IO流,记得关闭哈。可以使用try-with-resource关闭的: +``` +/* + * 关注公众号,捡田螺的小男孩 + */ +try (FileInputStream inputStream = new FileInputStream(new File("jay.txt")) { + // use resources +} catch (FileNotFoundException e) { + log.error(e); +} catch (IOException e) { + log.error(e); +} +``` + +### 27. 尽量使用函数内的基本类型临时变量 + +> - 在方法函数内,基本类型参数以及临时变量,都是保存在栈中的,访问速度比较快。 +> - 对象类型的参数和临时变量的引用都保存在栈中,内容都保存在堆中,访问速度较慢。 +> - 在类中,任何类型的成员变量都保存在堆(Heap)中,访问速度较慢。 + +``` +public class AccumulatorUtil { + + private double result = 0.0D; + //反例 + public void addAllOne( double[] values) { + for(double value : values) { + result += value; + } + } + //正例,先在方法内声明一个局部临时变量,累加完后,再赋值给方法外的成员变量 + public void addAll1Two(double[] values) { + double sum = 0.0D; + for(double value : values) { + sum += value; + } + result += sum; + } +} + +``` + +### 28. 如果数据库一次查询的数量过多,建议分页处理。 + +如果你的Sql一次性查出来的数据量比较多,建议分页处理。 + + +**反例:** +``` + +select user_id,name,age from user_info ; + +``` + +**正例:** + +``` +select user_id,name,age from user_info limit #{offset},#{pageSize}; +``` + +如果偏移量特别大的时候,查询效率就变得低下。可以这接种方式优化: + +``` +//方案一 :返回上次查询的最大记录(偏移量) +select id,name from user_info where id>10000 limit #{pageSize}. + +//方案二:order by + 索引 +select id,name from user_info order by id limit #{offset},#{pageSize} + +//方案三:在业务允许的情况下限制页数: + +``` + +### 29. 尽量减少对变量的重复计算 + +一般我们写代码的时候,会以以下的方式实现遍历: +``` +for (int i = 0; i < list.size; i++){ + +} +``` +如果list数据量比较小那还好。如果list比较大时,可以优化成这样: +``` +for (int i = 0, int length = list.size; i < length; i++){ + +} +``` + +理由: +- 对方法的调用,即使是只有一个语句,也是有有消耗的,比如创建栈帧。如果list比较大时,多次调用list.size也是会有资源消耗的。 + + +### 30. 修改对外老接口的时候,思考接口的兼容性。 + +很多bug都是因为修改了对外老接口,但是却不做兼容导致的。关键这个问题多数是比较严重的,可能直接导致系统发版失败的。新手程序员很容易就犯这个错误了哦~ + +所以,如果你的需求是在原来接口上修改,,尤其这个接口是对外提供服务的话,一定要考虑接口兼容。举个例子吧,比如dubbo接口,原本是只接收A,B参数,现在你加了一个参数C,就可以考虑这样处理。 + +``` +//老接口 +void oldService(A,B);{ + //兼容新接口,传个null代替C + newService(A,B,null); +} + +//新接口,暂时不能删掉老接口,需要做兼容。 +void newService(A,B,C); +``` + + +### 31 代码采取措施避免运行时错误(如数组边界溢出,被零除等) + +日常开发中,我们需要采取措施规避数组边界溢出,被零整除,空指针等运行时错误。 + + +类似代码比较常见: + +``` +String name = list.get(1).getName(); //list可能越界,因为不一定有2个元素哈 +``` + +所以,应该采取措施,预防一下数组边界溢出,**正例:** + +``` +if(CollectionsUtil.isNotEmpty(list)&& list.size()>1){ + String name = list.get(1).getName(); +} +``` + + +### 32. 注意 ArrayList.toArray() 强转的坑 + +``` +public class ArrayListTest { + public static void main(String[] args) { + List list = new ArrayList(1); + list.add("公众号:捡田螺的小男孩"); + String[] array21 = (String[])list.toArray();//类型转换异常 + } +} + +``` + +因为返回的是Object类型,Object类型数组强转String数组,会发生ClassCastException。解决方案是,使用toArray()重载方法toArray(T[] a) + +``` +String[] array1 = list.toArray(new String[0]);//可以正常运行 +``` + + +### 33. 尽量不在循环里远程调用、或者数据库操作,优先考虑批量进行。 + +程操作或者数据库操作都是比较耗网络、IO资源的,所以尽量不在循环里远程调用、不在循环里操作数据库,能批量一次性查回来尽量不要循环多次去查。(但是呢,也不要一次性查太多数据哈,要分批500一次酱紫) + + +**正例:** +``` +remoteBatchQuery(param); +``` + +**反例:** + +``` +for(int i=0;i userInfoList) { + for (int i = 0; i < userInfoList.size(); i++) { + //重复调用userList.size()方法了 + } + } +``` + +**正例:** + + +``` + public static void listDetail(List userInfoList) { + int length = userInfoList.size(); + for (int i = 0; i < length; i++) { + //减少调用userList.size()方法,只在length变量调了一次。 + } + } +``` + +### 37,直接大文件或者一次性从数据库读取太多数据到内存,可能导致OOM问题 + +如果一次性把大文件或者数据库太多数据达到内存,是会导致OOM的。所以,为什么查询DB数据库,一般都建议分批。 + +读取文件的话,一般文件不会太大,才使用Files.readAllLines()。为什么呢?因为它是直接把文件都读到内存的,预估下不会OOM才使用这个吧,可以看下它的源码: + + +``` +public static List readAllLines(Path path, Charset cs) throws IOException { + try (BufferedReader reader = newBufferedReader(path, cs)) { + List result = new ArrayList<>(); + for (;;) { + String line = reader.readLine(); + if (line == null) + break; + result.add(line); + } + return result; + } +} +``` +如果是太大的文件,可以使用Files.line()按需读取,当时读取文件这些,一般是使用完需要关闭资源流的哈。 + +### 38. 调用第三方接口,需要考虑异常处理,安全性,超时重试这几个点。 + +日常开发中,经常需要调用第三方服务,或者分布式远程服务的的话,需要考虑: + + +- 异常处理(比如,你调别人的接口,如果异常了,怎么处理,是重试还是当做失败) +- 超时(没法预估对方接口一般多久返回,一般设置个超时断开时间,以保护你的接口) +- 重试次数(你的接口调失败,需不需要重试,需要站在业务上角度思考这个问题) + +> 简单一个例子,你一个http请求调别人的服务,需要考虑设置connect-time,和retry次数。 + + +### 39 不要使用循环拷贝集合,尽量使用JDK提供的方法拷贝集合 + +> - JDK提供原生API方法,可以直接指定集合的容量,避免多次扩容损耗性能。 +> - 这些方法的底层调用System.arraycopy方法实现,进行数据的批量拷贝效率更高。 + +**反例:** + +``` +public List copyMergeList(List user1List, List user2List) { + List userList = new ArrayList<>(user1List.size() + user2List.size()); + for (UserInfo user : user1List) { + userList.add(user); + } + for (UserInfo user : user2List) { + userList.add(user); + } + + return user1List; + } +``` + +**正例:** + +``` +public List copyMergeList(List user1List, List user2List) { + List userList = new ArrayList<>(user1List.size() + user2List.size()); + userList.addAll(user1List); + userList.addAll(user2List); + return user1List; + } +``` + +### 40. 对于复杂的代码逻辑,添加清楚的注释 + +写代码的时候,是没有必要写太多的注释的,好的方法变量命名就是最好的注释。但是,如果是业务逻辑很复杂的代码,真的非常有必要写清楚注释。清楚的注释,更有利于后面的维护。 + + +### 41. 多线程情况下,考虑线性安全问题 + +在高并发情况下,HashMap可能会出现死循环。因为它是非线性安全的,可以考虑使用ConcurrentHashMap。 所以这个也尽量养成习惯,不要上来反手就是一个new HashMap(); + +- Hashmap、Arraylist、LinkedList、TreeMap等都是线性不安全的; +- Vector、Hashtable、ConcurrentHashMap等都是线性安全的 + +### 42. 使用spring事务功能时,注意这几个事务未生效的坑 + +日常业务开发中,我们经常跟事务打交道,事务失效主要有以下几个场景: + +- 底层数据库引擎不支持事务 +- 在非public修饰的方法使用 +- rollbackFor属性设置错误 +- 本类方法直接调用 +- 异常被try...catch吃了,导致事务失效。 + +**反例:** + + +``` +public class TransactionTest{ + public void A(){ + //插入一条数据 + //调用方法B (本地的类调用,事务失效了) + B(); + } + + @Transactional + public void B(){ + //插入数据 + } +} +``` + +**注解的事务方法给本类方法直接调用,事务失效** + + +### 43. 使用Executors声明线程池,newFixedThreadPool的OOM问题 + + +``` + ExecutorService executor = Executors.newFixedThreadPool(10); + for (int i = 0; i < Integer.MAX_VALUE; i++) { + executor.execute(() -> { + try { + Thread.sleep(10000); + } catch (InterruptedException e) { + //do nothing + } + }); + } + +``` +IDE指定JVM参数:-Xmx8m -Xms8m : + +![image.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b7154077d1074b3c8e1f5670e754adfd~tplv-k3u1fbpfcp-watermark.image) + +运行结果: + +![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/fa3de03ca1924787aa1775b0a94890b4~tplv-k3u1fbpfcp-watermark.image) + +我们看下源码,其实newFixedThreadPool使用的是无界队列! + + +``` +public static ExecutorService newFixedThreadPool(int nThreads) { + return new ThreadPoolExecutor(nThreads, nThreads, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue()); +} + +public class LinkedBlockingQueue extends AbstractQueue + implements BlockingQueue, java.io.Serializable { + ... + /** + * Creates a {@code LinkedBlockingQueue} with a capacity of + * {@link Integer#MAX_VALUE}. + */ + public LinkedBlockingQueue() { + this(Integer.MAX_VALUE); + } +... +} + +``` + +> newFixedThreadPool线程池的核心线程数是固定的,它使用了近乎于无界的LinkedBlockingQueue阻塞队列。当核心线程用完后,任务会入队到阻塞队列,如果任务执行的时间比较长,没有释放,会导致越来越多的任务堆积到阻塞队列,最后导致机器的内存使用不停的飙升,造成JVM OOM。 + + +### 44. catch住异常后,尽量不要使用e.printStackTrace(),而是使用log打印。 + +**反例:** + +``` +try{ + // do what you want +}catch(Exception e){ + e.printStackTrace(); +} +``` + +**正例:** + +``` +try{ + // do what you want +}catch(Exception e){ + log.info("你的程序有异常啦",e); +} +``` + +### 45. 接口需要考虑幂等性 + +接口是需要考虑幂等性的,尤其抢红包、转账这些重要接口。最直观的业务场景,就是用户连着点两次,你的接口有没有hold住。 + +一般幂等技术方案有这几种: + +- 查询操作 +- 唯一索引 +- token机制,防止重复提交 +- 数据库的delete/update操作 +- 乐观锁 +- 悲观锁 +- Redis、zookeeper 分布式锁(以前抢红包需求,用了Redis分布式锁) +- 状态机幂等 + + +### 46. 对于行数比较多的函数,建议划分小函数,增强可读性。 + +**反例:** +``` +public class Test { + private String name; + private Vector orders = new Vector(); + + public void printOwing() { + //print banner + System.out.println("****************"); + System.out.println("*****customer Owes *****"); + System.out.println("****************"); + + //calculate totalAmount + Enumeration env = orders.elements(); + double totalAmount = 0.0; + while (env.hasMoreElements()) { + Order order = (Order) env.nextElement(); + totalAmount += order.getAmout(); + } + + //print details + System.out.println("name:" + name); + System.out.println("amount:" + totalAmount); + } +} + +``` + +**正例:** + + +``` +public class Test { + private String name; + private Vector orders = new Vector(); + + public void printOwing() { + + //print banner + printBanner(); + //calculate totalAmount + double totalAmount = getTotalAmount(); + //print details + printDetail(totalAmount); + } + + void printBanner(){ + System.out.println("****************"); + System.out.println("*****customer Owes *****"); + System.out.println("****************"); + } + + double getTotalAmount(){ + Enumeration env = orders.elements(); + double totalAmount = 0.0; + while (env.hasMoreElements()) { + Order order = (Order) env.nextElement(); + totalAmount += order.getAmout(); + } + return totalAmount; + } + + void printDetail(double totalAmount){ + System.out.println("name:" + name); + System.out.println("amount:" + totalAmount); + } + +} + +``` + +一个过于冗长的函数或者一段需要注释才能让人理解用途的代码,可以考虑把它切分成一个功能明确的函数单元,并定义清晰简短的函数名,这样会让代码变得更加优雅。 + + +### 47. 你的关键业务代码,一般建议搞点日志保驾护航。 + +关键业务代码无论身处何地,都应该有足够的日志保驾护航。 + +> 比如:你实现转账业务,转个几百万,然后转失败了,接着客户投诉,然后你还没有打印到日志,想想那种水深火热的困境下,你却毫无办法。。。 + +那么,你的转账业务都需要那些日志信息呢?至少,方法调用前,入参需要打印需要吧,接口调用后,需要捕获一下异常吧,同时打印异常相关日志吧,如下: + +``` +public void transfer(TransferDTO transferDTO){ + log.info("invoke tranfer begin"); + //打印入参 + log.info("invoke tranfer,paramters:{}",transferDTO); + try { + res= transferService.transfer(transferDTO); + }catch(Exception e){ + log.error("transfer fail,cifno:{},account:{}",transferDTO.getCifno(), + transferDTO.getaccount()) + log.error("transfer fail,exception:{}",e); + } + log.info("invoke tranfer end"); + } +``` + +除了打印足够的日志,我们还需要注意一点是,日志级别别混淆使用,别本该打印info的日志,你却打印成error级别,告警半夜三更催你起来排查问题就不好了。 + +### 48. 某些可变因素,如红包皮肤等等,做成配置化是否会更好呢。 + +假如产品提了个红包需求,圣诞节的时候,红包皮肤为圣诞节相关的,春节的时候,红包皮肤等。 + +反例: + +``` +if(duringChristmas){ + img = redPacketChristmasSkin; +}else if(duringSpringFestival){ + img = redSpringFestivalSkin; +} +``` + +如果到了元宵节的时候,运营小姐姐突然又有想法,红包皮肤换成灯笼相关的,这时候,是不是要去修改代码了,重新发布了?从一开始,实现一张红包皮肤的配置表,将红包皮肤做成配置化呢?更换红包皮肤,只需修改一下表数据就好了。 + +### 49,.直接迭代需要使用的集合,无须在额外操作 + +直接迭代需要使用的集合,无需通过其它操作获取数据,比较典型就是Map的迭代遍历: + + +**反例:** +``` +Map userMap = ...; +for (Long userId : userMap.keySet()) { + UserDO user = userMap.get(userId); + ... +} +``` + +**正例:** + + +``` +Map userMap = ...; +for (Map.Entry userEntry : userMap.entrySet()) { + Long userId = userEntry.getKey(); + UserDO user = userEntry.getValue(); + ... +} +``` + +### 50. 策略模式+工厂方法优化冗余的if else + + +反例: + +``` + String medalType = "guest"; + if ("guest".equals(medalType)) { + System.out.println("嘉宾勋章"); + } else if ("vip".equals(medalType)) { + System.out.println("会员勋章"); + } else if ("guard".equals(medalType)) { + System.out.println("展示守护勋章"); + } + ... + +``` + +首先,我们把每个条件逻辑代码块,抽象成一个公共的接口,我们根据每个逻辑条件,定义相对应的策略实现类,可得以下代码: + + +``` +//勋章接口 +public interface IMedalService { + void showMedal(); +} + +//守护勋章策略实现类 +public class GuardMedalServiceImpl implements IMedalService { + @Override + public void showMedal() { + System.out.println("展示守护勋章"); + } +} +//嘉宾勋章策略实现类 +public class GuestMedalServiceImpl implements IMedalService { + @Override + public void showMedal() { + System.out.println("嘉宾勋章"); + } +} +//VIP勋章策略实现类 +public class VipMedalServiceImpl implements IMedalService { + @Override + public void showMedal() { + System.out.println("会员勋章"); + } +} + +``` + +接下来,我们再定义策略工厂类,用来管理这些勋章实现策略类,如下: + + +``` +//勋章服务工产类 +public class MedalServicesFactory { + + private static final Map map = new HashMap<>(); + static { + map.put("guard", new GuardMedalServiceImpl()); + map.put("vip", new VipMedalServiceImpl()); + map.put("guest", new GuestMedalServiceImpl()); + } + public static IMedalService getMedalService(String medalType) { + return map.get(medalType); + } +} + +``` + +优化后,正例如下: + +``` +ublic class Test { + public static void main(String[] args) { + String medalType = "guest"; + IMedalService medalService = MedalServicesFactory.getMedalService(medalType); + medalService.showMedal(); + } +} +``` + diff --git "a/\345\267\245\344\275\234\346\200\273\347\273\223/\347\250\213\345\272\217\345\221\230\345\277\205\345\244\207\345\237\272\347\241\200\357\274\232\345\246\202\344\275\225\345\256\211\345\205\250\344\274\240\350\276\223\345\255\230\345\202\250\347\224\250\346\210\267\345\257\206\347\240\201.md" "b/\345\267\245\344\275\234\346\200\273\347\273\223/\347\250\213\345\272\217\345\221\230\345\277\205\345\244\207\345\237\272\347\241\200\357\274\232\345\246\202\344\275\225\345\256\211\345\205\250\344\274\240\350\276\223\345\255\230\345\202\250\347\224\250\346\210\267\345\257\206\347\240\201.md" new file mode 100644 index 0000000..978ae68 --- /dev/null +++ "b/\345\267\245\344\275\234\346\200\273\347\273\223/\347\250\213\345\272\217\345\221\230\345\277\205\345\244\207\345\237\272\347\241\200\357\274\232\345\246\202\344\275\225\345\256\211\345\205\250\344\274\240\350\276\223\345\255\230\345\202\250\347\224\250\346\210\267\345\257\206\347\240\201.md" @@ -0,0 +1,123 @@ +

鍓嶈█

+

鎴戜滑寮鍙戠綉绔欐垨鑰匒PP鐨勬椂鍊欙紝棣栧厛瑕佽В鍐崇殑闂锛屽氨鏄濡備綍瀹夊叏浼犺緭鍜屽瓨鍌ㄧ敤鎴风殑瀵嗙爜銆備竴浜涘ぇ鍏徃鐨勭敤鎴锋暟鎹簱娉勯湶浜嬩欢涔熸椂鏈夊彂鐢燂紝甯︽潵闈炲父澶х殑璐熼潰褰卞搷銆傚洜姝わ紝濡備綍瀹夊叏浼犺緭瀛樺偍鐢ㄦ埛瀵嗙爜锛屾槸姣忎綅绋嬪簭鍛樺繀澶囩殑鍩虹銆傛湰鏂囧皢璺熷ぇ瀹朵竴璧峰涔狅紝濡備綍瀹夊叏浼犺緭瀛樺偍鐢ㄦ埛鐨勫瘑鐮併

+
+

鍏紬鍙凤細鎹$敯铻虹殑灏忕敺瀛锛堜竴璧疯璁哄瘑鐮佷紶杈撳瓨鍌ㄩ棶棰橈級

+

1. 濡備綍瀹夊叏鍦颁紶杈撶敤鎴风殑瀵嗙爜

+

瑕佹嫆缁濈敤鎴峰瘑鐮佸湪缃戠粶涓婅8濂旓紝鎴戜滑寰堝鏄撳氨鎯冲埌浣跨敤https鍗忚锛岄偅鍏堟潵鍥為【涓媓ttps鐩稿叧鐭ヨ瘑鍚

+

1.1 https 鍗忚

+
+
    +
  • http鐨勪笁澶ч闄
+

涓轰粈涔堣浣跨敤https鍗忚鍛紵http瀹冧笉棣鍚? 鍥犱负http鏄槑鏂囦俊鎭紶杈撶殑銆傚鏋滃湪鑼尗鐨勭綉缁滄捣娲嬶紝浣跨敤http鍗忚锛屾湁浠ヤ笅涓夊ぇ椋庨櫓锛

+
+
    +
  • 绐冨惉/鍡呮帰椋庨櫓锛氱涓夋柟鍙互鎴幏閫氫俊鏁版嵁銆
  • 鏁版嵁绡℃敼椋庨櫓锛氱涓夋柟鑾峰彇鍒伴氫俊鏁版嵁鍚庯紝浼氳繘琛屾伓鎰忎慨鏀广
  • 韬唤浼犻闄╋細绗笁鏂瑰彲浠ュ啋鍏呬粬浜鸿韩浠藉弬涓庨氫俊銆
+
+

濡傛灉浼犺緭涓嶉噸瑕佺殑淇℃伅杩樺ソ锛屼絾鏄紶杈撶敤鎴峰瘑鐮佽繖浜涙晱鎰熶俊鎭紝閭e彲涓嶅緱浜嗐傛墍浠ヤ竴鑸兘瑕佷娇鐢https鍗忚浼犺緭鐢ㄦ埛瀵嗙爜淇℃伅銆

+
    +
  • https 鍘熺悊
+

https鍘熺悊鏄粈涔堝憿锛熶负浠涔堝畠鑳借В鍐砲ttp鐨勪笁澶ч闄╁憿锛

+
+

https = http + SSL/TLS, SSL/TLS 鏄紶杈撳眰鍔犲瘑鍗忚锛屽畠鎻愪緵鍐呭鍔犲瘑銆佽韩浠借璇併佹暟鎹畬鏁存ф牎楠岋紝浠ヨВ鍐虫暟鎹紶杈撶殑瀹夊叏鎬ч棶棰樸

+
+

涓轰簡鍔犳繁https鍘熺悊鐨勭悊瑙o紝鎴戜滑涓璧峰涔犱竴涓涓娆″畬鏁磆ttps鐨勮姹傛祦绋鍚

+
+
+
    +
    1. +
    2. 瀹㈡埛绔彂璧穐ttps璇锋眰
    +
    1. +
    2. 鏈嶅姟鍣ㄥ繀椤昏鏈変竴濂楁暟瀛楄瘉涔︼紝鍙互鑷繁鍒朵綔锛屼篃鍙互鍚戞潈濞佹満鏋勭敵璇枫傝繖濂楄瘉涔﹀叾瀹炲氨鏄竴瀵瑰叕绉侀挜銆
    +
    1. +
    2. 鏈嶅姟鍣ㄥ皢鑷繁鐨勬暟瀛楄瘉涔︼紙鍚湁鍏挜銆佽瘉涔︾殑棰佸彂鏈烘瀯绛夛級鍙戦佺粰瀹㈡埛绔
    +
    1. +
    2. 瀹㈡埛绔敹鍒版湇鍔″櫒绔殑鏁板瓧璇佷功涔嬪悗锛屼細瀵瑰叾杩涜楠岃瘉锛屼富瑕侀獙璇佸叕閽ユ槸鍚︽湁鏁堬紝姣斿棰佸彂鏈烘瀯锛岃繃鏈熸椂闂寸瓑绛夈傚鏋滀笉閫氳繃锛屽垯寮瑰嚭璀﹀憡妗嗐傚鏋滆瘉涔︽病闂锛屽垯鐢熸垚涓涓瘑閽ワ紙瀵圭О鍔犲瘑绠楁硶鐨勫瘑閽ワ紝鍏跺疄鏄竴涓殢鏈哄硷級锛屽苟涓旂敤璇佷功鐨勫叕閽ュ杩欎釜闅忔満鍊煎姞瀵嗐
    +
    1. +
    2. 瀹㈡埛绔細鍙戣捣https涓殑绗簩涓姹傦紝灏嗗姞瀵嗕箣鍚庣殑瀹㈡埛绔瘑閽(闅忔満鍊)鍙戦佺粰鏈嶅姟鍣ㄣ
    +
    1. +
    2. 鏈嶅姟鍣ㄦ帴鏀跺埌瀹㈡埛绔彂鏉ョ殑瀵嗛挜涔嬪悗锛屼細鐢ㄨ嚜宸辩殑绉侀挜瀵瑰叾杩涜闈炲绉拌В瀵嗭紝瑙e瘑涔嬪悗寰楀埌瀹㈡埛绔瘑閽ワ紝鐒跺悗鐢ㄥ鎴风瀵嗛挜瀵硅繑鍥炴暟鎹繘琛屽绉板姞瀵嗭紝杩欐牱鏁版嵁灏卞彉鎴愪簡瀵嗘枃銆
    +
    1. +
    2. 鏈嶅姟鍣ㄥ皢鍔犲瘑鍚庣殑瀵嗘枃杩斿洖缁欏鎴风銆
    +
    1. +
    2. 瀹㈡埛绔敹鍒版湇鍔″櫒鍙戣繑鍥炵殑瀵嗘枃锛岀敤鑷繁鐨勫瘑閽ワ紙瀹㈡埛绔瘑閽ワ級瀵瑰叾杩涜瀵圭О瑙e瘑锛屽緱鍒版湇鍔″櫒杩斿洖鐨勬暟鎹
    +
+
+
    +
  • https涓瀹氬畨鍏ㄥ悧锛
+

https鐨勬暟鎹紶杈撹繃绋嬶紝鏁版嵁閮芥槸瀵嗘枃鐨勶紝閭d箞锛屼娇鐢ㄤ簡https鍗忚浼犺緭瀵嗙爜淇℃伅锛屼竴瀹氭槸瀹夊叏鐨勫悧锛熷叾瀹涓嶇劧~

+
+
    +
  • 姣斿锛宧ttps 瀹屽叏灏辨槸寤虹珛鍦ㄨ瘉涔﹀彲淇$殑鍩虹涓婄殑鍛€備絾鏄鏋滈亣鍒颁腑闂翠汉浼犺瘉涔︼紝涓鏃﹀鎴风閫氳繃楠岃瘉锛屽畨鍏ㄦч】鏃跺氨娌′簡鍝︼紒骞虫椂鍚勭閽撻奔涓嶅彲鎻忚堪鐨勭綉绔欙紝寰堝彲鑳藉氨鏄粦瀹㈠湪璇卞鐢ㄦ埛瀹夎瀹冧滑鐨勪吉閫犺瘉涔︼紒
  • 閫氳繃浼犺瘉涔︼紝https涔熸槸鍙兘琚姄鍖呯殑鍝︺
+
+

1.2 瀵圭О鍔犲瘑绠楁硶

+

鏃㈢劧浣跨敤浜唄ttps鍗忚浼犺緭鐢ㄦ埛瀵嗙爜锛岃繕鏄涓嶄竴瀹氬畨鍏锛岄偅涔堬紝鎴戜滑灏辩粰鐢ㄦ埛瀵嗙爜鍔犲瘑鍐嶄紶杈鍛梸

+

鍔犲瘑绠楁硶鏈瀵圭О鍔犲瘑闈炲绉板姞瀵涓ゅぇ绫汇傜敤鍝绫诲瀷鐨勫姞瀵嗙畻娉闈犺氨鍛紵

+
+

瀵圭О鍔犲瘑锛氬姞瀵嗗拰瑙e瘑浣跨敤鐩稿悓瀵嗛挜鐨勫姞瀵嗙畻娉曘 +

+
+

甯哥敤鐨勫绉板姞瀵嗙畻娉曚富瑕佹湁浠ヤ笅鍑犵鍝堬細 +

+

濡傛灉浣跨敤瀵圭О鍔犲瘑绠楁硶锛岄渶瑕佽冭檻瀵嗛挜濡備綍缁欏埌瀵规柟锛屽鏋滃瘑閽ヨ繕鏄綉缁滀紶杈撶粰瀵规柟锛屼紶杈撹繃绋嬶紝琚腑闂翠汉鎷垮埌鐨勮瘽锛屼篃鏄湁椋庨櫓鐨勫摝銆

+

1.3 闈炲绉板姞瀵嗙畻娉

+

鍐嶈冭檻涓涓嬮潪瀵圭О鍔犲瘑绠楁硶鍛紵

+
+

闈炲绉板姞瀵嗭細 闈炲绉板姞瀵嗙畻娉曢渶瑕佷袱涓瘑閽ワ紙鍏紑瀵嗛挜鍜岀鏈夊瘑閽ワ級銆傚叕閽ヤ笌绉侀挜鏄垚瀵瑰瓨鍦ㄧ殑锛屽鏋滅敤鍏挜瀵规暟鎹繘琛屽姞瀵嗭紝鍙湁瀵瑰簲鐨勭閽ユ墠鑳借В瀵嗐

+
+
+

甯哥敤鐨勯潪瀵圭О鍔犲瘑绠楁硶涓昏鏈変互涓嬪嚑绉嶅搱锛 +

+
+

濡傛灉浣跨敤闈炲绉板姞瀵嗙畻娉曪紝涔熼渶瑕佽冭檻瀵嗛挜鍏挜濡備綍缁欏埌瀵规柟锛屽鏋滃叕閽ヨ繕鏄綉缁滀紶杈撶粰瀵规柟锛屼紶杈撹繃绋嬶紝琚腑闂翠汉鎷垮埌鐨勮瘽锛屼細鏈変粈涔堥棶棰樺憿锛浠栦滑鏄笉鏄彲浠ヤ吉閫犲叕閽ワ紝鎶婁吉閫犵殑鍏挜缁欏鎴风锛岀劧鍚庯紝鐢ㄨ嚜宸辩殑绉侀挜绛夊叕閽ュ姞瀵嗙殑鏁版嵁杩囨潵锛 澶у鍙互鎬濊冧笅杩欎釜闂鍝垀

+
+

鎴戜滑鐩存帴鐧诲綍涓涓嬬櫨搴锛屾姄涓嬫帴鍙h姹傦紝楠岃瘉涓鍙戝ぇ鍘傛槸鎬庝箞鍔犲瘑鐨勩傚彲浠ュ彂鐜版湁鑾峰彇鍏挜鎺ュ彛锛屽涓:

+
+

鍐嶇湅涓嬬櫥褰曟帴鍙o紝鍙戠幇灏辨槸RSA绠楁硶锛孯SA灏辨槸闈炲绉板姞瀵嗙畻娉銆傚叾瀹炵櫨搴﹀墠绔槸鐢ㄤ簡JavaScript搴jsencrypt锛屽湪github鐨剆tar杩樻尯澶氱殑銆

+
+

鍥犳锛屾垜浠彲浠ョ敤https + 闈炲绉板姞瀵嗙畻娉曪紙濡俁SA锛 浼犺緭鐢ㄦ埛瀵嗙爜~

+

2. 濡備綍瀹夊叏鍦板瓨鍌ㄤ綘鐨勫瘑鐮侊紵

+

鍋囪瀵嗙爜宸茬粡瀹夊叏鍒拌揪鏈嶅姟绔暒锛岄偅涔堬紝濡備綍瀛樺偍鐢ㄦ埛鐨勫瘑鐮佸憿锛熶竴瀹氫笉鑳芥槑鏂囧瓨鍌ㄥ瘑鐮佸埌鏁版嵁搴撳摝锛佸彲浠ョ敤鍝堝笇鎽樿绠楁硶鍔犲瘑瀵嗙爜锛屽啀淇濆瓨鍒版暟鎹簱銆

+
+

鍝堝笇鎽樿绠楁硶锛 鍙兘浠庢槑鏂囩敓鎴愪竴涓搴旂殑鍝堝笇鍊硷紝涓嶈兘鍙嶈繃鏉ユ牴鎹搱甯屽煎緱鍒板搴旂殑鏄庢枃銆

+
+

2.1 MD5鎽樿绠楁硶淇濇姢浣犵殑瀵嗙爜

+

MD5 鏄竴绉嶉潪甯哥粡鍏哥殑鍝堝笇鎽樿绠楁硶锛岃骞挎硾搴旂敤浜庢暟鎹畬鏁存ф牎楠屻佹暟鎹紙娑堟伅锛夋憳瑕併佹暟鎹姞瀵嗙瓑銆備絾鏄粎浠呬娇鐢 MD5 瀵瑰瘑鐮佽繘琛屾憳瑕侊紝骞朵笉瀹夊叏銆傛垜浠湅涓緥瀛愶紝濡備笅锛

+
public class MD5Test {
    public static void main(String[] args) {
        String password = "abc123456";
        System.out.println(DigestUtils.md5Hex(password));
    }
}
+

杩愯缁撴灉锛

+
0659c7992e268962384eb17fafe88364
+

鍦∕D5鍏嶈垂鐮磋В缃戠珯涓杈撳叆锛岄┈涓婂氨鍙互鐪嬪埌鍘熷瘑鐮佷簡銆傘傘

+
+

璇曟兂涓涓嬶紝濡傛灉榛戝鏋勫缓涓涓秴澶х殑鏁版嵁搴擄紝鎶婃墍鏈20浣嶆暟瀛椾互鍐呯殑鏁板瓧鍜屽瓧姣嶇粍鍚堢殑瀵嗙爜鍏ㄩ儴璁$畻MD5鍝堝笇鍊煎嚭鏉ワ紝骞朵笖鎶婂瘑鐮佸拰瀹冧滑瀵瑰簲鐨勫搱甯屽煎瓨鍒伴噷闈㈠幓锛堣繖灏辨槸褰╄櫣琛锛夈傚湪鐮磋В瀵嗙爜鐨勬椂鍊欙紝鍙渶瑕佹煡涓涓嬭繖涓僵铏硅〃灏卞畬浜嬩簡銆傛墍浠鍗曞崟MD5瀵瑰瘑鐮佸彇鍝堝笇鍊煎瓨鍌锛屽凡缁忎笉瀹夊叏鍟

+

2.2 MD5+鐩愭憳瑕佺畻娉曚繚鎶ょ敤鎴风殑瀵嗙爜

+

閭d箞锛屼负浠涔堜笉璇曚竴涓婱D5+鐩愬憿锛熶粈涔堟槸鍔犵洂

+
+

鍦ㄥ瘑鐮佸涓紝鏄寚閫氳繃鍦ㄥ瘑鐮佷换鎰忓浐瀹氫綅缃彃鍏ョ壒瀹氱殑瀛楃涓诧紝璁╂暎鍒楀悗鐨勭粨鏋滃拰浣跨敤鍘熷瀵嗙爜鐨勬暎鍒楃粨鏋滀笉鐩哥锛岃繖绉嶈繃绋嬬О涔嬩负鈥滃姞鐩愨濄

+
+

鐢ㄦ埛瀵嗙爜+鐩愪箣鍚庯紝杩涜鍝堝笇鏁e垪锛屽啀淇濆瓨鍒版暟鎹簱銆傝繖鏍峰彲浠ユ湁鏁堝簲瀵瑰僵铏硅〃鐮磋В娉曘備絾鏄憿锛屼娇鐢ㄥ姞鐩愶紝闇瑕佹敞鎰忎竴涓嬪嚑鐐癸細

+
+
    +
  • 涓嶈兘鍦ㄤ唬鐮佷腑鍐欐鐩愶紝涓旂洂闇瑕佹湁涓瀹氱殑闀垮害锛堢洂鍐欐澶畝鍗曠殑璇濓紝榛戝鍙兘娉ㄥ唽鍑犱釜璐﹀彿鍙嶆帹鍑烘潵锛
  • 姣忎竴涓瘑鐮侀兘鏈夌嫭绔嬬殑鐩愶紝骞朵笖鐩愯闀夸竴鐐癸紝姣斿瓒呰繃 20 浣嶃(鐩愬お鐭紝鍔犱笂鍘熷瀵嗙爜澶煭锛屽鏄撶牬瑙)
  • 鏈濂芥槸闅忔満鐨勫硷紝骞朵笖鏄叏鐞冨敮涓鐨勶紝鎰忓懗鐫鍏ㄧ悆涓嶅彲鑳芥湁鐜版垚鐨勫僵铏硅〃缁欎綘鐢ㄣ
+
+

2.3 鎻愬崌瀵嗙爜瀛樺偍瀹夊叏鐨勫埄鍣ㄧ櫥鍦猴紝Bcrypt

+

鍗充娇鏄姞浜嗙洂锛屽瘑鐮佷粛鏈夊彲鑳借鏆村姏鐮磋В銆傚洜姝わ紝鎴戜滑鍙互閲囧彇鏇鎱竴鐐鐨勭畻娉曪紝璁╅粦瀹㈢牬瑙e瘑鐮佷粯鍑烘洿澶х殑浠d环锛岀敋鑷宠揩浣夸粬浠斁寮冦傛彁鍗囧瘑鐮佸瓨鍌ㄥ畨鍏ㄧ殑鍒╁櫒~Bcrypt锛屽彲浠ラ棯浜櫥鍦哄暒銆

+
+

瀹為檯涓婏紝Spring Security 宸茬粡搴熷純浜 MessageDigestPasswordEncoder锛屾帹鑽愪娇鐢˙CryptPasswordEncoder锛屼篃灏辨槸BCrypt鏉ヨ繘琛屽瘑鐮佸搱甯屻侭Crypt 鐢熻屼负淇濆瓨瀵嗙爜璁捐鐨勭畻娉曪紝鐩告瘮 MD5 瑕佹參寰堝銆

+
+

鐪嬩釜渚嬪瓙瀵规瘮涓涓嬪惂锛

+
public class BCryptTest {

    public static void main(String[] args) {
        String password = "123456";
        long md5Begin = System.currentTimeMillis();
        DigestUtils.md5Hex(password);
        long md5End = System.currentTimeMillis();
        System.out.println("md5 time:"+(md5End - md5Begin));
        long bcrytBegin = System.currentTimeMillis();
        BCrypt.hashpw(password, BCrypt.gensalt(10));
        long bcrytEnd = System.currentTimeMillis();
        System.out.println("bcrypt Time:" + (bcrytEnd- bcrytBegin));
    }
}
+

杩愯缁撴灉锛

+
md5 time:47
bcrypt Time:1597
+

绮楃暐瀵规瘮鍙戠幇锛孊Crypt姣擬D5鎱㈠嚑鍗佸嶏紝榛戝鎯虫毚鍔涚牬瑙g殑璇濓紝灏遍渶瑕佽姳璐瑰嚑鍗佸嶇殑浠d环銆傚洜姝や竴鑸儏鍐碉紝寤鸿浣跨敤Bcrypt鏉ュ瓨鍌ㄧ敤鎴风殑瀵嗙爜

+

3. 鎬荤粨

+
    +
  • 鍥犳锛屼竴鑸娇鐢╤ttps 鍗忚 + 闈炲绉板姞瀵嗙畻娉曪紙濡俁SA锛夋潵浼犺緭鐢ㄦ埛瀵嗙爜锛屼负浜嗘洿鍔犲畨鍏紝鍙互鍦ㄥ墠绔瀯閫犱竴涓嬮殢鏈哄洜瀛愬摝銆
  • 浣跨敤BCrypt + 鐩愬瓨鍌ㄧ敤鎴峰瘑鐮併
  • 鍦ㄦ劅鐭ュ埌鏆村姏鐮磋В鍗卞鐨勬椂鍊欙紝寮鍚煭淇¢獙璇併佸浘褰㈤獙璇佺爜銆佽处鍙锋殏鏃堕攣瀹绛夐槻寰℃満鍒舵潵鎶靛尽鏆村姏鐮磋В銆
+

鍙傝冧笌鎰熻阿

+
    +
  • 濡備綍姝g‘淇濆瓨鍜屼紶杈撴晱鎰熸暟鎹紵 https://time.geekbang.org/column/article/239150[1]
  • 濡備綍鍔犲瘑浼犺緭鍜屽瓨鍌ㄧ敤鎴峰瘑鐮 https://juejin.cn/post/6844903604944371726#heading-8[2]
+

鍏紬鍙

+
    +
  • 鍏紬鍙凤細鎹$敯铻虹殑灏忕敺瀛
  • github鍦板潃锛歨ttps://github.com/whx123/JavaHome
+ + +
+ \ No newline at end of file diff --git "a/\345\267\245\344\275\234\346\200\273\347\273\223/\347\250\213\345\272\217\345\221\230\345\277\205\345\244\207\345\237\272\347\241\200\357\274\232\345\246\202\344\275\225\345\256\211\345\205\250\344\274\240\350\276\223\345\255\230\345\202\250\347\224\250\346\210\267\345\257\206\347\240\201.md.bak" "b/\345\267\245\344\275\234\346\200\273\347\273\223/\347\250\213\345\272\217\345\221\230\345\277\205\345\244\207\345\237\272\347\241\200\357\274\232\345\246\202\344\275\225\345\256\211\345\205\250\344\274\240\350\276\223\345\255\230\345\202\250\347\224\250\346\210\267\345\257\206\347\240\201.md.bak" new file mode 100644 index 0000000..e69de29 diff --git "a/\347\274\223\345\255\230Redis\346\200\273\347\273\223/\344\270\203\347\247\215\346\226\271\346\241\210\345\257\271\346\257\224\345\210\206\345\270\203\345\274\217\351\224\201.md" "b/\347\274\223\345\255\230Redis\346\200\273\347\273\223/\344\270\203\347\247\215\346\226\271\346\241\210\345\257\271\346\257\224\345\210\206\345\270\203\345\274\217\351\224\201.md" new file mode 100644 index 0000000..d861cdb --- /dev/null +++ "b/\347\274\223\345\255\230Redis\346\200\273\347\273\223/\344\270\203\347\247\215\346\226\271\346\241\210\345\257\271\346\257\224\345\210\206\345\270\203\345\274\217\351\224\201.md" @@ -0,0 +1,225 @@ +### 鍓嶈█ +鏃ュ父寮鍙戜腑锛岀鏉涓嬪崟銆佹姠绾㈠寘绛夌瓑涓氬姟鍦烘櫙锛岄兘闇瑕佺敤鍒板垎甯冨紡閿併傝孯edis闈炲父閫傚悎浣滀负鍒嗗竷寮忛攣浣跨敤銆傛湰鏂囧皢鍒嗕竷涓柟妗堝睍寮锛岃窡澶у鎺㈣Redis鍒嗗竷寮忛攣鐨勬纭娇鐢ㄦ柟寮忋傚鏋滄湁涓嶆纭殑鍦版柟锛屾杩庡ぇ瀹舵寚鍑哄搱锛屼竴璧峰涔犱竴璧疯繘姝ャ + + +鍏紬鍙凤細**鎹$敯铻虹殑灏忕敺瀛** + +- 浠涔堟槸鍒嗗竷寮忛攣 +- 鏂规涓锛歋ETNX + EXPIRE +- 鏂规浜岋細SETNX + value鍊兼槸锛堢郴缁熸椂闂+杩囨湡鏃堕棿锛 +- 鏂规涓夛細浣跨敤Lua鑴氭湰(鍖呭惈SETNX + EXPIRE涓ゆ潯鎸囦护) +- 鏂规鍥涳細SET鐨勬墿灞曞懡浠わ紙SET EX PX NX锛 +- 鏂规浜旓細SET EX PX NX + 鏍¢獙鍞竴闅忔満鍊,鍐嶉噴鏀鹃攣 +- 鏂规鍏: 寮婧愭鏋:Redisson +- 鏂规涓冿細澶氭満瀹炵幇鐨勫垎甯冨紡閿丷edlock + +- github鍦板潃锛屾劅璋㈡瘡棰梥tar +> https://github.com/whx123/JavaHome + + +### 浠涔堟槸鍒嗗竷寮忛攣 + +> 鍒嗗竷寮忛攣鍏跺疄灏辨槸锛屾帶鍒跺垎甯冨紡绯荤粺涓嶅悓杩涚▼鍏卞悓璁块棶鍏变韩璧勬簮鐨勪竴绉嶉攣鐨勫疄鐜般傚鏋滀笉鍚岀殑绯荤粺鎴栧悓涓涓郴缁熺殑涓嶅悓涓绘満涔嬮棿鍏变韩浜嗘煇涓复鐣岃祫婧愶紝寰寰闇瑕佷簰鏂ユ潵闃叉褰兼骞叉壈锛屼互淇濊瘉涓鑷存с + +鎴戜滑鍏堟潵鐪嬩笅锛屼竴鎶婇潬璋辩殑鍒嗗竷寮忛攣搴旇鏈夊摢浜涚壒寰侊細 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/42884a1613344c11be5fef3b9e8ed7c5~tplv-k3u1fbpfcp-zoom-1.image) + +- **浜掓枼鎬**: 浠绘剰鏃跺埢锛屽彧鏈変竴涓鎴风鑳芥寔鏈夐攣銆 +- **閿佽秴鏃堕噴鏀**锛氭寔鏈夐攣瓒呮椂锛屽彲浠ラ噴鏀撅紝闃叉涓嶅繀瑕佺殑璧勬簮娴垂锛屼篃鍙互闃叉姝婚攣銆 +- **鍙噸鍏ユ**:涓涓嚎绋嬪鏋滆幏鍙栦簡閿佷箣鍚,鍙互鍐嶆瀵瑰叾璇锋眰鍔犻攣銆 +- **楂樻ц兘鍜岄珮鍙敤**锛氬姞閿佸拰瑙i攣闇瑕佸紑閿灏藉彲鑳戒綆锛屽悓鏃朵篃瑕佷繚璇侀珮鍙敤锛岄伩鍏嶅垎甯冨紡閿佸け鏁堛 +- **瀹夊叏鎬**锛氶攣鍙兘琚寔鏈夌殑瀹㈡埛绔垹闄わ紝涓嶈兘琚叾浠栧鎴风鍒犻櫎 + +### Redis鍒嗗竷寮忛攣鏂规涓锛歋ETNX + EXPIRE + +鎻愬埌Redis鐨勫垎甯冨紡閿侊紝寰堝灏忎紮浼撮┈涓婂氨浼氭兂鍒癭``setnx```+ ```expire```鍛戒护銆傚嵆鍏堢敤```setnx```鏉ユ姠閿侊紝濡傛灉鎶㈠埌涔嬪悗锛屽啀鐢╜``expire```缁欓攣璁剧疆涓涓繃鏈熸椂闂达紝闃叉閿佸繕璁颁簡閲婃斁銆 + +> SETNX 鏄疭ET IF NOT EXISTS鐨勭畝鍐.鏃ュ父鍛戒护鏍煎紡鏄疭ETNX key value锛屽鏋 key涓嶅瓨鍦紝鍒橲ETNX鎴愬姛杩斿洖1锛屽鏋滆繖涓猭ey宸茬粡瀛樺湪浜嗭紝鍒欒繑鍥0銆 + +鍋囪鏌愮數鍟嗙綉绔欑殑鏌愬晢鍝佸仛绉掓潃娲诲姩锛宬ey鍙互璁剧疆涓簁ey_resource_id,value璁剧疆浠绘剰鍊硷紝浼唬鐮佸涓嬶細 + +``` +if锛坖edis.setnx(key_resource_id,lock_value) == 1锛墈 //鍔犻攣 + expire锛坘ey_resource_id锛100锛; //璁剧疆杩囨湡鏃堕棿 + try { + do something //涓氬姟璇锋眰 + }catch(){ +銆銆} +銆銆finally { + jedis.del(key_resource_id); //閲婃斁閿 + } +} +``` +浣嗘槸杩欎釜鏂规涓紝```setnx```鍜宍``expire```涓や釜鍛戒护鍒嗗紑浜嗭紝**涓嶆槸鍘熷瓙鎿嶄綔**銆傚鏋滄墽琛屽畬```setnx```鍔犻攣锛屾瑕佹墽琛宍``expire```璁剧疆杩囨湡鏃堕棿鏃讹紝杩涚▼crash鎴栬呰閲嶅惎缁存姢浜嗭紝閭d箞杩欎釜閿佸氨鈥滈暱鐢熶笉鑰佲濅簡锛**鍒殑绾跨▼姘歌繙鑾峰彇涓嶅埌閿佸暒**銆 + + +### Redis鍒嗗竷寮忛攣鏂规浜岋細SETNX + value鍊兼槸(绯荤粺鏃堕棿+杩囨湡鏃堕棿) + +涓轰簡瑙e喅鏂规涓锛**鍙戠敓寮傚父閿佸緱涓嶅埌閲婃斁鐨勫満鏅**锛屾湁灏忎紮浼磋涓猴紝鍙互鎶婅繃鏈熸椂闂存斁鍒癭``setnx```鐨剉alue鍊奸噷闈€傚鏋滃姞閿佸け璐ワ紝鍐嶆嬁鍑簐alue鍊兼牎楠屼竴涓嬪嵆鍙傚姞閿佷唬鐮佸涓嬶細 +``` +long expires = System.currentTimeMillis() + expireTime; //绯荤粺鏃堕棿+璁剧疆鐨勮繃鏈熸椂闂 +String expiresStr = String.valueOf(expires); + +// 濡傛灉褰撳墠閿佷笉瀛樺湪锛岃繑鍥炲姞閿佹垚鍔 +if (jedis.setnx(key_resource_id, expiresStr) == 1) { + return true; +} +// 濡傛灉閿佸凡缁忓瓨鍦紝鑾峰彇閿佺殑杩囨湡鏃堕棿 +String currentValueStr = jedis.get(key_resource_id); + +// 濡傛灉鑾峰彇鍒扮殑杩囨湡鏃堕棿锛屽皬浜庣郴缁熷綋鍓嶆椂闂达紝琛ㄧず宸茬粡杩囨湡 +if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) { + + // 閿佸凡杩囨湡锛岃幏鍙栦笂涓涓攣鐨勮繃鏈熸椂闂达紝骞惰缃幇鍦ㄩ攣鐨勮繃鏈熸椂闂达紙涓嶄簡瑙edis鐨刧etSet鍛戒护鐨勫皬浼欎即锛屽彲浠ュ幓瀹樼綉鐪嬩笅鍝堬級 + String oldValueStr = jedis.getSet(key_resource_id, expiresStr); + + if (oldValueStr != null && oldValueStr.equals(currentValueStr)) { + // 鑰冭檻澶氱嚎绋嬪苟鍙戠殑鎯呭喌锛屽彧鏈変竴涓嚎绋嬬殑璁剧疆鍊煎拰褰撳墠鍊肩浉鍚岋紝瀹冩墠鍙互鍔犻攣 + return true; + } +} + +//鍏朵粬鎯呭喌锛屽潎杩斿洖鍔犻攣澶辫触 +return false; +} +``` + +杩欎釜鏂规鐨勪紭鐐规槸锛屽阀濡欑Щ闄``expire```鍗曠嫭璁剧疆杩囨湡鏃堕棿鐨勬搷浣滐紝鎶**杩囨湡鏃堕棿鏀惧埌setnx鐨剉alue鍊**閲岄潰鏉ャ傝В鍐充簡鏂规涓鍙戠敓寮傚父锛岄攣寰椾笉鍒伴噴鏀剧殑闂銆備絾鏄繖涓柟妗堣繕鏈夊埆鐨勭己鐐癸細 + +> - 杩囨湡鏃堕棿鏄鎴风鑷繁鐢熸垚鐨勶紙System.currentTimeMillis()鏄綋鍓嶇郴缁熺殑鏃堕棿锛夛紝蹇呴』瑕佹眰鍒嗗竷寮忕幆澧冧笅锛屾瘡涓鎴风鐨勬椂闂村繀椤诲悓姝ャ +> - 濡傛灉閿佽繃鏈熺殑鏃跺欙紝骞跺彂澶氫釜瀹㈡埛绔悓鏃惰姹傝繃鏉ワ紝閮芥墽琛宩edis.getSet()锛屾渶缁堝彧鑳芥湁涓涓鎴风鍔犻攣鎴愬姛锛屼絾鏄瀹㈡埛绔攣鐨勮繃鏈熸椂闂达紝鍙兘琚埆鐨勫鎴风瑕嗙洊 +> - 璇ラ攣娌℃湁淇濆瓨鎸佹湁鑰呯殑鍞竴鏍囪瘑锛屽彲鑳借鍒殑瀹㈡埛绔噴鏀/瑙i攣銆 + + +### Redis鍒嗗竷寮忛攣鏂规涓夛細浣跨敤Lua鑴氭湰(鍖呭惈SETNX + EXPIRE涓ゆ潯鎸囦护) + +瀹為檯涓婏紝鎴戜滑杩樺彲浠ヤ娇鐢↙ua鑴氭湰鏉ヤ繚璇佸師瀛愭э紙鍖呭惈setnx鍜宔xpire涓ゆ潯鎸囦护锛夛紝lua鑴氭湰濡備笅锛 +``` +if redis.call('setnx',KEYS[1],ARGV[1]) == 1 then + redis.call('expire',KEYS[1],ARGV[2]) +else + return 0 +end; +``` +鍔犻攣浠g爜濡備笅锛 + +``` + String lua_scripts = "if redis.call('setnx',KEYS[1],ARGV[1]) == 1 then" + + " redis.call('expire',KEYS[1],ARGV[2]) return 1 else return 0 end"; +Object result = jedis.eval(lua_scripts, Collections.singletonList(key_resource_id), Collections.singletonList(values)); +//鍒ゆ柇鏄惁鎴愬姛 +return result.equals(1L); +``` +杩欎釜鏂规杩樻槸鏈夌己鐐圭殑鍝︼紝鑷充簬鍝簺缂虹偣锛屼綘鍏堟濊冧竴涓嬨備篃鍙互鎯充笅銆傝窡鏂规浜屽姣旓紝鍝釜鏇村ソ锛 + +### Redis鍒嗗竷寮忛攣鏂规鏂规鍥涳細SET鐨勬墿灞曞懡浠わ紙SET EX PX NX锛 + +闄や簡浣跨敤锛屼娇鐢↙ua鑴氭湰锛屼繚璇乣``SETNX + EXPIRE```涓ゆ潯鎸囦护鐨勫師瀛愭э紝鎴戜滑杩樺彲浠ュ阀鐢≧edis鐨凷ET鎸囦护鎵╁睍鍙傛暟锛侊紙```SET key value[EX seconds][PX milliseconds][NX|XX]```锛夛紝瀹冧篃鏄師瀛愭х殑锛 + +> SET key value[EX seconds][PX milliseconds][NX|XX] +> - NX :琛ㄧずkey涓嶅瓨鍦ㄧ殑鏃跺欙紝鎵嶈兘set鎴愬姛锛屼篃鍗充繚璇佸彧鏈夌涓涓鎴风璇锋眰鎵嶈兘鑾峰緱閿侊紝鑰屽叾浠栧鎴风璇锋眰鍙兘绛夊叾閲婃斁閿侊紝鎵嶈兘鑾峰彇銆 +> - EX seconds :璁惧畾key鐨勮繃鏈熸椂闂达紝鏃堕棿鍗曚綅鏄銆 +> - PX milliseconds: 璁惧畾key鐨勮繃鏈熸椂闂达紝鍗曚綅涓烘绉 +> - XX: 浠呭綋key瀛樺湪鏃惰缃 + +浼唬鐮乨emo濡備笅锛 +``` +if锛坖edis.set(key_resource_id, lock_value, "NX", "EX", 100s) == 1锛墈 //鍔犻攣 + try { + do something //涓氬姟澶勭悊 + }catch(){ +銆銆} +銆銆finally { + jedis.del(key_resource_id); //閲婃斁閿 + } +} +``` + +浣嗘槸鍛紝杩欎釜鏂规杩樻槸鍙兘瀛樺湪闂锛 + +- 闂涓锛**閿佽繃鏈熼噴鏀句簡锛屼笟鍔¤繕娌℃墽琛屽畬**銆傚亣璁剧嚎绋媋鑾峰彇閿佹垚鍔燂紝涓鐩村湪鎵ц涓寸晫鍖虹殑浠g爜銆備絾鏄100s杩囧幓鍚庯紝瀹冭繕娌℃墽琛屽畬銆備絾鏄紝杩欐椂鍊欓攣宸茬粡杩囨湡浜嗭紝姝ゆ椂绾跨▼b鍙堣姹傝繃鏉ャ傛樉鐒剁嚎绋媌灏卞彲浠ヨ幏寰楅攣鎴愬姛锛屼篃寮濮嬫墽琛屼复鐣屽尯鐨勪唬鐮併傞偅涔堥棶棰樺氨鏉ヤ簡锛屼复鐣屽尯鐨勪笟鍔′唬鐮侀兘涓嶆槸涓ユ牸涓茶鎵ц鐨勫暒銆 +- 闂浜岋細**閿佽鍒殑绾跨▼璇垹**銆傚亣璁剧嚎绋媋鎵ц瀹屽悗锛屽幓閲婃斁閿併備絾鏄畠涓嶇煡閬撳綋鍓嶇殑閿佸彲鑳芥槸绾跨▼b鎸佹湁鐨勶紙绾跨▼a鍘婚噴鏀鹃攣鏃讹紝鏈夊彲鑳借繃鏈熸椂闂村凡缁忓埌浜嗭紝姝ゆ椂绾跨▼b杩涙潵鍗犳湁浜嗛攣锛夈傞偅绾跨▼a灏辨妸绾跨▼b鐨勯攣閲婃斁鎺変簡锛屼絾鏄嚎绋媌涓寸晫鍖轰笟鍔′唬鐮佸彲鑳介兘杩樻病鎵ц瀹屽憿銆 + +### 鏂规浜旓細SET EX PX NX + 鏍¢獙鍞竴闅忔満鍊,鍐嶅垹闄 + +鏃㈢劧閿佸彲鑳借鍒殑绾跨▼璇垹锛岄偅鎴戜滑缁檝alue鍊艰缃竴涓爣璁板綋鍓嶇嚎绋嬪敮涓鐨勯殢鏈烘暟锛屽湪鍒犻櫎鐨勬椂鍊欙紝鏍¢獙涓涓嬶紝涓嶅氨OK浜嗗槢銆備吉浠g爜濡備笅锛 +``` +if锛坖edis.set(key_resource_id, uni_request_id, "NX", "EX", 100s) == 1锛墈 //鍔犻攣 + try { + do something //涓氬姟澶勭悊 + }catch(){ +銆銆} +銆銆finally { + //鍒ゆ柇鏄笉鏄綋鍓嶇嚎绋嬪姞鐨勯攣,鏄墠閲婃斁 + if (uni_request_id.equals(jedis.get(key_resource_id))) { + jedis.del(lockKey); //閲婃斁閿 + } + } +} +``` + +鍦ㄨ繖閲岋紝**鍒ゆ柇鏄笉鏄綋鍓嶇嚎绋嬪姞鐨勯攣**鍜**閲婃斁閿**涓嶆槸涓涓師瀛愭搷浣溿傚鏋滆皟鐢╦edis.del()閲婃斁閿佺殑鏃跺欙紝鍙兘杩欐妸閿佸凡缁忎笉灞炰簬褰撳墠瀹㈡埛绔紝浼氳В闄や粬浜哄姞鐨勯攣銆 + +![](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9237655e6b1a47038d2774231e507e11~tplv-k3u1fbpfcp-watermark.image) + +涓轰簡鏇翠弗璋紝涓鑸篃鏄敤lua鑴氭湰浠f浛銆俵ua鑴氭湰濡備笅锛 +``` +if redis.call('get',KEYS[1]) == ARGV[1] then + return redis.call('del',KEYS[1]) +else + return 0 +end; +``` + +### Redis鍒嗗竷寮忛攣鏂规鍏細Redisson妗嗘灦 + +鏂规浜旇繕鏄彲鑳藉瓨鍦**閿佽繃鏈熼噴鏀撅紝涓氬姟娌℃墽琛屽畬**鐨勯棶棰樸傛湁浜涘皬浼欎即璁や负锛岀◢寰妸閿佽繃鏈熸椂闂磋缃暱涓浜涘氨鍙互鍟︺傚叾瀹炴垜浠鎯充竴涓嬶紝鏄惁鍙互缁欒幏寰楅攣鐨勭嚎绋嬶紝寮鍚竴涓畾鏃跺畧鎶ょ嚎绋嬶紝姣忛殧涓娈垫椂闂存鏌ラ攣鏄惁杩樺瓨鍦紝瀛樺湪鍒欏閿佺殑杩囨湡鏃堕棿寤堕暱锛岄槻姝㈤攣杩囨湡鎻愬墠閲婃斁銆 + +褰撳墠寮婧愭鏋禦edisson瑙e喅浜嗚繖涓棶棰樸傛垜浠竴璧锋潵鐪嬩笅Redisson搴曞眰鍘熺悊鍥惧惂锛 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/367cd1a7a3fb4d398988e4166416d71d~tplv-k3u1fbpfcp-zoom-1.image) + + +鍙绾跨▼涓鍔犻攣鎴愬姛锛屽氨浼氬惎鍔ㄤ竴涓猔``watch dog```鐪嬮棬鐙楋紝瀹冩槸涓涓悗鍙扮嚎绋嬶紝浼氭瘡闅10绉掓鏌ヤ竴涓嬶紝濡傛灉绾跨▼1杩樻寔鏈夐攣锛岄偅涔堝氨浼氫笉鏂殑寤堕暱閿乲ey鐨勭敓瀛樻椂闂淬傚洜姝わ紝Redisson灏辨槸浣跨敤Redisson瑙e喅浜**閿佽繃鏈熼噴鏀撅紝涓氬姟娌℃墽琛屽畬**闂銆 + +### Redis鍒嗗竷寮忛攣鏂规涓冿細澶氭満瀹炵幇鐨勫垎甯冨紡閿丷edlock+Redisson + +鍓嶉潰鍏鏂规閮藉彧鏄熀浜庡崟鏈虹増鐨勮璁猴紝杩樹笉鏄緢瀹岀編銆傚叾瀹濺edis涓鑸兘鏄泦缇ら儴缃茬殑锛 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7349794feeee458aa71c27f27a0b2428~tplv-k3u1fbpfcp-watermark.image) + +濡傛灉绾跨▼涓鍦≧edis鐨刴aster鑺傜偣涓婃嬁鍒颁簡閿侊紝浣嗘槸鍔犻攣鐨刱ey杩樻病鍚屾鍒皊lave鑺傜偣銆傛伆濂借繖鏃讹紝master鑺傜偣鍙戠敓鏁呴殰锛屼竴涓猻lave鑺傜偣灏变細鍗囩骇涓簃aster鑺傜偣銆傜嚎绋嬩簩灏卞彲浠ヨ幏鍙栧悓涓猭ey鐨勯攣鍟︼紝浣嗙嚎绋嬩竴涔熷凡缁忔嬁鍒伴攣浜嗭紝閿佺殑瀹夊叏鎬у氨娌′簡銆 + +涓轰簡瑙e喅杩欎釜闂锛孯edis浣滆 antirez鎻愬嚭涓绉嶉珮绾х殑鍒嗗竷寮忛攣绠楁硶锛歊edlock銆俁edlock鏍稿績鎬濇兂鏄繖鏍风殑锛 +> 鎼炲涓猂edis master閮ㄧ讲锛屼互淇濊瘉瀹冧滑涓嶄細鍚屾椂瀹曟帀銆傚苟涓旇繖浜沵aster鑺傜偣鏄畬鍏ㄧ浉浜掔嫭绔嬬殑锛岀浉浜掍箣闂翠笉瀛樺湪鏁版嵁鍚屾銆傚悓鏃讹紝闇瑕佺‘淇濆湪杩欏涓猰aster瀹炰緥涓婏紝鏄笌鍦≧edis鍗曞疄渚嬶紝浣跨敤鐩稿悓鏂规硶鏉ヨ幏鍙栧拰閲婃斁閿併 + +鎴戜滑鍋囪褰撳墠鏈5涓猂edis master鑺傜偣锛屽湪5鍙版湇鍔″櫒涓婇潰杩愯杩欎簺Redis瀹炰緥銆 + +![](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0df0a36c7ccd439291a8a869ff4ddad3~tplv-k3u1fbpfcp-watermark.image) + +RedLock鐨勫疄鐜版楠:濡備笅 +> - 1.鑾峰彇褰撳墠鏃堕棿锛屼互姣涓哄崟浣嶃 +> - 2.鎸夐『搴忓悜5涓猰aster鑺傜偣璇锋眰鍔犻攣銆傚鎴风璁剧疆缃戠粶杩炴帴鍜屽搷搴旇秴鏃舵椂闂达紝骞朵笖瓒呮椂鏃堕棿瑕佸皬浜庨攣鐨勫け鏁堟椂闂淬傦紙鍋囪閿佽嚜鍔ㄥけ鏁堟椂闂翠负10绉掞紝鍒欒秴鏃舵椂闂翠竴鑸湪5-50姣涔嬮棿,鎴戜滑灏卞亣璁捐秴鏃舵椂闂存槸50ms鍚э級銆傚鏋滆秴鏃讹紝璺宠繃璇aster鑺傜偣锛屽敖蹇幓灏濊瘯涓嬩竴涓猰aster鑺傜偣銆 +> - 3.瀹㈡埛绔娇鐢ㄥ綋鍓嶆椂闂村噺鍘诲紑濮嬭幏鍙栭攣鏃堕棿锛堝嵆姝ラ1璁板綍鐨勬椂闂达級锛屽緱鍒拌幏鍙栭攣浣跨敤鐨勬椂闂淬傚綋涓斾粎褰撹秴杩囦竴鍗婏紙N/2+1锛岃繖閲屾槸5/2+1=3涓妭鐐癸級鐨凴edis master鑺傜偣閮借幏寰楅攣锛屽苟涓斾娇鐢ㄧ殑鏃堕棿灏忎簬閿佸け鏁堟椂闂存椂锛岄攣鎵嶇畻鑾峰彇鎴愬姛銆傦紙濡備笂鍥撅紝10s> 30ms+40ms+50ms+4m0s+50ms锛 +> - 濡傛灉鍙栧埌浜嗛攣锛宬ey鐨勭湡姝f湁鏁堟椂闂村氨鍙樺暒锛岄渶瑕佸噺鍘昏幏鍙栭攣鎵浣跨敤鐨勬椂闂淬 +> - 濡傛灉鑾峰彇閿佸け璐ワ紙娌℃湁鍦ㄨ嚦灏慛/2+1涓猰aster瀹炰緥鍙栧埌閿侊紝鏈夋垨鑰呰幏鍙栭攣鏃堕棿宸茬粡瓒呰繃浜嗘湁鏁堟椂闂达級锛屽鎴风瑕佸湪鎵鏈夌殑master鑺傜偣涓婅В閿侊紙鍗充究鏈変簺master鑺傜偣鏍规湰灏辨病鏈夊姞閿佹垚鍔燂紝涔熼渶瑕佽В閿侊紝浠ラ槻姝㈡湁浜涙紡缃戜箣楸硷級銆 + +绠鍖栦笅姝ラ灏辨槸锛 +- 鎸夐『搴忓悜5涓猰aster鑺傜偣璇锋眰鍔犻攣 +- 鏍规嵁璁剧疆鐨勮秴鏃舵椂闂存潵鍒ゆ柇锛屾槸涓嶆槸瑕佽烦杩囪master鑺傜偣銆 +- 濡傛灉澶т簬绛変簬涓変釜鑺傜偣鍔犻攣鎴愬姛锛屽苟涓斾娇鐢ㄧ殑鏃堕棿灏忎簬閿佺殑鏈夋晥鏈燂紝鍗冲彲璁ゅ畾鍔犻攣鎴愬姛鍟︺ +- 濡傛灉鑾峰彇閿佸け璐ワ紝瑙i攣锛 + +Redisson瀹炵幇浜唕edLock鐗堟湰鐨勯攣锛屾湁鍏磋叮鐨勫皬浼欎即锛屽彲浠ュ幓浜嗚В涓涓嬪搱~ + +### 鍏紬鍙 +- 娆㈣繋鍏虫敞鍏紬鍙凤細鎹$敯铻虹殑灏忕敺瀛 + +### 鍙傝冧笌鎰熻阿 + +- [redis绯诲垪锛氬垎甯冨紡閿乚(https://juejin.cn/post/6844903656911798285 "redis绯诲垪锛氬垎甯冨紡閿") +- [娴呮瀽 Redis 鍒嗗竷寮忛攣瑙e喅鏂规](https://www.infoq.cn/article/dvaaj71f4fbqsxmgvdce "娴呮瀽 Redis 鍒嗗竷寮忛攣瑙e喅鏂规") +- [缁嗚Redis鍒嗗竷寮忛攣馃敀](https://juejin.cn/post/6844904082860146695#heading-3 "缁嗚Redis鍒嗗竷寮忛攣馃敀") +- [Redlock锛歊edis鍒嗗竷寮忛攣鏈鐗涢肩殑瀹炵幇](https://mp.weixin.qq.com/s?__biz=MzU5ODUwNzY1Nw==&mid=2247484155&idx=1&sn=0c73f45f2f641ba0bf4399f57170ac9b&scene=21#wechat_redirect) + diff --git "a/\347\274\223\345\255\230Redis\346\200\273\347\273\223/\344\275\277\347\224\250Redis\347\232\20421\344\270\252\346\263\250\346\204\217\347\202\271.md" "b/\347\274\223\345\255\230Redis\346\200\273\347\273\223/\344\275\277\347\224\250Redis\347\232\20421\344\270\252\346\263\250\346\204\217\347\202\271.md" new file mode 100644 index 0000000..6a4364e --- /dev/null +++ "b/\347\274\223\345\255\230Redis\346\200\273\347\273\223/\344\275\277\347\224\250Redis\347\232\20421\344\270\252\346\263\250\346\204\217\347\202\271.md" @@ -0,0 +1,386 @@ +### 前言 + +最近在学习Redis相关知识,看了阿里的redis开发规范,以及Redis开发与运维这本书。分使用规范、有坑的命令、项目实战操作、运维配置四个方向。整理了使用Redis的21个注意点,希望对大家有帮助,一起学习哈 + +公众号:**捡田螺的小男孩** +![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c59661f74a014a63a4527939096f11aa~tplv-k3u1fbpfcp-watermark.image) + +## 1、Redis的使用规范 + +### 1.1、 key的规范要点 + +我们设计Redis的key的时候,要注意以下这几个点: + +> - 以业务名为key前缀,用冒号隔开,以防止key冲突覆盖。如,live:rank:1 +> - 确保key的语义清晰的情况下,key的长度尽量小于30个字符。 +> - key禁止包含特殊字符,如空格、换行、单双引号以及其他转义字符。 +> - Redis的key尽量设置ttl,以保证不使用的Key能被及时清理或淘汰。 + +### 1.2、value的规范要点 + +Redis的value值不可以随意设置的哦。 + +**第一点**,如果大量存储bigKey是会有问题的,会导致慢查询,内存增长过快等等。 +> - 如果是String类型,单个value大小控制10k以内。 +> - 如果是hash、list、set、zset类型,元素个数一般不超过5000。 + + +**第二点**,要选择适合的数据类型。不少小伙伴只用Redis的String类型,上来就是set和get。实际上,Redis 提供了**丰富的数据结构类型**,有些业务场景,更适合```hash、zset```等其他数据结果。 + +![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1874e69c709940fd80d66cc8ab683135~tplv-k3u1fbpfcp-watermark.image) + +**反例:** + +``` +set user:666:name jay +set user:666:age 18 +``` + +**正例** + +``` +hmset user:666 name jay age 18 +``` + +### 1.3. 给Key设置过期时间,同时注意不同业务的key,尽量过期时间分散一点 + +- 因为Redis的数据是存在内存中的,而内存资源是很宝贵的。 +- 我们一般是把Redis当做缓存来用,而**不是数据库**,所以key的生命周期就不宜太长久啦。 +- 因此,你的key,一般建议用**expire设置过期时间**。 + + +如果大量的key在某个时间点集中过期,到过期的那个时间点,Redis可能会存在卡顿,甚至出现**缓存雪崩**现象,因此一般不同业务的key,过期时间应该分散一些。有时候,同业务的,也可以在时间上加一个随机值,让过期时间分散一些。 + + +### 1.4.建议使用批量操作提高效率 + +我们日常写SQL的时候,都知道,批量操作效率会更高,一次更新50条,比循环50次,每次更新一条效率更高。其实Redis操作命令也是这个道理。 + +Redis客户端执行一次命令可分为4个过程:1.发送命令-> 2.命令排队-> 3.命令执行-> 4. 返回结果。1和4 称为RRT(命令执行往返时间)。 Redis提供了**批量操作命令,如mget、mset**等,可有效节约RRT。但是呢,大部分的命令,是不支持批量操作的,比如hgetall,并没有mhgetall存在。**Pipeline** 则可以解决这个问题。 + +> Pipeline是什么呢?它能将一组Redis命令进行组装,通过一次RTT传输给Redis,再将这组Redis命令的执行结果按顺序返回给客户端. + +我们先来看下没有使用Pipeline执行了n条命令的模型: + +![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b71283614a3344c4afac8ac82438fa44~tplv-k3u1fbpfcp-watermark.image) + +使用Pipeline执行了n次命令,整个过程需要1次RTT,模型如下: + +![image.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b865d241c02d45e7a88540ab7f70280a~tplv-k3u1fbpfcp-watermark.image) + +## 2、Redis 有坑的那些命令 + + +### 2.1. 慎用```O(n)```复杂度命令,如```hgetall```、```smember```,```lrange```等 + +因为Redis是单线程执行命令的。hgetall、smember等命令时间复杂度为O(n),当n持续增加时,会导致 Redis CPU 持续飙高,阻塞其他命令的执行。 + +> hgetall、smember,lrange等这些命令不是一定不能使用,需要综合评估数据量,明确n的值,再去决定。 +> 比如hgetall,如果哈希元素n比较多的话,可以优先考虑使用**hscan**。 + + +### 2.2 慎用Redis的monitor命令 + +Redis Monitor 命令用于实时打印出Redis服务器接收到的命令,如果我们想知道客户端对redis服务端做了哪些命令操作,就可以用Monitor 命令查看,但是它一般**调试**用而已,尽量不要在生产上用!因为**monitor命令可能导致redis的内存持续飙升。** + +> monitor的模型是酱紫的,它会将所有在Redis服务器执行的命令进行输出,一般来讲Redis服务器的QPS是很高的,也就是如果执行了monitor命令,Redis服务器在Monitor这个客户端的输出缓冲区又会有大量“存货”,也就占用了大量Redis内存。 + + +![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d3610a4a95fe4995862d9ddd878269fe~tplv-k3u1fbpfcp-watermark.image) + + +### 2.3、生产环境不能使用 keys指令 + +Redis Keys 命令用于查找所有符合给定模式pattern的key。如果想查看Redis 某类型的key有多少个,不少小伙伴想到用keys命令,如下: + +``` +keys key前缀* +``` + +但是,redis的```keys```是遍历匹配的,复杂度是```O(n)```,数据库数据越多就越慢。我们知道,redis是单线程的,如果数据比较多的话,keys指令就会导致redis线程阻塞,线上服务也会停顿了,直到指令执行完,服务才会恢复。因此,**一般在生产环境,不要使用keys指令**。官方文档也有声明: + +> Warning: consider KEYS as a command that should only be used in production environments with extreme care. It may ruin performance when it is executed against large databases. This command is intended for debugging and special operations, such as changing your keyspace layout. Don't use KEYS in your regular application code. If you're looking for a way to find keys in a subset of your keyspace, consider using sets. + +其实,可以使用scan指令,它同keys命令一样提供模式匹配功能。它的复杂度也是 O(n),但是它通过游标分步进行,**不会阻塞redis线程**;但是会有一定的**重复概率**,需要在**客户端做一次去重**。 + +> scan支持增量式迭代命令,增量式迭代命令也是有缺点的:举个例子, 使用 SMEMBERS 命令可以返回集合键当前包含的所有元素, 但是对于 SCAN 这类增量式迭代命令来说, 因为在对键进行增量式迭代的过程中, 键可能会被修改, 所以增量式迭代命令只能对被返回的元素提供有限的保证 。 + + +### 2.4 禁止使用flushall、flushdb + +> - Flushall 命令用于清空整个 Redis 服务器的数据(删除所有数据库的所有 key )。 +> - Flushdb 命令用于清空当前数据库中的所有 key。 + +这两命令是原子性的,不会终止执行。一旦开始执行,不会执行失败的。 + +### 2.5 注意使用del命令 + +删除key你一般使用什么命令?是直接del?如果删除一个key,直接使用del命令当然没问题。但是,你想过del的时间复杂度是多少嘛?我们分情况探讨一下: +- 如果删除一个String类型的key,时间复杂度就是```O(1)```,**可以直接del**。 +- 如果删除一个List/Hash/Set/ZSet类型时,它的复杂度是```O(n)```, n表示元素个数。 + +因此,如果你删除一个List/Hash/Set/ZSet类型的key时,元素越多,就越慢。**当n很大时,要尤其注意**,会阻塞主线程的。那么,如果不用del,我们应该怎么删除呢? + +> - 如果是List类型,你可以执行```lpop或者rpop```,直到所有元素删除完成。 +> - 如果是Hash/Set/ZSet类型,你可以先执行```hscan/sscan/scan```查询,再执行```hdel/srem/zrem```依次删除每个元素。 + +### 2.6 避免使用SORT、SINTER等复杂度过高的命令。 + +执行复杂度较高的命令,会消耗更多的 CPU 资源,会阻塞主线程。所以你要避免执行如```SORT、SINTER、SINTERSTORE、ZUNIONSTORE、ZINTERSTORE```等聚合命令,一般建议把它放到客户端来执行。 + +## 3、项目实战避坑操作 + +### 3.1 分布式锁使用的注意点 + +分布式锁其实就是,控制分布式系统不同进程共同访问共享资源的一种锁的实现。秒杀下单、抢红包等等业务场景,都需要用到分布式锁。我们经常使用Redis作为分布式锁,主要有这些注意点: + +#### 3.1.1 两个命令SETNX + EXPIRE分开写(典型错误实现范例) +``` +if(jedis.setnx(key_resource_id,lock_value) == 1){ //加锁 + expire(key_resource_id,100); //设置过期时间 + try { + do something //业务请求 + }catch(){ +  } +  finally { + jedis.del(key_resource_id); //释放锁 + } +} +``` +如果执行完```setnx```加锁,正要执行expire设置过期时间时,进程crash或者要重启维护了,那么这个锁就“长生不老”了,**别的线程永远获取不到锁**啦,所以一般分布式锁不能这么实现。 + +#### 3.1.2 SETNX + value值是过期时间 (有些小伙伴是这么实现,有坑) + + +``` +long expires = System.currentTimeMillis() + expireTime; //系统时间+设置的过期时间 +String expiresStr = String.valueOf(expires); + +// 如果当前锁不存在,返回加锁成功 +if (jedis.setnx(key_resource_id, expiresStr) == 1) { + return true; +} +// 如果锁已经存在,获取锁的过期时间 +String currentValueStr = jedis.get(key_resource_id); + +// 如果获取到的过期时间,小于系统当前时间,表示已经过期 +if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) { + + // 锁已过期,获取上一个锁的过期时间,并设置现在锁的过期时间(不了解redis的getSet命令的小伙伴,可以去官网看下哈) + String oldValueStr = jedis.getSet(key_resource_id, expiresStr); + + if (oldValueStr != null && oldValueStr.equals(currentValueStr)) { + // 考虑多线程并发的情况,只有一个线程的设置值和当前值相同,它才可以加锁 + return true; + } +} + +//其他情况,均返回加锁失败 +return false; +} +``` +这种方案的**缺点**: +> - 过期时间是客户端自己生成的,分布式环境下,每个客户端的时间必须同步 +> - 没有保存持有者的唯一标识,可能被别的客户端释放/解锁。 +> - 锁过期的时候,并发多个客户端同时请求过来,都执行了```jedis.getSet()```,最终只能有一个客户端加锁成功,但是该客户端锁的过期时间,可能被别的客户端覆盖。 + +#### 3.1.3: SET的扩展命令(SET EX PX NX)(注意可能存在的问题) + +``` +if(jedis.set(key_resource_id, lock_value, "NX", "EX", 100s) == 1){ //加锁 + try { + do something //业务处理 + }catch(){ +  } +  finally { + jedis.del(key_resource_id); //释放锁 + } +} +``` + +这个方案还是可能存在问题: +- 锁过期释放了,业务还没执行完。 +- 锁被别的线程误删。 + + +#### 3.1.4 SET EX PX NX + 校验唯一随机值,再删除(解决了误删问题,还是存在锁过期,业务没执行完的问题) + +``` +if(jedis.set(key_resource_id, uni_request_id, "NX", "EX", 100s) == 1){ //加锁 + try { + do something //业务处理 + }catch(){ +  } +  finally { + //判断是不是当前线程加的锁,是才释放 + if (uni_request_id.equals(jedis.get(key_resource_id))) { + jedis.del(lockKey); //释放锁 + } + } +} +``` + +在这里,判断是不是当前线程加的锁和释放锁不是一个原子操作。如果调用jedis.del()释放锁的时候,可能这把锁已经不属于当前客户端,会解除他人加的锁。 + + +![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/88518412ca20489cbd38498d883639db~tplv-k3u1fbpfcp-watermark.image) + + +一般也是用lua脚本代替。lua脚本如下: + +``` +if redis.call('get',KEYS[1]) == ARGV[1] then + return redis.call('del',KEYS[1]) +else + return 0 +end; +``` + + +#### 3.1.5 Redisson框架 + Redlock算法 解决锁过期释放,业务没执行完问题+单机问题 + +Redisson 使用了一个```Watch dog```解决了锁过期释放,业务没执行完问题,Redisson原理图如下: +![image.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a80964e2ed1d4e739dc2a62ac73110da~tplv-k3u1fbpfcp-watermark.image) + +以上的分布式锁,还存在单机问题: +![image.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3b9e6b6050874be98f6a256291552459~tplv-k3u1fbpfcp-watermark.image) +> 如果线程一在Redis的master节点上拿到了锁,但是加锁的key还没同步到slave节点。恰好这时,master节点发生故障,一个slave节点就会升级为master节点。线程二就可以获取同个key的锁啦,但线程一也已经拿到锁了,锁的安全性就没了。 + +针对单机问题,可以使用Redlock算法。有兴趣的朋友可以看下我这篇文章哈,[七种方案!探讨Redis分布式锁的正确使用姿势](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488142&idx=1&sn=79a304efae7a814b6f71bbbc53810c0c&chksm=cf21cda7f85644b11ff80323defb90193bc1780b45c1c6081f00da85d665fd9eb32cc934b5cf&token=1120875912&lang=zh_CN#rd) + +### 3.2 缓存一致性注意点 + +- 如果是读请求,先读缓存,后读数据库 +- 如果写请求,先更新数据库,再写缓存 +- 每次更新数据后,需要清除缓存 +- 缓存一般都需要设置一定的过期失效 +- 一致性要求高的话,可以使用biglog+MQ保证。 + +有兴趣的朋友,可以看下我这篇文章哈:[并发环境下,先操作数据库还是先操作缓存?](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488079&idx=1&sn=49255f6c0c540deeb3333bcf86d6c77c&chksm=cf21cd66f856447061b5eca47f51199e120a9eaa83fa7546b4bd2667218403ccc97e726ab456&token=1120875912&lang=zh_CN#rd) + +### 3.3 合理评估Redis容量,避免由于频繁set覆盖,导致之前设置的过期时间无效。 + +我们知道,Redis的所有数据结构类型,都是可以设置过期时间的。假设一个字符串,已经设置了过期时间,你再去重新设置它,就会导致之前的过期时间无效。 + +![image.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/29a81b1775e044e2b1198dff2e3b1ca1~tplv-k3u1fbpfcp-watermark.image) + +Redis ```setKey```源码如下: +``` +void setKey(redisDb *db,robj *key,robj *val) { + if(lookupKeyWrite(db,key)==NULL) { + dbAdd(db,key,val); + }else{ + dbOverwrite(db,key,val); + } + incrRefCount(val); + removeExpire(db,key); //去掉过期时间 + signalModifiedKey(db,key); +} +``` + +实际业务开发中,同时我们要合理评估Redis的容量,避免频繁set覆盖,导致设置了过期时间的key失效。新手小白容易犯这个错误。 + +### 3.4 缓存穿透问题 + +先来看一个常见的缓存使用方式:读请求来了,先查下缓存,缓存有值命中,就直接返回;缓存没命中,就去查数据库,然后把数据库的值更新到缓存,再返回。 + + +![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/59c69359b2c249ad8954b7da7c0e6fb8~tplv-k3u1fbpfcp-watermark.image) + +**缓存穿透**:指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,进而给数据库带来压力。 + +> 通俗点说,读请求访问时,缓存和数据库都没有某个值,这样就会导致每次对这个值的查询请求都会穿透到数据库,这就是缓存穿透。 + +缓存穿透一般都是这几种情况产生的: + +- **业务不合理的设计**,比如大多数用户都没开守护,但是你的每个请求都去缓存,查询某个userid查询有没有守护。 +- **业务/运维/开发失误的操作**,比如缓存和数据库的数据都被误删除了。 +- **黑客非法请求攻击**,比如黑客故意捏造大量非法请求,以读取不存在的业务数据。 + +**如何避免缓存穿透呢?** 一般有三种方法。 + +- 1. 如果是非法请求,我们在API入口,对参数进行校验,过滤非法值。 +- 2. 如果查询数据库为空,我们可以给缓存设置个空值,或者默认值。但是如有有写请求进来的话,需要更新缓存哈,以保证缓存一致性,同时,最后给缓存设置适当的过期时间。(业务上比较常用,简单有效) +- 3. 使用布隆过滤器快速判断数据是否存在。即一个查询请求过来时,先通过布隆过滤器判断值是否存在,存在才继续往下查。 +> 布隆过滤器原理:它由初始值为0的位图数组和N个哈希函数组成。一个对一个key进行N个hash算法获取N个值,在比特数组中将这N个值散列后设定为1,然后查的时候如果特定的这几个位置都为1,那么布隆过滤器判断该key存在。 + + +### 3.5 缓存雪奔问题 + +**缓存雪奔:** 指缓存中数据大批量到过期时间,而查询数据量巨大,请求都直接访问数据库,引起数据库压力过大甚至down机。 + +- 缓存雪奔一般是由于大量数据同时过期造成的,对于这个原因,可通过均匀设置过期时间解决,即让过期时间相对离散一点。如采用一个较大固定值+一个较小的随机值,5小时+0到1800秒酱紫。 +- Redis 故障宕机也可能引起缓存雪奔。这就需要构造Redis高可用集群啦。 + + +### 3.6 缓存击穿问题 + +**缓存击穿:** 指热点key在某个时间点过期的时候,而恰好在这个时间点对这个Key有大量的并发请求过来,从而大量的请求打到db。 + +缓存击穿看着有点像,其实它两区别是,缓存雪奔是指数据库压力过大甚至down机,缓存击穿只是大量并发请求到了DB数据库层面。可以认为击穿是缓存雪奔的一个子集吧。有些文章认为它俩区别,是区别在于击穿针对某一热点key缓存,雪奔则是很多key。 + +解决方案就有两种: + +- **1.使用互斥锁方案**。缓存失效时,不是立即去加载db数据,而是先使用某些带成功返回的原子操作命令,如(Redis的setnx)去操作,成功的时候,再去加载db数据库数据和设置缓存。否则就去重试获取缓存。 +- **2. “永不过期”**,是指没有设置过期时间,但是热点数据快要过期时,异步线程去更新和设置过期时间。 + +### 3.7、缓存热key问题 + +在Redis中,我们把访问频率高的key,称为热点key。如果某一热点key的请求到服务器主机时,由于请求量特别大,可能会导致主机资源不足,甚至宕机,从而影响正常的服务。 + +而热点Key是怎么产生的呢?主要原因有两个: +> - 用户消费的数据远大于生产的数据,如秒杀、热点新闻等读多写少的场景。 +> - 请求分片集中,超过单Redi服务器的性能,比如固定名称key,Hash落入同一台服务器,瞬间访问量极大,超过机器瓶颈,产生热点Key问题。 + +那么在日常开发中,如何识别到热点key呢? +> - 凭经验判断哪些是热Key; +> - 客户端统计上报; +> - 服务代理层上报 + +如何解决热key问题? + +> - Redis集群扩容:增加分片副本,均衡读流量; +> - 对热key进行hash散列,比如将一个key备份为key1,key2……keyN,同样的数据N个备份,N个备份分布到不同分片,访问时可随机访问N个备份中的一个,进一步分担读流量; +> - 使用二级缓存,即JVM本地缓存,减少Redis的读请求。 + +## 4. Redis配置运维 + +### 4.1 使用长连接而不是短连接,并且合理配置客户端的连接池 + +- 如果使用短连接,每次都需要过 TCP 三次握手、四次挥手,会增加耗时。然而长连接的话,它建立一次连接,redis的命令就能一直使用,酱紫可以减少建立redis连接时间。 +- 连接池可以实现在客户端建立多个连接并且不释放,需要使用连接的时候,不用每次都创建连接,节省了耗时。但是需要合理设置参数,长时间不操作 Redis时,也需及时释放连接资源。 + +### 4.2 只使用 db0 + +Redis-standalone架构禁止使用非db0.原因有两个 + +- 一个连接,Redis执行命令select 0和select 1切换,会损耗新能。 +- Redis Cluster 只支持 db0,要迁移的话,成本高 + +### 4.3 设置maxmemory + 恰当的淘汰策略。 + +为了防止内存积压膨胀。比如有些时候,业务量大起来了,redis的key被大量使用,内存直接不够了,运维小哥哥也忘记加大内存了。难道redis直接这样挂掉?所以需要根据实际业务,选好maxmemory-policy(最大内存淘汰策略),设置好过期时间。一共有8种内存淘汰策略: + + - volatile-lru:当内存不足以容纳新写入数据时,从设置了过期时间的key中使用LRU(最近最少使用)算法进行淘汰; +- allkeys-lru:当内存不足以容纳新写入数据时,从所有key中使用LRU(最近最少使用)算法进行淘汰。 +- volatile-lfu:4.0版本新增,当内存不足以容纳新写入数据时,在过期的key中,使用LFU算法进行删除key。 +- allkeys-lfu:4.0版本新增,当内存不足以容纳新写入数据时,从所有key中使用LFU算法进行淘汰; +- volatile-random:当内存不足以容纳新写入数据时,从设置了过期时间的key中,随机淘汰数据;。 +- allkeys-random:当内存不足以容纳新写入数据时,从所有key中随机淘汰数据。 +- volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的key中,根据过期时间进行淘汰,越早过期的优先被淘汰; +- noeviction:默认策略,当内存不足以容纳新写入数据时,新写入操作会报错。 + +### 4.4 开启 lazy-free 机制 + +Redis4.0+版本支持lazy-free机制,如果你的Redis还是有bigKey这种玩意存在,建议把lazy-free开启。当开启它后,Redis 如果删除一个 bigkey 时,释放内存的耗时操作,会放到后台线程去执行,减少对主线程的阻塞影响。 + +![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6f6c5e7c58fa488ea0540f671c08081b~tplv-k3u1fbpfcp-watermark.image) + +### 参考与感谢 + +- [Redis 千万不要乱用KEYS命令,不然会挨打的](https://www.cnblogs.com/tonyY/p/12175032.html) +- [阿里云Redis开发规范](https://developer.aliyun.com/article/531067) +- [Redis 最佳实践指南:7个维度+43条使用规范](https://mp.weixin.qq.com/s/2sUWnpJCvkJ8-7XSGLdesA) +- [Redis的缓存穿透及解决方法——布隆过滤器BloomFilter](https://blog.csdn.net/wx1528159409/article/details/88357728) +- [ Redis 缓存性能实践及总结](https://www.shangmayuan.com/a/d2f178b548a64c25854a9750.html) + From b6c47701db1d56630b83b39eb5d5e396504b3aea Mon Sep 17 00:00:00 2001 From: whx123 <327658337@qq.com> Date: Sun, 20 Jun 2021 09:44:13 +0800 Subject: [PATCH 02/52] =?UTF-8?q?m=E5=87=8F=E5=B0=91bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...345\260\221bug\345\221\242\357\274\237.md" | 663 ++++++++++++++++++ ...260\221bug\345\221\242\357\274\237.md.bak" | 0 2 files changed, 663 insertions(+) create mode 100644 "\345\267\245\344\275\234\346\200\273\347\273\223/\350\201\212\350\201\212\346\227\245\345\270\270\345\274\200\345\217\221\344\270\255\357\274\214\345\246\202\344\275\225\345\207\217\345\260\221bug\345\221\242\357\274\237.md" create mode 100644 "\345\267\245\344\275\234\346\200\273\347\273\223/\350\201\212\350\201\212\346\227\245\345\270\270\345\274\200\345\217\221\344\270\255\357\274\214\345\246\202\344\275\225\345\207\217\345\260\221bug\345\221\242\357\274\237.md.bak" diff --git "a/\345\267\245\344\275\234\346\200\273\347\273\223/\350\201\212\350\201\212\346\227\245\345\270\270\345\274\200\345\217\221\344\270\255\357\274\214\345\246\202\344\275\225\345\207\217\345\260\221bug\345\221\242\357\274\237.md" "b/\345\267\245\344\275\234\346\200\273\347\273\223/\350\201\212\350\201\212\346\227\245\345\270\270\345\274\200\345\217\221\344\270\255\357\274\214\345\246\202\344\275\225\345\207\217\345\260\221bug\345\221\242\357\274\237.md" new file mode 100644 index 0000000..0c47dce --- /dev/null +++ "b/\345\267\245\344\275\234\346\200\273\347\273\223/\350\201\212\350\201\212\346\227\245\345\270\270\345\274\200\345\217\221\344\270\255\357\274\214\345\246\202\344\275\225\345\207\217\345\260\221bug\345\221\242\357\274\237.md" @@ -0,0 +1,663 @@ +## 前言 + +大家好呀~ 我是捡田螺的小男孩,今天跟大家聊聊日常开发中,如何减少bug?本文将从**数据库、代码层面、缓存使用篇**3个大方向,总结出一共60多个注意点,助大家成为开发质量之星。 +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/41bd0d208d054f87a99f6c7df514f35d~tplv-k3u1fbpfcp-zoom-1.image) + +- 欢迎关注公众号:**捡田螺的小男孩** +- [github地址](https://github.com/whx123/JavaHome),感谢每一颗star + +## 1. 数据库篇 + +![慢查询](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a05dccf50dc3403c8c665d3395cdcc91~tplv-k3u1fbpfcp-zoom-1.image) + +数据库篇的话,哪些地方容易导致bug出现呢?我总结了7个方面:**慢查询、数据库字段注意点、事务失效的场景、死锁、主从延迟、新老数据兼容、一些SQL经典注意点**。 + +### 1.1 慢查询 + +![慢查询.gif](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8d38c462aa484b47b9fcfded5f4f2140~tplv-k3u1fbpfcp-watermark.image) + +#### 1.1.1 是否命中索引 +提起慢查询,我们马上就会想到加索引。如果一条SQL没加索引,或者没有命中索引的话,就会产生慢查询。 + +**索引哪些情况会失效?** + +- 查询条件包含or,可能导致索引失效 +- 如何字段类型是字符串,where时一定用引号括起来,否则索引失效 +- like通配符可能导致索引失效。 +- 联合索引,查询时的条件列不是联合索引中的第一个列,索引失效。 +- 在索引列上使用mysql的内置函数,索引失效。 +- 对索引列运算(如,+、-、*、/),索引失效。 +- 索引字段上使用(!= 或者 < >,not in)时,可能会导致索引失效。 +- 索引字段上使用is null, is not null,可能导致索引失效。 +- 左连接查询或者右连接查询查询关联的字段编码格式不一样,可能导致索引失效。 +- mysql估计使用全表扫描要比使用索引快,则不使用索引。 + + +#### 1.1.2 数据量大,考虑分库分表 + +单表数据量太大,就会影响SQL执行性能。我们知道索引数据结构一般是B+树,一棵高度为3的B+树,大概可以存储两千万的数据。超过这个数的话,B+树要变高,查询性能会下降。 + +因此,数据量大的时候,建议分库分表。分库分表的中间件有**mycat、sharding-jdbc** + + +#### 1.1.3 不合理的SQL + +日常开发中,笔者见过很多不合理的SQL:比如一个SQL居然用了**6个表连接**,连表太多会影响查询性能;再比如一个表,居然加了**10个索引**等等。索引是会降低了插入和更新SQL性能,所以索引一般不建议太多,一般不能超过五个。 + + +### 1.2 数据库字段注意点 + +数据库字段这块内容,很容易出bug。比如,你测试环境修改了表结构,加了某个字段,忘记把脚本带到生产环境,那发版肯定有问题了。 + +#### 1.2.1 字段是否会超长 + +假设你的数据库字段是: + +``` +`name` varchar(255) DEFAULT NOT NULL +``` + +如果请求参数来了变量name,字段长度是300,那插入表的时候就**报错**了。所以需要校验参数,防止字段超长。 + +#### 1.2.2 字段为空,是否会导致空指针等 + +我们设计数据库表字段的时候,尽量把字段设置为**not null**。 + +- 如果是整形,我们一般使用0或者-1作为默认值。 +- 如果字符串,默认空字符串 + +如果数据库字段设置为```NULL```值,容易导致程序空指针;如果数据库字段设置为```NULL```值,需要注意**count(具体列)** 的使用,会有坑。 + +#### 1.2.3 字段缺失 + +我们的日常开发任务,如果在测试环境,对表进行修改,比如添加了一个新字段,必须要把SQL脚本带到生产环境,否则字段缺失,发版就有问题啦。 + + +#### 1.2.4 字段类型是否支持表情 + +如果一个表字段需要支持表情存储,使用**utf8mb4**。 + +#### 1.2.5 谨慎使用text、blob字段 + +如果你要用一个字段存储文件,考虑**存储文件的路径**,而不保存整个文件下去。使用text时,涉及查询条件时,注意创建**前缀索引**。 + +### 1.3 事务失效的场景 + +#### 1.3.1 @Transactional 在非public修饰的方法上失效 + + +@Transactional注解,加在非public修饰的方法上,事务是不会生效的。spring事务是借鉴了AOP的思想,也是通过动态代理来实现的。spring事务自己在调用动态代理之前,已经对非public方法过滤了,所以非public方法,事务不生效。 + +#### 1.3.2 本地方法直接调用 +以下这个场景, @Transactional事务也是无效的 +``` +public class TransactionTest{ + public void A(){ + //插入一条数据 + //调用方法B (本地的类调用,事务失效了) + B(); + } + + @Transactional + public void B(){ + //插入数据 + } +} +``` + +#### 1.3.3 异常被try...catch吃了,导致事务失效。 + + +``` +@Transactional +public void method(){ + try{ + //插入一条数据 + insertA(); + //更改一条数据 + updateB(); + }catch(Exception e){ + logger.error("异常被捕获了,那你的事务就失效咯",e); + } +} + +``` + +#### 1.3.4 rollbackFor属性设置错误 + +Spring默认抛出了未检查```unchecked```异常(继承自RuntimeException 的异常)或者Error才回滚事务;其他异常不会触发回滚事务。如果在事务中抛出其他类型的异常,就需要指定```rollbackFor```属性。 + +#### 1.3.5 底层数据库引擎不支持事务 + +MyISAM存储引擎不支持事务,InnoDb就支持事务 + +#### 1.3.6 spring事务和业务逻辑代码必须在一个线程中 + +业务代码要和spring事务的源码在同一个线程中,才会受spring事务的控制。比如下面代码,方法mothed的子线程,内部执行的事务操作,将不受mothed方法上spring事务的控制,这一点大家要注意。这是因为spring事务实现中使用了ThreadLocal,实现同一个线程中数据共享。 + +``` +@Transactional +public void mothed() { + new Thread() { + 事务操作 + }.start(); +} +``` + + +### 1.4 死锁 + +死锁是指两个或多个事务在同一资源上相互占用,并请求锁定对方的资源,从而导致恶性循环的现象。 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3513a3fd3ef64e318f157dd51ec280ef~tplv-k3u1fbpfcp-zoom-1.image) + + +MySQL内部有一套死锁检测机制,一旦发生死锁会立即回滚一个事务,让另一个事务执行下去。但死锁有**资源的利用率降低、进程得不到正确结果**等危害。 + +#### 1.4.1 9种情况的SQL加锁分析 + +要避免死锁,需要学会分析:一条SQL的加锁是如何进行的?一条SQL加锁,可以分9种情况进行探讨: + +- 组合一:id列是主键,RC隔离级别 +- 组合二:id列是二级唯一索引,RC隔离级别 +- 组合三:id列是二级非唯一索引,RC隔离级别 +- 组合四:id列上没有索引,RC隔离级别 +- 组合五:id列是主键,RR隔离级别 +- 组合六:id列是二级唯一索引,RR隔离级别 +- 组合七:id列是二级非唯一索引,RR隔离级别 +- 组合八:id列上没有索引,RR隔离级别 +- 组合九:Serializable隔离级别 + + +#### 1.4.2 如何分析解决死锁? + +分析解决死锁的步骤如下: + +- 模拟死锁场景 +- show engine innodb status;查看死锁日志 +- 找出死锁SQL +- SQL加锁分析,这个可以去官网看哈 +- 分析死锁日志(持有什么锁,等待什么锁) +- 熟悉锁模式兼容矩阵,InnoDB存储引擎中锁的兼容性矩阵。 + +有兴趣的小伙伴,可以看下我之前写的这篇文章:[手把手教你分析Mysql死锁问题](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487979&idx=1&sn=588c83d77a8851f3b3c18cd68ed9c454&chksm=cf21cec2f85647d4a77cc239ae9a4cfd31bb8832be3d98540a08ea8b4a1f46b38cf736210a02&token=1327808550&lang=zh_CN#rd) + + +### 1.5 主从延迟问题考虑 + +先插入,接着就去查询,这类代码逻辑比较常见,这可能会有问题的。一般数据库都是有主库,从库的。写入的话是写主库,读一般是读从库。如果发生主从延迟,,很可能出现你插入成功了,但是你查询不到的情况。 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/560555c31cfe42a0b07dd9bcad24c0e1~tplv-k3u1fbpfcp-zoom-1.image) + + +#### 1.5.1 要求强一致性,考虑读主库 + +如果是重要业务,要求强一致性,考虑直接读主库 + +#### 1.5.2 不要求强一致性,读从库 + +如果是一般业务,可以接受短暂的数据不一致的话,优先考虑读从库。因为从库可以分担主库的读写压力,提高系统性能。 + +### 1.6 新老数据兼容 + +#### 1.6.1 新加的字段,考虑存量数据的默认值 + +我们日常开发中,随着业务需求变更,经常需要给某个数据库表添加个字段。比如在某个APP配置表,需要添加个场景号字段,如```scene_type```,它的枚举值是 ```01、02、03```,那我们就要跟业务对齐,新添加的字段,老数据是什么默认值,是为空还是默认01,如果是为```NULL```的话,程序代码就要做好空指针处理。 + +#### 1.6.2 如果新业务用老的字段,考虑老数据的值是否有坑 + +如果我们开发中,需要沿用数据库表的老字段,并且有存量数据,那就需要考虑老存量数据库的值是否有坑。比如我们表有个user_role_code 的字段,老的数据中,它枚举值是 ``` 01:超级管理员 02:管理员 03:一般用户```。假设业务需求是**一般用户**拆分为**03查询用户和04操作用户**,那我们在开发中,就要考虑老数据的问题啦。 + +### 1.7 一些SQL的经典注意点 + +#### 1.7.1 limit大分页问题 + +limit大分页是一个非常经典的SQL问题,我们一般有这3种对应的解决方案 + +**方案一:** 如果id是连续的,可以这样,返回上次查询的最大记录(偏移量),再往下limit + + +``` +select id,name from employee where id>1000000 limit 10. +``` + +**方案二:** 在业务允许的情况下限制页数: + +建议跟业务讨论,有没有必要查这么后的分页啦。因为绝大多数用户都不会往后翻太多页。谷歌搜索页也是限制了页数,因此不存在limit大分页问题。 + +**方案三:** 利用延迟关联或者子查询优化超多分页场景。(先快速定位需要获取的id段,然后再关联) + +``` +SELECT a.* FROM employee a, (select id from employee where 条件 LIMIT 1000000,10 ) b where a.id=b.id +``` + +#### 1.7.2 修改、查询数据量多时,考虑分批进行。 + +我们更新或者查询数据库数据时,尽量避免循环去操作数据库,可以考虑分批进行。比如你要插入10万数据的话,可以一次插入500条 + +**正例:** +``` +remoteBatchQuery(param); +``` +**反例:** + +``` + +for(int i=0;i<100000;i++){ + remoteSingleQuery(param) +} +``` + + +## 2. 代码层面篇 + +![代码层面](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/819c4665e0064db5bb3441c5bee4cb7a~tplv-k3u1fbpfcp-zoom-1.image) + +### 2.1 编码细节 + +![编码细节.gif](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/aaa1fee8efa745d39a2ef869caa55b4f~tplv-k3u1fbpfcp-watermark.image) + +#### 2.1.1 六大典型空指针问题 + +我们编码的时候,需要注意这六种类型的空指针问题 + +- 包装类型的空指针问题 +- 级联调用的空指针问题 +- Equals方法左边的空指针问题 +- ConcurrentHashMap 类似容器不支持 k-v为 null。 +- 集合,数组直接获取元素 +- 对象直接获取属性 + + +``` +if(object!=null){ + String name = object.getName(); +} +``` + +#### 2.1.2 线程池使用注意点 + +- 使用 Executors.newFixedThreadPool,可能会出现OOM问题,因为它使用的是无界阻塞队列 +- 建议使用自定义的线程池,最好给线程池一个清晰的命名,方便排查问题 +- 不同的业务,最好做线程池隔离,避免所有的业务公用一个线程池。 +- 线程池异常处理要考虑好 + +#### 2.1.3 线性安全的集合、类 + +在高并发场景下,```HashMap```可能会出现死循环。因为它是非线性安全的,可以考虑使用```ConcurrentHashMap```。所以我们使用这些集合的时候,需要注意是不是线性安全的。 + +- Hashmap、Arraylist、LinkedList、TreeMap等都是线性不安全的; +- Vector、Hashtable、ConcurrentHashMap等都是线性安全的 + +#### 2.1.4 日期格式,金额处理精度等 + +日常开发,经常需要对日期格式化,但是呢,年份设置为YYYY大写的时候,是有坑的哦。 + + +``` +Calendar calendar = Calendar.getInstance(); +calendar.set(2019, Calendar.DECEMBER, 31); + +Date testDate = calendar.getTime(); + +SimpleDateFormat dtf = new SimpleDateFormat("YYYY-MM-dd"); +System.out.println("2019-12-31 转 YYYY-MM-dd 格式后 " + dtf.format(testDate)); +``` +运行结果: + +``` +2019-12-31 转 YYYY-MM-dd 格式后 2020-12-31 +``` + +还有金额计算也比较常见,我们要注意精度问题: + + +``` +public class DoubleTest { + public static void main(String[] args) { + System.out.println(0.1+0.2); + System.out.println(1.0-0.8); + System.out.println(4.015*100); + System.out.println(123.3/100); + + double amount1 = 3.15; + double amount2 = 2.10; + if (amount1 - amount2 == 1.05){ + System.out.println("OK"); + } + } +} + +``` +运行结果: + + +``` +0.30000000000000004 +0.19999999999999996 +401.49999999999994 +1.2329999999999999 +``` + + + +#### 2.1.5 大文件处理 + + +读取大文件的时候,不要```Files.readAllBytes```直接读到内存,会OOM的,建议使用```BufferedReader ```一行一行来,或者使用```NIO``` + + +#### 2.1.6 使用完IO资源流,需要关闭 + + +使用try-with-resource,读写完文件,需要关闭流 + +``` +/* + * 关注公众号,捡田螺的小男孩 + */ +try (FileInputStream inputStream = new FileInputStream(new File("jay.txt")) { + // use resources +} catch (FileNotFoundException e) { + log.error(e); +} catch (IOException e) { + log.error(e); +} +``` + + +#### 2.1.7 try...catch异常使用的一些坑 + +- 尽量不要使用e.printStackTrace()打印,可能导致字符串常量池内存空间占满 +- catch了异常,使用log把它打印出来 +- 不要用一个Exception捕捉所有可能的异常 +- 不要把捕获异常当做业务逻辑来处理 + + +#### 2.1.8 先查询,再更新/删除的并发一致性 + + +日常开发中,这种代码实现经常可见:先查询是否有剩余可用的票,再去更新票余量。 + + +``` +if(selectIsAvailable(ticketId){ + 1、deleteTicketById(ticketId) + 2、给现金增加操作 +}else{ + return “没有可用现金券” +} +``` + +如果是并发执行,很可能有问题的,应该利用数据库更新/删除的原子性,正解如下: + +``` +if(deleteAvailableTicketById(ticketId) == 1){ + 1、给现金增加操作 +}else{ + return “没有可用现金券” +} +``` + + +### 2.2 提供对外接口 + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/818d79dfadab43e5a2bddf26a3ea2870~tplv-k3u1fbpfcp-zoom-1.image) + + +#### 2.2.1 校验参数合法性 + +我们提供对外的接口,不管是提供给客户端、还是前端,又或是别的系统调用,都需要校验一下入参的合法性。 + +> 如果你的数据库字段设置为varchar(16),对方传了一个32位的字符串过来,你不校验参数长度,插入数据库直接异常了。 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4f4649f1bb3b43418ef808b8c5599c76~tplv-k3u1fbpfcp-watermark.image) + +#### 2.2.2 新老接口兼容 + +很多bug都是因为修改了对外老接口,但是却不做兼容导致的。关键这个问题多数是比较严重的,可能直接导致系统发版失败的。新手程序员很容易犯这个错误哦~ + +比如我们有个dubbo的分布式接口,本次你修改了入参,就需要考虑新老接口兼容。原本是只接收A,B参数,现在你加了一个参数C,就可以考虑这样处理。 + + +``` +//老接口 +void oldService(A,B){ + //兼容新接口,传个null代替C + newService(A,B,null); +} + +//新接口,暂时不能删掉老接口,需要做兼容。 +void newService(A,B,C); +``` + + + +#### 2.2.3 限流,防止大流量压垮系统 + +如果瞬间的大流量请求过来,容易压垮系统。所以为了保护我们的系统,一般要做限流处理。可以使用**guava ratelimiter** 组件做限流,也可以用阿里开源的**Sentinel** + +#### 2.2.4 接口安全性,加签验签,鉴权 + + +我们转账等类型的接口,一定要注意安全性。一定要鉴权,**加签验签**,为用户交易保驾护航。 + + +#### 2.2.5 考虑接口幂等性 + +接口是需要考虑幂等性的,尤其抢红包、转账这些重要接口。最直观的业务场景,就是**用户连着点击两次**,你的接口有没有hold住。 + +> 1. 幂等(idempotent、idempotence)是一个数学与计算机学概念,常见于抽象代数中。 +> 2. 在编程中.一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。 + + +一般「幂等技术方案」有这几种: + +1. 查询操作 +2. 唯一索引 +3. token机制,防止重复提交 +4. 数据库的delete删除操作 +5. 乐观锁 +6. 悲观锁 +7. Redis、zookeeper 分布式锁(以前抢红包需求,用了Redis分布式锁) +8. 状态机幂等 + +![接口幂等性.gif](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/55e09e293249431a85d68f8b217d9a8d~tplv-k3u1fbpfcp-watermark.image) + +### 2.3 调用第三方接口 + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/41e0a0d34083431ca0d44f3354dca2f5~tplv-k3u1fbpfcp-zoom-1.image) + +#### 2.3.1 超时处理 + +我们调用别人的接口,如果超时了怎么办呢? + +> 举个例子,我们调用一个远程转账接口,A客户给B客户转100万,成功的时候就把本地转账流水置为成功,失败的时候就把本地流水置为失败。如果调用转账系统超时了呢,我们怎么处理呢?置为成功还是失败呢?这个**超时处理可要考虑好**,要不然就资金损失了。这种场景下,调接口超时,我们就可以先**不更新本地转账流水**状态,而是重新发起查询远程转账请求,查询到转账成功的记录,再更新本地状态状态 + + + +#### 2.3.2 考虑重试机制 + +如果我们调用一个远程http或者dubbo接口,调用失败了,我们可以考虑引入重试机制。有时候网路抖动一下,接口就调失败了,引入重试机制可以提高用户体验。但是这个重试机制需要评估次数,或者有些接口不支持幂等,就不适合重试的。 + +#### 2.3.3 考虑是否降级处理 + + +假设我们系统是一个提供注册的服务:用户注册成功之后,调远程A接口发短信,调远程B接口发邮件,最后更新注册状态为成功。 + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d2a2180e624d4f8fadcf8fc8f63651bf~tplv-k3u1fbpfcp-zoom-1.image) + + +如果调用接口B发邮件失败,那用户就注册失败,业务可能就不会同意了。这时候我们可以考虑给B接口**降级处理**,提供**有损服务**。也就是说,如果调用B接口失败,那先不发邮件,而是先让用户注册成功,后面搞个定时补发邮件就好啦。 + +#### 2.3.4 考虑是否异步处理 + +我还是使用上个小节的**用户注册**的例子。我们可以开个异步线程去调A接口发短信,异步调B接口发邮件,那即使A或者B接口调失败,我们还是可以保证用户先注册成功。 + +把发短信这些通知类接口,放到异步线程处理,可以降低接口耗时,提升用户体验哦。 + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/07eef178cfe04048ade9fbed2f465d12~tplv-k3u1fbpfcp-zoom-1.image) + + + +#### 2.3.5 调接口异常处理 + +如果我们调用一个远程接口,一般需要思考以下:如果别人接口异常,我们要怎么处理,怎么兜底,是重试还是当做失败?怎么保证数据的最终一致性等等。 + + +## 3. 缓存篇 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f84d96671e8e451d936e110a53bf9cf6~tplv-k3u1fbpfcp-zoom-1.image) + +### 3.1 数据库与缓存一致性 + +使用缓存,可以降低耗时,提供系统吞吐性能。但是,使用缓存,会存在数据一致性的问题。 + +#### 3.1.1 几种缓存使用模式 + +- Cache-Aside Pattern,旁路缓存模式 +- Read-Through/Write-Through(读写穿透) +- Write- behind (异步缓存写入) + +一般我们使用缓存,都是**旁路缓存模式**,读请求流程如下: + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/38f7efc4d066409dbf65a56eb10eb90e~tplv-k3u1fbpfcp-zoom-1.image) + + +- 读的时候,先读缓存,缓存命中的话,直接返回数据 +- 缓存没有命中的话,就去读数据库,从数据库取出数据,放入缓存后,同时返回响应。 + +旁路缓存模式的写流程: +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c80f0df22739439088d6a47ced7b6ae0~tplv-k3u1fbpfcp-zoom-1.image) + + +#### 3.1.2 删除缓存呢,还是更新缓存? + +我们在操作缓存的时候,到底应该删除缓存还是更新缓存呢?我们先来看个例子: + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b0a52a30ec994ca7b66cf83fba5398a2~tplv-k3u1fbpfcp-zoom-1.image) + + +1. 线程A先发起一个写操作,第一步先更新数据库 +2. 线程B再发起一个写操作,第二步更新了数据库 +3. 由于网络等原因,线程B先更新了缓存 +4. 线程A更新缓存。 + +这时候,缓存保存的是A的数据(老数据),数据库保存的是B的数据(新数据),数据不一致了,脏数据出现啦。如果是删除缓存取代更新缓存则不会出现这个脏数据问题。 + + +#### 3.1.3 先操作数据库还是先操作缓存 + +双写的情况下,先操作数据库还是先操作缓存?我们再来看一个例子:假设有A、B两个请求,请求A做更新操作,请求B做查询读取操作。 + +![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/95b0b2cd05d34ff1b66a8aa0a768cc04~tplv-k3u1fbpfcp-watermark.image) + +1. 线程A发起一个写操作,第一步del cache +2. 此时线程B发起一个读操作,cache miss +3. 线程B继续读DB,读出来一个老数据 +4. 然后线程B把老数据设置入cache +5. 线程A写入DB最新的数据 + +酱紫就有问题啦,缓存和数据库的数据不一致了。缓存保存的是老数据,数据库保存的是新数据。因此,Cache-Aside缓存模式,选择了先操作数据库而不是先操作缓存。 + + +#### 3.1.4 如何保证最终一致性 + +- 缓存延时双删 +- 删除缓存重试机制 +- 读取biglog异步删除缓存 + + + +### 3.2 缓存穿透 + +> 缓存穿透:指查询一个一定不存在的数据,由于缓存不命中时,需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,进而给数据库带来压力。 + +缓存穿透一般都是这几种情况产生的:**业务不合理的设计、业务/运维/开发失误的操作、黑客非法请求攻击**。 +如何避免缓存穿透呢? 一般有三种方法。 + +- 如果是非法请求,我们在API入口,**对参数进行校验**,过滤非法值。 +- 如果查询数据库为空,我们可以**给缓存设置个空值,或者默认值**。但是如有有写请求进来的话,需要更新缓存哈,以保证缓存一致性,同时,最后给缓存设置适当的过期时间。(业务上比较常用,简单有效) +- 使用**布隆过滤器**快速判断数据是否存在。即一个查询请求过来时,先通过布隆过滤器判断值是否存在,存在才继续往下查。 + +### 3.3 缓存雪崩 + +> 缓存雪崩:指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。 + +- 缓存雪奔一般是由于大量数据同时过期造成的,对于这个原因,可通过**均匀设置过期时间解决,即让过期时间相对离散一点**。如采用一个较大固定值+一个较小的随机值,5小时+0到1800秒酱紫。 +- **Redis 故障宕机也可能引起缓存雪奔**。这就需要构造Redis高可用集群啦。 + + +### 3.4 缓存机击穿 + +> 缓存击穿: 指热点key在某个时间点过期的时候,而恰好在这个时间点对这个Key有大量的并发请求过来,从而大量的请求打到db。 + +缓存击穿看着有点像缓存雪崩,其实它两区别是,缓存雪奔是指数据库压力过大甚至down机,缓存击穿只是大量并发请求到了DB数据库层面。可以认为击穿是缓存雪奔的一个子集吧。有些文章认为它俩区别,是在于击穿针对某一热点key缓存,雪奔则是很多key。 + + +解决方案就有两种: + +1. **使用互斥锁方案**。缓存失效时,不是立即去加载db数据,而是先使用某些带成功返回的原子操作命令,如(Redis的setnx)去操作,成功的时候,再去加载db数据库数据和设置缓存。否则就去重试获取缓存。 +2. **“永不过期”**,是指没有设置过期时间,但是热点数据快要过期时,异步线程去更新和设置过期时间。 + + +### 3.5 缓存热Key + +在Redis中,我们把访问频率高的key,称为热点key。如果某一热点key的请求到服务器主机时,由于请求量特别大,可能会导致主机资源不足,甚至宕机,从而影响正常的服务。 + +如何解决热key问题? + +- **Redis集群扩容**:增加分片副本,均衡读流量; +- **对热key进行hash散列**,比如将一个key备份为key1,key2……keyN,同样的数据N个备份,N个备份分布到不同分片,访问时可随机访问N个备份中的一个,进一步分担读流量; +- **使用二级缓存**,即JVM本地缓存,减少Redis的读请求。 + +### 3.6 缓存容量内存考虑 + +#### 3.6.1 评估容量,合理利用 + +如果我们使用的是Redis,而Redis的内存是比较昂贵的,我们不要什么数据都往Redis里面塞,一般Redis只缓存查询比较频繁的数据。同时,我们要合理评估Redis的容量,也避免频繁set覆盖,导致设置了过期时间的key失效。 + +如果我们使用的是本地缓存,如guava的本地缓存,也要评估下容量。避免容量不够。 + + +#### 3.6.2 Redis的八种内存淘汰机制 + +为了避免Redis内存不够用,Redis用8种内存淘汰策略保护自己~ + +> - volatile-lru:当内存不足以容纳新写入数据时,从设置了过期时间的key中使用LRU(最近最少使用)算法进行淘汰; +> - allkeys-lru:当内存不足以容纳新写入数据时,从所有key中使用LRU(最近最少使用)算法进行淘汰。 +> - volatile-lfu:4.0版本新增,当内存不足以容纳新写入数据时,在过期的key中,使用LFU算法进行删除key。 +> - allkeys-lfu:4.0版本新增,当内存不足以容纳新写入数据时,从所有key中使用LFU算法进行淘汰; +> - volatile-random:当内存不足以容纳新写入数据时,从设置了过期时间的key中,随机淘汰数据;。 +> - allkeys-random:当内存不足以容纳新写入数据时,从所有key中随机淘汰数据。 +> - volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的key中,根据过期时间进行淘汰,越早过期的优先被淘汰; +> - noeviction:默认策略,当内存不足以容纳新写入数据时,新写入操作会报错。 + +#### 3.6.3 不同的业务场景,Redis选择适合的数据结构 + +- 排行榜适合用zset +- 缓存用户信息一般用hash +- 消息队列,文章列表适用用list +- 用户标签、社交需求一般用set +- 计数器、分布式锁等一般用String类型 + +### 3.7 Redis一些有坑的命令 + +1. 不能使用 keys指令 +2. 慎用O(n)复杂度命令,如hgetall等 +3. 慎用Redis的monitor命令 +4. 禁止使用flushall、flushdb +5. 注意使用del命令 + +## 最后 + +本文总结了60多个减少bug的编码注意点,都是日常开发经典的范例,希望对大家有帮助哈。另外, +关注公众号:**捡田螺的小男孩**,回复**思维导图**,可以**领取本文的高清思维导图**。 + + diff --git "a/\345\267\245\344\275\234\346\200\273\347\273\223/\350\201\212\350\201\212\346\227\245\345\270\270\345\274\200\345\217\221\344\270\255\357\274\214\345\246\202\344\275\225\345\207\217\345\260\221bug\345\221\242\357\274\237.md.bak" "b/\345\267\245\344\275\234\346\200\273\347\273\223/\350\201\212\350\201\212\346\227\245\345\270\270\345\274\200\345\217\221\344\270\255\357\274\214\345\246\202\344\275\225\345\207\217\345\260\221bug\345\221\242\357\274\237.md.bak" new file mode 100644 index 0000000..e69de29 From 33784b8a311b182ef7ed2c7e3daf01f66be7de14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Sun, 11 Jul 2021 21:09:56 +0800 Subject: [PATCH 03/52] Add files via upload --- ...\350\256\25615\350\277\236\351\227\256.md" | 395 ++++++++++++++++++ 1 file changed, 395 insertions(+) create mode 100644 "Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/TCP\345\215\217\350\256\25615\350\277\236\351\227\256.md" diff --git "a/Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/TCP\345\215\217\350\256\25615\350\277\236\351\227\256.md" "b/Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/TCP\345\215\217\350\256\25615\350\277\236\351\227\256.md" new file mode 100644 index 0000000..eae7eec --- /dev/null +++ "b/Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/TCP\345\215\217\350\256\25615\350\277\236\351\227\256.md" @@ -0,0 +1,395 @@ +### 鍓嶈█ + +TCP鍗忚鏄ぇ鍘傞潰璇曞繀闂殑鐭ヨ瘑鐐广傛暣鐞嗕簡15閬撻潪甯哥粡鍏哥殑TCP闈㈣瘯棰橈紝甯屾湜澶у閮芥壘鍒扮悊鎯崇殑offer鍛 + + +![](https://files.mdnice.com/user/3535/47429a24-7e0b-4bf6-8200-7e2ec1baad63.png) + + +- 鍏紬鍙凤細**鎹$敯铻虹殑灏忕敺瀛** + +### 1. 璁蹭笅TCP涓夋鎻℃墜娴佺▼ + +![](https://files.mdnice.com/user/3535/43f4b02a-ad18-45e5-8d6e-52349cc371d6.png) + +寮濮嬪鎴风鍜屾湇鍔″櫒閮藉浜嶤LOSED鐘舵侊紝鐒跺悗鏈嶅姟绔紑濮嬬洃鍚煇涓鍙o紝杩涘叆LISTEN鐘舵 + +- 绗竴娆℃彙鎵(SYN=1, seq=x)锛屽彂閫佸畬姣曞悗锛屽鎴风杩涘叆 SYN_SEND 鐘舵 +- 绗簩娆℃彙鎵(SYN=1, ACK=1, seq=y, ACKnum=x+1)锛 鍙戦佸畬姣曞悗锛屾湇鍔″櫒绔繘鍏 SYN_RCVD 鐘舵併 +- 绗笁娆℃彙鎵(ACK=1锛孉CKnum=y+1)锛屽彂閫佸畬姣曞悗锛屽鎴风杩涘叆 ESTABLISHED 鐘舵侊紝褰撴湇鍔″櫒绔帴鏀跺埌杩欎釜鍖呮椂,涔熻繘鍏 ESTABLISHED 鐘舵侊紝TCP 鎻℃墜锛屽嵆鍙互寮濮嬫暟鎹紶杈撱 + +### 2.TCP鎻℃墜涓轰粈涔堟槸涓夋锛屼笉鑳芥槸涓ゆ锛熶笉鑳芥槸鍥涙锛 + +TCP鎻℃墜涓轰粈涔堟槸涓夋鍛紵涓轰簡鏂逛究鐞嗚В锛屾垜浠互璋堟亱鐖变负渚嬪瓙锛氫袱涓汉鑳借蛋鍒颁竴璧凤紝鏈閲嶈鐨勪簨鎯呭氨鏄浉鐖憋紝灏辨槸**鎴戠埍浣狅紝骞朵笖鎴戠煡閬擄紝浣犱篃鐖辨垜**锛屾帴涓嬫潵鎴戜滑浠ユ鏉ユā鎷熶笁娆℃彙鎵嬬殑杩囩▼锛 + + +![](https://files.mdnice.com/user/3535/374acab7-d609-4c7b-9db6-6a40dbe42926.png) + + +**涓轰粈涔堟彙鎵嬩笉鑳芥槸涓ゆ鍛紵** + +濡傛灉鍙湁涓ゆ鎻℃墜锛屽コ瀛╁瓙鍙兘灏变笉鐭ラ亾锛屽ス鐨勯偅鍙**鎴戜篃鐖变綘**锛岀敺瀛╁瓙鏄惁**鏀跺埌**锛屾亱鐖卞叧绯诲氨涓嶈兘鎰夊揩灞曞紑銆 + +**涓轰粈涔堟彙鎵嬩笉鑳芥槸鍥涙鍛紵** + +鍥犱负鎻℃墜涓嶈兘鏄洓娆″憿锛熷洜涓轰笁娆″凡缁忓浜嗭紝涓夋宸茬粡鑳借鍙屾柟閮界煡閬擄細浣犵埍鎴戯紝鎴戜篃鐖变綘銆傝屽洓娆″氨澶氫綑浜嗐 + +### 3. 璁蹭笅TCP鍥涙鎸ユ墜杩囩▼ + +![](https://files.mdnice.com/user/3535/439e735c-c443-4b2f-96b1-b750004d8d05.png) + +1. 绗竴娆℃尌鎵(FIN=1锛宻eq=u)锛屽彂閫佸畬姣曞悗锛屽鎴风杩涘叆FIN_WAIT_1 鐘舵 +2. 绗簩娆℃尌鎵(ACK=1锛宎ck=u+1,seq =v)锛屽彂閫佸畬姣曞悗锛屾湇鍔″櫒绔繘鍏LOSE_WAIT 鐘舵侊紝瀹㈡埛绔帴鏀跺埌杩欎釜纭鍖呬箣鍚庯紝杩涘叆 FIN_WAIT_2 鐘舵 +3. 绗笁娆℃尌鎵(FIN=1锛孉CK1,seq=w,ack=u+1)锛屽彂閫佸畬姣曞悗锛屾湇鍔″櫒绔繘鍏AST_ACK 鐘舵侊紝绛夊緟鏉ヨ嚜瀹㈡埛绔殑鏈鍚庝竴涓狝CK銆 +4. 绗洓娆℃尌鎵(ACK=1锛宻eq=u+1,ack=w+1)锛屽鎴风鎺ユ敹鍒版潵鑷湇鍔″櫒绔殑鍏抽棴璇锋眰锛屽彂閫佷竴涓‘璁ゅ寘锛屽苟杩涘叆 TIME_WAIT鐘舵侊紝**绛夊緟浜嗘煇涓浐瀹氭椂闂达紙涓や釜鏈澶ф鐢熷懡鍛ㄦ湡锛2MSL锛2 Maximum Segment Lifetime锛変箣鍚**锛屾病鏈夋敹鍒版湇鍔″櫒绔殑 ACK 锛岃涓烘湇鍔″櫒绔凡缁忔甯稿叧闂繛鎺ワ紝浜庢槸鑷繁涔熷叧闂繛鎺ワ紝杩涘叆 CLOSED 鐘舵併傛湇鍔″櫒绔帴鏀跺埌杩欎釜纭鍖呬箣鍚庯紝鍏抽棴杩炴帴锛岃繘鍏 CLOSED 鐘舵併 + +### 4. TCP鎸ユ墜涓轰粈涔堥渶瑕佸洓娆″憿锛 + +涓句釜渚嬪瓙鍚! + +> 灏忔槑鍜屽皬绾㈡墦鐢佃瘽鑱婂ぉ锛岄氳瘽宸笉澶氳缁撴潫鏃讹紝灏忕孩璇粹滄垜娌″暐瑕佽鐨勪簡鈥濓紝灏忔槑鍥炵瓟鈥滄垜鐭ラ亾浜嗏濄備絾鏄皬鏄庡彲鑳借繕浼氭湁瑕佽鐨勮瘽锛屽皬绾笉鑳借姹傚皬鏄庤窡鐫鑷繁鐨勮妭濂忕粨鏉熼氳瘽锛屼簬鏄皬鏄庡彲鑳藉張鍙藉徑姝璇翠簡涓閫氾紝鏈鍚庡皬鏄庤鈥滄垜璇村畬浜嗏濓紝灏忕孩鍥炵瓟鈥滅煡閬撲簡鈥濓紝杩欐牱閫氳瘽鎵嶇畻缁撴潫銆 + +![](https://files.mdnice.com/user/3535/966cef0c-1477-4eca-aadf-059219da0198.png) + +### 5. TIME-WAIT 鐘舵佷负浠涔堥渶瑕佺瓑寰 2MSL + +![](https://files.mdnice.com/user/3535/f56000c8-da62-4370-9559-71bf312f6214.png) + +2MSL锛2 Maximum Segment Lifetime锛屽嵆涓や釜鏈澶ф鐢熷懡鍛ㄦ湡 + +> - 1涓 MSL 淇濊瘉鍥涙鎸ユ墜涓富鍔ㄥ叧闂柟鏈鍚庣殑 ACK 鎶ユ枃鑳芥渶缁堝埌杈惧绔 +> - 1涓 MSL 淇濊瘉瀵圭娌℃湁鏀跺埌 ACK 閭d箞杩涜閲嶄紶鐨 FIN 鎶ユ枃鑳藉鍒拌揪 + +### 6.TCP 鍜 UDP 鐨勫尯鍒 + +1. TCP闈㈠悜杩炴帴锛堬紙濡傛墦鐢佃瘽瑕佸厛鎷ㄥ彿寤虹珛杩炴帴锛;UDP鏄棤杩炴帴鐨勶紝鍗冲彂閫佹暟鎹箣鍓嶄笉闇瑕佸缓绔嬭繛鎺ャ +2. TCP瑕佹眰瀹夊叏鎬э紝鎻愪緵鍙潬鐨勬湇鍔★紝閫氳繃TCP杩炴帴浼犻佺殑鏁版嵁锛屼笉涓㈠け銆佷笉閲嶅銆佸畨鍏ㄥ彲闈犮傝孶DP灏芥渶澶у姫鍔涗氦浠橈紝鍗充笉淇濊瘉鍙潬浜や粯銆 +3. TCP鏄偣瀵圭偣杩炴帴鐨勶紝UDP涓瀵逛竴锛屼竴瀵瑰锛屽瀵瑰閮藉彲浠 +4. TCP浼犺緭鏁堢巼鐩稿杈冧綆,鑰孶DP浼犺緭鏁堢巼楂橈紝瀹冮傜敤浜庡楂橀熶紶杈撳拰瀹炴椂鎬ф湁杈冮珮鐨勯氫俊鎴栧箍鎾氫俊銆 +5. TCP閫傚悎鐢ㄤ簬缃戦〉锛岄偖浠剁瓑;UDP閫傚悎鐢ㄤ簬瑙嗛锛岃闊冲箍鎾瓑 +6. TCP闈㈠悜瀛楄妭娴侊紝UDP闈㈠悜鎶ユ枃 + +### 7. TCP鎶ユ枃棣栭儴鏈夊摢浜涘瓧娈碉紝璇磋鍏朵綔鐢 + + +![](https://files.mdnice.com/user/3535/f9f25411-09d7-4441-bf64-3f0881c4fc01.png) + +- **16浣嶇鍙e彿**锛氭簮绔彛鍙凤紝涓绘満璇ユ姤鏂囨鏄潵鑷摢閲岋紱鐩爣绔彛鍙凤紝瑕佷紶缁欏摢涓笂灞傚崗璁垨搴旂敤绋嬪簭 +- **32浣嶅簭鍙**锛氫竴娆CP閫氫俊锛堜粠TCP杩炴帴寤虹珛鍒版柇寮锛夎繃绋嬩腑鏌愪竴涓紶杈撴柟鍚戜笂鐨勫瓧鑺傛祦鐨勬瘡涓瓧鑺傜殑缂栧彿銆 +- **32浣嶇‘璁ゅ彿**锛氱敤浣滃鍙︿竴鏂瑰彂閫佺殑tcp鎶ユ枃娈电殑鍝嶅簲銆傚叾鍊兼槸鏀跺埌鐨凾CP鎶ユ枃娈电殑搴忓彿鍊煎姞1銆 +- **4浣嶅ご閮ㄩ暱搴**锛氳〃绀簍cp澶撮儴鏈夊灏戜釜32bit瀛楋紙4瀛楄妭锛夈傚洜涓4浣嶆渶澶ц兘鏍囪瘑15锛屾墍浠CP澶撮儴鏈闀挎槸60瀛楄妭銆 +- **6浣嶆爣蹇椾綅**锛歎RG(绱фユ寚閽堟槸鍚︽湁鏁)锛孉Ck锛堣〃绀虹‘璁ゅ彿鏄惁鏈夋晥锛夛紝PSH锛堢紦鍐插尯灏氭湭濉弧锛夛紝RST锛堣〃绀鸿姹傚鏂归噸鏂板缓绔嬭繛鎺ワ級锛孲YN锛堝缓绔嬭繛鎺ユ秷鎭爣蹇楁帴锛夛紝FIN锛堣〃绀哄憡鐭ュ鏂规湰绔鍏抽棴杩炴帴浜嗭級 +- **16浣嶇獥鍙eぇ灏**锛氭槸TCP娴侀噺鎺у埗鐨勪竴涓墜娈点傝繖閲岃鐨勭獥鍙o紝鎸囩殑鏄帴鏀堕氬憡绐楀彛銆傚畠鍛婅瘔瀵规柟鏈鐨凾CP鎺ユ敹缂撳啿鍖鸿繕鑳藉绾冲灏戝瓧鑺傜殑鏁版嵁锛岃繖鏍峰鏂瑰氨鍙互鎺у埗鍙戦佹暟鎹殑閫熷害銆 +- **16浣嶆牎楠屽拰**锛氱敱鍙戦佺濉厖锛屾帴鏀剁瀵筎CP鎶ユ枃娈垫墽琛孋RC绠楁硶浠ユ楠孴CP鎶ユ枃娈靛湪浼犺緭杩囩▼涓槸鍚︽崯鍧忋傛敞鎰忥紝杩欎釜鏍¢獙涓嶄粎鍖呮嫭TCP澶撮儴锛屼篃鍖呮嫭鏁版嵁閮ㄥ垎銆傝繖涔熸槸TCP鍙潬浼犺緭鐨勪竴涓噸瑕佷繚闅溿 +- **16浣嶇揣鎬ユ寚閽**锛氫竴涓鐨勫亸绉婚噺銆傚畠鍜屽簭鍙峰瓧娈电殑鍊肩浉鍔犺〃绀烘渶鍚庝竴涓揣鎬ユ暟鎹殑涓嬩竴瀛楄妭鐨勫簭鍙枫傚洜姝わ紝纭垏鍦拌锛岃繖涓瓧娈垫槸绱фユ寚閽堢浉瀵瑰綋鍓嶅簭鍙风殑鍋忕Щ锛屼笉濡ㄧО涔嬩负绱фュ亸绉汇俆CP鐨勭揣鎬ユ寚閽堟槸鍙戦佺鍚戞帴鏀剁鍙戦佺揣鎬ユ暟鎹殑鏂规硶銆 + +### 8. TCP 鏄浣曚繚璇佸彲闈犳х殑 + + +![](https://files.mdnice.com/user/3535/fce5ee83-8664-4f82-a453-fe25bc35dd88.png) + + +- 棣栧厛锛孴CP鐨勮繛鎺ユ槸鍩轰簬**涓夋鎻℃墜**锛岃屾柇寮鍒欐槸**鍥涙鎸ユ墜**銆傜‘淇濊繛鎺ュ拰鏂紑鐨勫彲闈犳с +- 鍏舵锛孴CP鐨勫彲闈犳э紝杩樹綋鐜板湪**鏈夌姸鎬**;TCP浼氳褰曞摢浜涙暟鎹彂閫佷簡锛屽摢浜涙暟鎹鎺ュ彈浜嗭紝鍝簺娌℃湁琚帴鍙楋紝骞朵笖淇濊瘉鏁版嵁鍖呮寜搴忓埌杈撅紝淇濊瘉鏁版嵁浼犺緭涓嶅嚭宸敊銆 +- 鍐嶆锛孴CP鐨勫彲闈犳э紝杩樹綋鐜板湪**鍙帶鍒**銆傚畠鏈夋姤鏂囨牎楠屻丄CK搴旂瓟銆**瓒呮椂閲嶄紶(鍙戦佹柟)**銆佸け搴忔暟鎹噸浼狅紙鎺ユ敹鏂癸級銆佷涪寮冮噸澶嶆暟鎹佹祦閲忔帶鍒讹紙婊戝姩绐楀彛锛夊拰鎷ュ鎺у埗绛夋満鍒躲 + +### 9. TCP 閲嶄紶鏈哄埗 + +#### 瓒呮椂閲嶄紶 +TCP 涓轰簡瀹炵幇鍙潬浼犺緭锛屽疄鐜颁簡閲嶄紶鏈哄埗銆傛渶鍩烘湰鐨勯噸浼犳満鍒讹紝灏辨槸**瓒呮椂閲嶄紶**锛屽嵆鍦ㄥ彂閫佹暟鎹姤鏂囨椂锛岃瀹氫竴涓畾鏃跺櫒锛屾瘡闂撮殧涓娈垫椂闂达紝娌℃湁鏀跺埌瀵规柟鐨凙CK纭搴旂瓟鎶ユ枃锛屽氨浼氶噸鍙戣鎶ユ枃銆 + +杩欎釜闂撮殧鏃堕棿锛屼竴鑸缃负澶氬皯鍛紵鎴戜滑鍏堟潵鐪嬩笅浠涔堝彨**RTT锛圧ound-Trip Time锛屽線杩旀椂闂达級**銆 + +![](https://files.mdnice.com/user/3535/05b6c061-2515-4367-aa58-0526db10f6b6.png) + +RTT灏辨槸锛屼竴涓暟鎹寘浠庡彂鍑哄幓鍒板洖鏉ョ殑鏃堕棿锛屽嵆**鏁版嵁鍖呯殑涓娆″線杩旀椂闂**銆傝秴鏃堕噸浼犳椂闂达紝灏辨槸Retransmission Timeout 锛岀畝绉**RTO**銆 + +**RTO璁剧疆澶氫箙鍛紵** +- 濡傛灉RTO姣旇緝灏忥紝閭e緢鍙兘鏁版嵁閮芥病鏈変涪澶憋紝灏遍噸鍙戜簡锛岃繖浼氬鑷寸綉缁滈樆濉烇紝浼氬鑷存洿澶氱殑瓒呮椂鍑虹幇銆 +- 濡傛灉RTO姣旇緝澶э紝绛夊埌鑺卞効閮借阿浜嗚繕鏄病鏈夐噸鍙戯紝閭f晥鏋滃氨涓嶅ソ浜嗐 + +涓鑸儏鍐典笅锛孯TO鐣ュぇ浜嶳TT锛屾晥鏋滄槸鏈濂界殑銆備竴浜涘皬浼欎即浼氶棶锛岃秴鏃舵椂闂存湁娌℃湁璁$畻鍏紡鍛?鏈夌殑锛佹湁涓爣鍑嗘柟娉曠畻RTO鐨勫叕寮忥紝涔熷彨**Jacobson / Karels 绠楁硶**銆傛垜浠竴璧锋潵鐪嬩笅璁$畻RTO鐨勫叕寮 + +**1. 鍏堣绠桽RTT锛堣绠楀钩婊戠殑RTT锛** + +``` +SRTT = (1 - 伪) * SRTT + 伪 * RTT //姹 SRTT 鐨勫姞鏉冨钩鍧 +``` + +**2. 鍐嶈绠桼TTVAR (round-trip time variation)** + + +``` +RTTVAR = (1 - 尾) * RTTVAR + 尾 * (|RTT - SRTT|) //璁$畻 SRTT 涓庣湡瀹炲肩殑宸窛 +``` + +**3. 鏈缁堢殑RTO** + +``` +RTO = 碌 * SRTT + 鈭 * RTTVAR = SRTT + 4路RTTVAR +``` + +鍏朵腑锛宍``伪 = 0.125锛屛 = 0.25锛 渭 = 1锛屸垈 = 4```锛岃繖浜涘弬鏁伴兘鏄ぇ閲忕粨鏋滃緱鍑虹殑鏈浼樺弬鏁般 + +浣嗘槸锛岃秴鏃堕噸浼犱細鏈夎繖浜涚己鐐癸細 +> - 褰撲竴涓姤鏂囨涓㈠け鏃讹紝浼氱瓑寰呬竴瀹氱殑瓒呮椂鍛ㄦ湡鐒跺悗鎵嶉噸浼犲垎缁勶紝澧炲姞浜嗙鍒扮鐨勬椂寤躲 +> - 褰撲竴涓姤鏂囨涓㈠け鏃讹紝鍦ㄥ叾绛夊緟瓒呮椂鐨勮繃绋嬩腑锛屽彲鑳戒細鍑虹幇杩欑鎯呭喌锛氬叾鍚庣殑鎶ユ枃娈靛凡缁忚鎺ユ敹绔帴鏀朵絾鍗磋繜杩熷緱涓嶅埌纭锛屽彂閫佺浼氳涓轰篃涓㈠け浜嗭紝浠庤屽紩璧蜂笉蹇呰鐨勯噸浼狅紝鏃㈡氮璐硅祫婧愪篃娴垂鏃堕棿銆 + +骞朵笖锛孴CP鏈変釜绛栫暐锛屽氨鏄秴鏃舵椂闂撮棿闅斾細鍔犲嶃傝秴鏃堕噸浼犻渶瑕**绛夊緟寰堥暱鏃堕棿**銆傚洜姝わ紝杩樺彲浠ヤ娇鐢**蹇熼噸浼**鏈哄埗銆 + +#### 蹇熼噸浼 + +**蹇熼噸浼**鏈哄埗锛屽畠涓嶄互鏃堕棿椹卞姩锛岃屾槸浠ユ暟鎹┍鍔ㄣ傚畠鍩轰簬鎺ユ敹绔殑鍙嶉淇℃伅鏉ュ紩鍙戦噸浼犮 + +涓璧锋潵鐪嬩笅蹇熼噸浼犳祦绋嬶細 + +![蹇熼噸浼犳祦绋媇(https://files.mdnice.com/user/3535/2c172057-bb6c-40e1-8d64-b6a15818f596.png) + +鍙戦佺鍙戦佷簡 1锛2锛3锛4锛5,6 浠芥暟鎹: + +- 绗竴浠 Seq=1 鍏堥佸埌浜嗭紝浜庢槸灏 Ack 鍥 2锛 +- 绗簩浠 Seq=2 涔熼佸埌浜嗭紝鍋囪涔熸甯革紝浜庢槸ACK 鍥 3锛 +- 绗笁浠 Seq=3 鐢变簬缃戠粶绛夊叾浠栧師鍥狅紝娌¢佸埌锛 +- 绗洓浠 Seq=4 涔熼佸埌浜嗭紝浣嗘槸鍥犱负Seq3娌℃敹鍒般傛墍浠CK鍥3锛 +- 鍚庨潰鐨 Seq=4,5鐨勪篃閫佸埌浜嗭紝浣嗘槸ACK杩樻槸鍥炲3锛屽洜涓篠eq=3娌℃敹鍒般 +- 鍙戦佺杩炵潃鏀跺埌涓変釜閲嶅鍐椾綑ACK=3鐨勭‘璁わ紙瀹為檯涓婃槸4涓紝浣嗘槸鍓嶉潰涓涓槸姝e父鐨凙CK锛屽悗闈笁涓墠鏄噸澶嶅啑浣欑殑锛夛紝渚跨煡閬撳摢涓姤鏂囨鍦ㄤ紶杈撹繃绋嬩腑涓㈠け浜嗭紝浜庢槸鍦ㄥ畾鏃跺櫒杩囨湡涔嬪墠锛岄噸浼犺鎶ユ枃娈点 +- 鏈鍚庯紝鎺ユ敹鍒版敹鍒颁簡 Seq3锛屾鏃跺洜涓 Seq=4锛5锛6閮芥敹鍒颁簡锛屼簬鏄疉CK鍥7. + +浣**蹇熼噸浼**杩樺彲鑳戒細鏈変釜闂锛欰CK鍙悜鍙戦佺鍛婄煡鏈澶х殑鏈夊簭鎶ユ枃娈碉紝鍒板簳鏄摢涓姤鏂囦涪澶变簡鍛紵**骞朵笉纭畾**锛侀偅鍒板簳璇ラ噸浼犲灏戜釜鍖呭憿锛 +> 鏄噸浼 Seq3 鍛紵杩樻槸閲嶄紶 Seq3銆丼eq4銆丼eq5銆丼eq6 鍛紵鍥犱负鍙戦佺骞朵笉娓呮杩欎笁涓繛缁殑 ACK3 鏄皝浼犲洖鏉ョ殑銆 + +#### 甯﹂夋嫨纭鐨勯噸浼狅紙SACK锛 + +涓轰簡瑙e喅蹇熼噸浼犵殑闂锛**搴旇閲嶄紶澶氬皯涓寘**? TCP鎻愪緵浜**SACK鏂规硶**锛堝甫閫夋嫨纭鐨勯噸浼狅紝Selective Acknowledgment锛夈 + +**SACK鏈哄埗**灏辨槸锛屽湪蹇熼噸浼犵殑鍩虹涓婏紝鎺ユ敹绔繑鍥炴渶杩戞敹鍒扮殑鎶ユ枃娈电殑搴忓垪鍙疯寖鍥达紝杩欐牱鍙戦佺灏辩煡閬撴帴鏀剁鍝簺鏁版嵁鍖呮病鏀跺埌锛岄叡绱氨寰堟竻妤氳閲嶄紶鍝簺鏁版嵁鍖呭暒銆係ACK鏍囪鏄姞鍦═CP澶撮儴**閫夐」**瀛楁閲岄潰鐨勩 + +![SACK鏈哄埗](https://files.mdnice.com/user/3535/9475e768-9d4d-46dd-97a5-ec2298c433bd.png) + +濡備笂鍥句腑锛屽彂閫佺鏀跺埌浜嗕笁娆″悓鏍风殑ACK=30鐨勭‘璁ゆ姤鏂囷紝浜庢槸灏变細瑙﹀彂蹇熼噸鍙戞満鍒讹紝閫氳繃SACK淇℃伅鍙戠幇鍙湁```30~39```杩欐鏁版嵁涓㈠け锛屼簬鏄噸鍙戞椂灏卞彧閫夋嫨浜嗚繖涓猔``30~39```鐨凾CP鎶ユ枃娈佃繘琛岄噸鍙戙 + +#### D-SACK + + D-SACK锛屽嵆Duplicate SACK锛堥噸澶峉ACK锛夛紝鍦⊿ACK鐨勫熀纭涓婂仛浜嗕竴浜涙墿灞曪紝锛屼富瑕佺敤鏉ュ憡璇夊彂閫佹柟锛屾湁鍝簺鏁版嵁鍖呰嚜宸遍噸澶嶆帴鍙椾簡銆侱SACK鐨勭洰鐨勬槸甯姪鍙戦佹柟鍒ゆ柇锛屾槸鍚﹀彂鐢熶簡鍖呭け搴忋丄CK涓㈠け銆佸寘閲嶅鎴栦吉閲嶄紶銆傝TCP鍙互鏇村ソ鐨勫仛缃戠粶娴佹帶銆傛潵鐪嬩釜鍥惧惂锛 + +![D-SACK绠瑕佹祦绋媇(https://files.mdnice.com/user/3535/d3647f5d-ce7c-4998-953a-04e8c8a9e71c.png) + +### 10. 鑱婅亰TCP鐨勬粦鍔ㄧ獥鍙 + +TCP 鍙戦佷竴涓暟鎹紝闇瑕佹敹鍒扮‘璁ゅ簲绛旓紝鎵嶄細鍙戦佷笅涓涓暟鎹傝繖鏍锋湁涓己鐐癸紝灏辨槸鏁堢巼浼氭瘮杈冧綆銆 +> 杩欏氨濂藉儚鎴戜滑闈㈠闈㈣亰澶╋紝浣犺瀹屼竴鍙ワ紝鎴戝簲绛斿悗锛屼綘鎵嶄細璇翠笅涓鍙ャ傞偅涔堬紝濡傛灉鎴戝湪蹇欏叾浠栦簨鎯咃紝娌℃湁鑳藉鍙婃椂鍥炲浣犮備綘璇村畬涓鍙ュ悗锛岃绛夊埌鎴戝繖瀹屽洖澶嶄綘锛屼綘鎵嶈涓嬪彞锛岃繖鏄剧劧寰堜笉鐜板疄銆 + +涓轰簡瑙e喅杩欎釜闂锛孴CP寮曞叆浜**绐楀彛**锛屽畠鏄搷浣滅郴缁熷紑杈熺殑涓涓紦瀛樼┖闂淬傜獥鍙eぇ灏忓艰〃绀烘棤闇绛夊緟纭搴旂瓟锛岃屽彲浠ョ户缁彂閫佹暟鎹殑鏈澶у笺 + +TCP澶撮儴鏈変釜瀛楁鍙玾in锛屼篃鍗抽偅涓**16浣嶇殑绐楀彛澶у皬**锛屽畠鍛婅瘔瀵规柟鏈鐨凾CP鎺ユ敹缂撳啿鍖鸿繕鑳藉绾冲灏戝瓧鑺傜殑鏁版嵁锛岃繖鏍峰鏂瑰氨鍙互鎺у埗鍙戦佹暟鎹殑閫熷害锛屼粠鑰岃揪鍒**娴侀噺鎺у埗**鐨勭洰鐨勩 +> 閫氫織鐐硅锛屽氨鏄帴鍙楁柟姣忔鏀跺埌鏁版嵁鍖咃紝鍦ㄥ彂閫佺‘璁ゆ姤鏂囩殑鏃跺欙紝鍚屾椂鍛婅瘔鍙戦佹柟锛岃嚜宸辩殑缂撳瓨鍖鸿繕鏈夊灏戠┖浣欑┖闂达紝缂撳啿鍖虹殑绌轰綑绌洪棿锛屾垜浠氨绉颁箣涓烘帴鍙楃獥鍙eぇ灏忋傝繖灏辨槸win銆 + +TCP 婊戝姩绐楀彛鍒嗕负涓ょ: 鍙戦佺獥鍙e拰鎺ユ敹绐楀彛銆**鍙戦佺鐨勬粦鍔ㄧ獥鍙**鍖呭惈鍥涘ぇ閮ㄥ垎锛屽涓嬶細 +- 宸插彂閫佷笖宸叉敹鍒癆CK纭 +- 宸插彂閫佷絾鏈敹鍒癆CK纭 +- 鏈彂閫佷絾鍙互鍙戦 +- 鏈彂閫佷篃涓嶅彲浠ュ彂閫 + +![](https://files.mdnice.com/user/3535/8f7d9784-f6e6-47d8-82bb-deb398431025.png) + +- 铏氱嚎鐭╁舰妗嗭紝灏辨槸鍙戦佺獥鍙c +- SND.WND: 琛ㄧず鍙戦佺獥鍙g殑澶у皬,涓婂浘铏氱嚎妗嗙殑鏍煎瓙鏁板氨鏄14涓 +- SND.UNA: 涓涓粷瀵规寚閽堬紝瀹冩寚鍚戠殑鏄凡鍙戦佷絾鏈‘璁ょ殑绗竴涓瓧鑺傜殑搴忓垪鍙枫 +- SND.NXT锛氫笅涓涓彂閫佺殑浣嶇疆锛屽畠鎸囧悜鏈彂閫佷絾鍙互鍙戦佺殑绗竴涓瓧鑺傜殑搴忓垪鍙枫 + +鎺ユ敹鏂圭殑婊戝姩绐楀彛鍖呭惈涓夊ぇ閮ㄥ垎锛屽涓嬶細 +- 宸叉垚鍔熸帴鏀跺苟纭 +- 鏈敹鍒版暟鎹絾鍙互鎺ユ敹 +- 鏈敹鍒版暟鎹苟涓嶅彲浠ユ帴鏀剁殑鏁版嵁 + +![](https://files.mdnice.com/user/3535/40b906fe-aa60-42f3-b7bf-b4fcaa9a0588.png) + +- 铏氱嚎鐭╁舰妗嗭紝灏辨槸鎺ユ敹绐楀彛銆 +- REV.WND: 琛ㄧず鎺ユ敹绐楀彛鐨勫ぇ灏,涓婂浘铏氱嚎妗嗙殑鏍煎瓙灏辨槸9涓 +- REV.NXT:涓嬩竴涓帴鏀剁殑浣嶇疆锛屽畠鎸囧悜鏈敹鍒颁絾鍙互鎺ユ敹鐨勭涓涓瓧鑺傜殑搴忓垪鍙枫 + +### 11. 鑱婅亰TCP鐨勬祦閲忔帶鍒 + +TCP涓夋鎻℃墜锛屽彂閫佺鍜屾帴鏀剁杩涘叆鍒癊STABLISHED鐘舵侊紝瀹冧滑鍗冲彲浠ユ剦蹇湴浼犺緭鏁版嵁鍟︺ + +浣嗘槸鍙戦佺涓嶈兘鐤媯鍦板悜鎺ユ敹绔彂閫佹暟鎹紝鍥犱负鎺ユ敹绔帴鏀朵笉杩囨潵鐨勮瘽锛屾帴鏀舵柟鍙兘鎶婂鐞嗕笉杩囨潵鐨勬暟鎹瓨鍦ㄧ紦瀛樺尯閲屻傚鏋滅紦瀛樺尯閮芥弧浜嗭紝鍙戦佹柟杩樺湪鐤媯鍙戦佹暟鎹殑璇濓紝鎺ユ敹鏂瑰彧鑳芥妸鏀跺埌鐨勬暟鎹寘涓㈡帀锛岃繖灏辨氮璐逛簡缃戠粶璧勬簮鍟︺ + +> TCP 鎻愪緵涓绉嶆満鍒跺彲浠ヨ鍙戦佺鏍规嵁鎺ユ敹绔殑瀹為檯鎺ユ敹鑳藉姏鎺у埗鍙戦佺殑鏁版嵁閲忥紝杩欏氨鏄**娴侀噺鎺у埗**銆 + +TCP閫氳繃婊戝姩绐楀彛鏉ユ帶鍒舵祦閲忥紝鎴戜滑鐪嬩笅娴侀噺鎺у埗鐨**绠瑕佹祦绋**鍚э細 + +棣栧厛鍙屾柟涓夋鎻℃墜锛屽垵濮嬪寲鍚勮嚜鐨勭獥鍙eぇ灏忥紝鍧囦负 400 涓瓧鑺傘 + + +![TCP鐨勬祦閲忔帶鍒禲(https://files.mdnice.com/user/3535/e233b594-72b5-4f9a-bc9c-23bb5c065bfe.png) + +1. 鍋囧褰撳墠鍙戦佹柟缁欐帴鏀舵柟鍙戦佷簡200涓瓧鑺傦紝閭d箞锛屽彂閫佹柟鐨刞``SND.NXT```浼氬彸绉200涓瓧鑺傦紝涔熷氨鏄褰撳墠鐨勫彲鐢ㄧ獥鍙e噺灏戜簡200 涓瓧鑺傘 +2. 鎺ュ彈鏂规敹鍒板悗锛屾斁鍒扮紦鍐查槦鍒楅噷闈紝REV.WND =400-200=200瀛楄妭锛屾墍浠in=200瀛楄妭杩斿洖缁欏彂閫佹柟銆傛帴鏀舵柟浼氬湪 ACK 鐨勬姤鏂囬閮ㄥ甫涓婄缉灏忓悗鐨勬粦鍔ㄧ獥鍙200瀛楄妭 +3. 鍙戦佹柟鍙堝彂閫200瀛楄妭杩囨潵锛200瀛楄妭鍒拌揪锛岀户缁斁鍒扮紦鍐查槦鍒椼備笉杩囪繖鏃跺欙紝鐢变簬澶ч噺璐熻浇鐨勫師鍥狅紝鎺ュ彈鏂瑰鐞嗕笉浜嗚繖涔堝瀛楄妭锛屽彧鑳藉鐞100瀛楄妭锛屽墿浣欑殑100瀛楄妭缁х画鏀惧埌缂撳啿闃熷垪銆傝繖鏃跺欙紝REV.WND = 400-200-100=100瀛楄妭锛屽嵆win=100杩斿洖鍙戦佹柟銆 +4. 鍙戦佹柟缁х画骞叉椿锛屽彂閫100瀛楄妭杩囨潵锛岃繖鏃跺欙紝鎺ュ彈绐楀彛win鍙樹负0銆 +5. 鍙戦佹柟鍋滄鍙戦侊紝寮鍚竴涓畾鏃朵换鍔★紝姣忛殧涓娈垫椂闂达紝灏卞幓璇㈤棶鎺ュ彈鏂癸紝鐩村埌win澶т簬0锛屾墠缁х画寮濮嬪彂閫併 + +### 12. TCP鐨勬嫢濉炴帶鍒 + +鎷ュ鎺у埗鏄**浣滅敤浜庣綉缁滅殑锛岄槻姝㈣繃澶氱殑鏁版嵁鍖呮敞鍏ュ埌缃戠粶涓紝閬垮厤鍑虹幇缃戠粶璐熻浇杩囧ぇ鐨勬儏鍐**銆傚畠鐨勭洰鏍囦富瑕佹槸鏈澶у寲鍒╃敤缃戠粶涓婄摱棰堥摼璺殑甯﹀銆傚畠璺**娴侀噺鎺у埗**鍙堟湁浠涔堝尯鍒憿锛熸祦閲忔帶鍒舵槸浣滅敤浜庢帴鏀惰呯殑锛屾牴鎹**鎺ユ敹绔殑瀹為檯鎺ユ敹鑳藉姏鎺у埗鍙戦侀熷害**锛岄槻姝㈠垎缁勪涪澶辩殑銆 + +鎴戜滑鍙互鎶婄綉缁滈摼璺瘮鍠绘垚涓鏍规按绠★紝濡傛灉鎴戜滑鎯虫渶澶у寲鍒╃敤缃戠粶鏉ヤ紶杈撴暟鎹紝閭e氨鏄敖蹇姘寸杈惧埌鏈浣冲厖婊$姸鎬併 + +![](https://files.mdnice.com/user/3535/f4b5b102-75db-47cc-8c1a-83fa01941dcc.png) + +鍙戦佹柟缁存姢涓涓**鎷ュ绐楀彛cwnd锛坈ongestion window锛** 鐨勫彉閲忥紝鐢ㄦ潵浼扮畻鍦ㄤ竴娈垫椂闂村唴杩欐潯閾捐矾锛堟按绠★級鍙互鎵胯浇鍜岃繍杈撶殑鏁版嵁锛堟按锛夌殑鏁伴噺銆傚畠澶у皬浠h〃鐫缃戠粶鐨勬嫢濉炵▼搴︼紝骞朵笖鏄姩鎬佸彉鍖栫殑锛屼絾鏄负浜嗚揪鍒版渶澶х殑浼犺緭鏁堢巼锛屾垜浠濡備綍鐭ラ亾杩欐潯姘寸鐨勮繍閫佹晥鐜囨槸澶氬皯鍛紵 + +涓涓瘮杈冪畝鍗曠殑鏂规硶灏辨槸涓嶆柇澧炲姞浼犺緭鐨勬按閲忥紝鐩村埌姘寸蹇鐖嗚涓烘锛堝搴斿埌缃戠粶涓婂氨鏄彂鐢熶涪鍖咃級锛岀敤 TCP 鐨勬弿杩板氨鏄細 +> 鍙缃戠粶涓病鏈夊嚭鐜版嫢濉烇紝鎷ュ绐楀彛鐨勫煎氨鍙互鍐嶅澶т竴浜涳紝浠ヤ究鎶婃洿澶氱殑鏁版嵁鍖呭彂閫佸嚭鍘伙紝浣嗗彧瑕佺綉缁滃嚭鐜版嫢濉烇紝鎷ュ绐楀彛鐨勫煎氨搴旇鍑忓皬涓浜涳紝浠ュ噺灏戞敞鍏ュ埌缃戠粶涓殑鏁版嵁鍖呮暟銆 + +瀹為檯涓婏紝鎷ュ鎺у埗涓昏鏈夎繖鍑犵甯哥敤绠楁硶 +- 鎱㈠惎鍔 +- 鎷ュ閬垮厤 +- 鎷ュ鍙戠敓 +- 蹇熸仮澶 + +#### 鎱㈠惎鍔ㄧ畻娉 + +鎱㈠惎鍔ㄧ畻娉曪紝琛ㄩ潰鎰忔濆氨鏄紝鍒ユ參鎱㈡潵銆傚畠琛ㄧずTCP寤虹珛杩炴帴瀹屾垚鍚庯紝涓寮濮嬩笉瑕佸彂閫佸ぇ閲忕殑鏁版嵁锛岃屾槸鍏堟帰娴嬩竴涓嬬綉缁滅殑鎷ュ绋嬪害銆傜敱灏忓埌澶ч愭笎澧炲姞鎷ュ绐楀彛鐨勫ぇ灏忥紝濡傛灉娌℃湁鍑虹幇涓㈠寘锛**姣忔敹鍒颁竴涓狝CK锛屽氨灏嗘嫢濉炵獥鍙wnd澶у皬灏卞姞1锛堝崟浣嶆槸MSS锛**銆**姣忚疆娆**鍙戦佺獥鍙e鍔犱竴鍊嶏紝鍛堟寚鏁板闀匡紝濡傛灉鍑虹幇涓㈠寘锛屾嫢濉炵獥鍙e氨鍑忓崐锛岃繘鍏ユ嫢濉為伩鍏嶉樁娈点 + +- TCP杩炴帴瀹屾垚锛屽垵濮嬪寲cwnd = 1锛岃〃鏄庡彲浠ヤ紶涓涓狹SS鍗曚綅澶у皬鐨勬暟鎹 +- 姣忓綋鏀跺埌涓涓狝CK锛宑wnd灏卞姞涓; +- 姣忓綋杩囦簡涓涓猂TT锛宑wnd灏卞鍔犱竴鍊; 鍛堟寚鏁拌鍗 + +![](https://files.mdnice.com/user/3535/c9edd5d1-0302-45b7-bee7-22d1e505b085.png) + +涓轰簡闃叉cwnd澧為暱杩囧ぇ寮曡捣缃戠粶鎷ュ锛岃繕闇璁剧疆涓涓**鎱㈠惎鍔ㄩ榾鍊約sthresh**锛坰low start threshold锛夌姸鎬佸彉閲忋傚綋```cwnd```鍒拌揪璇ラ榾鍊煎悗锛屽氨濂藉儚姘寸琚叧灏忎簡姘撮緳澶翠竴鏍凤紝鍑忓皯鎷ュ鐘舵併傚嵆褰**cwnd >ssthresh**鏃讹紝杩涘叆浜**鎷ュ閬垮厤**绠楁硶銆 + + +#### 鎷ュ閬垮厤绠楁硶 + +涓鑸潵璇达紝鎱㈠惎鍔ㄩ榾鍊約sthresh鏄65535瀛楄妭锛宍``cwnd```鍒拌揪**鎱㈠惎鍔ㄩ榾鍊**鍚 +- 姣忔敹鍒颁竴涓狝CK鏃讹紝cwnd = cwnd + 1/cwnd +- 褰撴瘡杩囦竴涓猂TT鏃讹紝cwnd = cwnd + 1 + +鏄剧劧杩欐槸涓涓嚎鎬т笂鍗囩殑绠楁硶锛岄伩鍏嶈繃蹇鑷寸綉缁滄嫢濉為棶棰樸 + +![](https://files.mdnice.com/user/3535/600ed914-5f98-4c01-9f1d-d7dcc12244b8.png) + +#### 鎷ュ鍙戠敓 + +褰撶綉缁滄嫢濉炲彂鐢**涓㈠寘**鏃讹紝浼氭湁涓ょ鎯呭喌锛 + +- RTO瓒呮椂閲嶄紶 +- 蹇熼噸浼 + +濡傛灉鏄彂鐢熶簡**RTO瓒呮椂閲嶄紶**锛屽氨浼氫娇鐢ㄦ嫢濉炲彂鐢熺畻娉 + +- 鎱㈠惎鍔ㄩ榾鍊約shthresh = cwnd /2 +- cwnd 閲嶇疆涓 1 +- 杩涘叆鏂扮殑鎱㈠惎鍔ㄨ繃绋 + + +![](https://files.mdnice.com/user/3535/9e54bfb4-ed83-42a9-aeb0-f98b44563067.png) + +杩欑湡鐨勬槸**杈涜緵鑻﹁嫤鍑犲崄骞达紝涓鏈濆洖鍒拌В鏀惧墠**銆傚叾瀹炶繕鏈夋洿濂界殑澶勭悊鏂瑰紡锛屽氨鏄**蹇熼噸浼**銆傚彂閫佹柟鏀跺埌3涓繛缁噸澶嶇殑ACK鏃讹紝灏变細蹇熷湴閲嶄紶锛屼笉蹇呯瓑寰**RTO瓒呮椂**鍐嶉噸浼犮 + +![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e5f5ca98465c40b0936ed83aba2ffc15~tplv-k3u1fbpfcp-watermark.image) + +鎱㈠惎鍔ㄩ榾鍊約sthresh 鍜 cwnd 鍙樺寲濡備笅锛 + +- 鎷ュ绐楀彛澶у皬 cwnd = cwnd/2 +- 鎱㈠惎鍔ㄩ榾鍊 ssthresh = cwnd +- 杩涘叆蹇熸仮澶嶇畻娉 + +#### 蹇熸仮澶 + +蹇熼噸浼犲拰蹇熸仮澶嶇畻娉曚竴鑸悓鏃朵娇鐢ㄣ傚揩閫熸仮澶嶇畻娉曡涓猴紝杩樻湁3涓噸澶岮CK鏀跺埌锛岃鏄庣綉缁滀篃娌¢偅涔堢碂绯曪紝鎵浠ユ病鏈夊繀瑕佸儚RTO瓒呮椂閭d箞寮虹儓銆 + +姝e鍓嶉潰鎵璇达紝杩涘叆蹇熸仮澶嶄箣鍓嶏紝cwnd 鍜 sshthresh宸茶鏇存柊锛 +``` +- cwnd = cwnd /2 +- sshthresh = cwnd +``` + +鐒跺悗锛岀湡姝g殑蹇熺畻娉曞涓嬶細 + +- cwnd = sshthresh + 3 +- 閲嶄紶閲嶅鐨勯偅鍑犱釜ACK锛堝嵆涓㈠け鐨勯偅鍑犱釜鏁版嵁鍖咃級 +- 濡傛灉鍐嶆敹鍒伴噸澶嶇殑 ACK锛岄偅涔 cwnd = cwnd +1 +- 濡傛灉鏀跺埌鏂版暟鎹殑 ACK 鍚, cwnd = sshthresh銆傚洜涓烘敹鍒版柊鏁版嵁鐨 ACK锛岃〃鏄庢仮澶嶈繃绋嬪凡缁忕粨鏉燂紝鍙互鍐嶆杩涘叆浜嗘嫢濉為伩鍏嶇殑绠楁硶浜嗐 + +![](https://files.mdnice.com/user/3535/1cb2de35-db67-4efa-8b64-1ea00d57c116.png) + +### 13. 鍗婅繛鎺ラ槦鍒楀拰 SYN Flood 鏀诲嚮鐨勫叧绯 + +TCP杩涘叆涓夋鎻℃墜鍓嶏紝鏈嶅姟绔細浠**CLOSED**鐘舵佸彉涓**LISTEN**鐘舵,鍚屾椂鍦ㄥ唴閮ㄥ垱寤轰簡涓や釜闃熷垪锛氬崐杩炴帴闃熷垪锛圫YN闃熷垪锛夊拰鍏ㄨ繛鎺ラ槦鍒楋紙ACCEPT闃熷垪锛夈 + +浠涔堟槸**鍗婅繛鎺ラ槦鍒楋紙SYN闃熷垪锛** 鍛? 浠涔堟槸**鍏ㄨ繛鎺ラ槦鍒楋紙ACCEPT闃熷垪锛** 鍛紵鍥炲繂涓婽CP涓夋鎻℃墜鐨勫浘锛 + +![涓夋鎻℃墜](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/67e2444df1934f549e7509fb5ce4b561~tplv-k3u1fbpfcp-watermark.image) + +- TCP涓夋鎻℃墜鏃讹紝瀹㈡埛绔彂閫丼YN鍒版湇鍔$锛屾湇鍔$鏀跺埌涔嬪悗锛屼究鍥炲**ACK鍜孲YN**锛岀姸鎬佺敱**LISTEN鍙樹负SYN_RCVD**锛屾鏃惰繖涓繛鎺ュ氨琚帹鍏ヤ簡**SYN闃熷垪**锛屽嵆鍗婅繛鎺ラ槦鍒椼 +- 褰撳鎴风鍥炲ACK, 鏈嶅姟绔帴鏀跺悗锛屼笁娆℃彙鎵嬪氨瀹屾垚浜嗐傝繖鏃惰繛鎺ヤ細绛夊緟琚叿浣撶殑搴旂敤鍙栬蛋锛屽湪琚彇璧颁箣鍓嶏紝瀹冭鎺ㄥ叆ACCEPT闃熷垪锛屽嵆鍏ㄨ繛鎺ラ槦鍒椼 + +SYN Flood鏄竴绉嶅吀鍨嬬殑DoS (Denial of Service锛屾嫆缁濇湇鍔) 鏀诲嚮锛屽畠鍦ㄧ煭鏃堕棿鍐咃紝浼**涓嶅瓨鍦ㄧ殑IP鍦板潃**,鍚戞湇鍔″櫒澶ч噺鍙戣捣SYN鎶ユ枃銆傚綋鏈嶅姟鍣ㄥ洖澶峉YN+ACK鎶ユ枃鍚庯紝涓嶄細鏀跺埌ACK鍥炲簲鎶ユ枃锛屽鑷存湇鍔″櫒涓婂缓绔嬪ぇ閲忕殑鍗婅繛鎺ュ崐杩炴帴闃熷垪婊′簡锛岃繖灏辨棤娉曞鐞嗘甯哥殑TCP璇锋眰鍟︺ + +涓昏鏈 **syn cookie**鍜**SYN Proxy闃茬伀澧**绛夋柟妗堝簲瀵广 + +- **syn cookie**锛氬湪鏀跺埌SYN鍖呭悗锛屾湇鍔″櫒鏍规嵁涓瀹氱殑鏂规硶锛屼互鏁版嵁鍖呯殑婧愬湴鍧銆佺鍙g瓑淇℃伅涓哄弬鏁拌绠楀嚭涓涓猚ookie鍊间綔涓鸿嚜宸辩殑SYNACK鍖呯殑搴忓垪鍙凤紝鍥炲SYN+ACK鍚庯紝鏈嶅姟鍣ㄥ苟涓嶇珛鍗冲垎閰嶈祫婧愯繘琛屽鐞嗭紝绛夋敹鍒板彂閫佹柟鐨凙CK鍖呭悗锛岄噸鏂版牴鎹暟鎹寘鐨勬簮鍦板潃銆佺鍙h绠楄鍖呬腑鐨勭‘璁ゅ簭鍒楀彿鏄惁姝g‘锛屽鏋滄纭垯寤虹珛杩炴帴锛屽惁鍒欎涪寮冭鍖呫 + +- **SYN Proxy闃茬伀澧**锛氭湇鍔″櫒闃茬伀澧欎細瀵规敹鍒扮殑姣忎竴涓猄YN鎶ユ枃杩涜浠g悊鍜屽洖搴旓紝骞朵繚鎸佸崐杩炴帴銆傜瓑鍙戦佹柟灏咥CK鍖呰繑鍥炲悗锛屽啀閲嶆柊鏋勯燬YN鍖呭彂鍒版湇鍔″櫒锛屽缓绔嬬湡姝g殑TCP杩炴帴銆 + +### 14. Nagle 绠楁硶涓庡欢杩熺‘璁 + +#### Nagle绠楁硶 + +濡傛灉鍙戦佺鐤媯鍦板悜鎺ユ敹绔彂閫佸緢灏忕殑鍖咃紝姣斿灏1涓瓧鑺傦紝閭d箞浜茬埍鐨勫皬浼欎即锛屼綘浠寰椾細鏈変粈涔堥棶棰樺憿锛 + +> TCP/IP鍗忚涓紝鏃犺鍙戦佸灏戞暟鎹紝鎬绘槸瑕佸湪鏁版嵁鍓嶉潰鍔犱笂鍗忚澶达紝鍚屾椂锛屽鏂规帴鏀跺埌鏁版嵁锛屼篃闇瑕佸彂閫丄CK琛ㄧず纭銆備负浜嗗敖鍙兘鐨勫埄鐢ㄧ綉缁滃甫瀹斤紝TCP鎬绘槸甯屾湜灏藉彲鑳界殑鍙戦佽冻澶熷ぇ鐨勬暟鎹**Nagle绠楁硶**灏辨槸涓轰簡灏藉彲鑳藉彂閫佸ぇ鍧楁暟鎹紝閬垮厤缃戠粶涓厖鏂ョ潃璁稿灏忔暟鎹潡銆 + +Nagle绠楁硶鐨勫熀鏈畾涔夋槸锛**浠绘剰鏃跺埢锛屾渶澶氬彧鑳芥湁涓涓湭琚‘璁ょ殑灏忔**銆 鎵璋撯滃皬娈碘濓紝鎸囩殑鏄皬浜嶮SS灏哄鐨勬暟鎹潡锛屾墍璋撯滄湭琚‘璁も濓紝鏄寚涓涓暟鎹潡鍙戦佸嚭鍘诲悗锛屾病鏈夋敹鍒板鏂瑰彂閫佺殑ACK纭璇ユ暟鎹凡鏀跺埌銆 + +Nagle绠楁硶鐨勫疄鐜拌鍒欙細 + +- 濡傛灉鍖呴暱搴﹁揪鍒癕SS锛屽垯鍏佽鍙戦侊紱 +- 濡傛灉璇ュ寘鍚湁FIN锛屽垯鍏佽鍙戦侊紱 +- 璁剧疆浜員CP_NODELAY閫夐」锛屽垯鍏佽鍙戦侊紱 +- 鏈缃甌CP_CORK閫夐」鏃讹紝鑻ユ墍鏈夊彂鍑哄幓鐨勫皬鏁版嵁鍖咃紙鍖呴暱搴﹀皬浜嶮SS锛夊潎琚‘璁わ紝鍒欏厑璁稿彂閫侊紱 +- 涓婅堪鏉′欢閮芥湭婊¤冻锛屼絾鍙戠敓浜嗚秴鏃讹紙涓鑸负200ms锛夛紝鍒欑珛鍗冲彂閫併 + +#### 寤惰繜纭 + +濡傛灉鎺ュ彈鏂瑰垰鎺ユ敹鍒板彂閫佹柟鐨勬暟鎹寘锛屽湪寰堢煭寰堢煭鐨勬椂闂村唴锛屽張鎺ユ敹鍒扮浜屼釜鍖呫傞偅涔堣闂帴鏀舵柟鏄竴涓竴涓湴鍥炲濂界偣锛岃繕鏄悎骞朵竴璧峰洖澶嶅ソ鍛紵 + +> 鎺ユ敹鏂规敹鍒版暟鎹寘鍚庯紝濡傛灉鏆傛椂娌℃湁鏁版嵁瑕佸彂缁欏绔紝瀹冨彲浠ョ瓑涓娈垫椂鍐嶇‘璁わ紙Linux涓婇粯璁ゆ槸40ms锛夈傚鏋滆繖娈垫椂闂村垰濂芥湁鏁版嵁瑕佷紶缁欏绔紝ACK灏遍殢鐫鏁版嵁浼犺緭锛岃屼笉闇瑕佸崟鐙彂閫佷竴娆CK銆傚鏋滆秴杩囨椂闂磋繕娌℃湁鏁版嵁瑕佸彂閫侊紝涔熷彂閫丄CK锛岄伩鍏嶅绔互涓轰涪鍖呫 + +浣嗘槸鏈変簺鍦烘櫙涓嶈兘寤惰繜纭锛屾瘮濡傚彂鐜颁簡**涔卞簭鍖**銆**鎺ユ敹鍒颁簡澶т簬涓涓 frame 鐨勬姤鏂囷紝涓旈渶瑕佽皟鏁寸獥鍙eぇ灏**绛夈 + +涓鑸儏鍐典笅锛**Nagle绠楁硶鍜屽欢杩熺‘璁**涓嶈兘涓璧蜂娇鐢紝Nagle绠楁硶鎰忓懗鐫寤惰繜鍙戯紝**寤惰繜纭**鎰忓懗鐫寤惰繜鎺ユ敹锛岄叡绱氨浼氶犳垚鏇村ぇ鐨勫欢杩燂紝浼氫骇鐢熸ц兘闂銆 + +### 15. TCP鐨勭矘鍖呭拰鎷嗗寘 + +TCP鏄潰鍚戞祦锛屾病鏈夌晫闄愮殑涓涓叉暟鎹俆CP搴曞眰骞朵笉浜嗚В涓婂眰涓氬姟鏁版嵁鐨勫叿浣撳惈涔夛紝瀹冧細鏍规嵁TCP缂撳啿鍖虹殑瀹為檯鎯呭喌杩涜鍖呯殑鍒掑垎锛屾墍浠ュ湪涓氬姟涓婅涓猴紝涓**涓畬鏁寸殑鍖呭彲鑳戒細琚玊CP鎷嗗垎鎴愬涓寘杩涜鍙戦**锛**涔熸湁鍙兘鎶婂涓皬鐨勫寘灏佽鎴愪竴涓ぇ鐨勬暟鎹寘鍙戦**锛岃繖灏辨槸鎵璋撶殑TCP绮樺寘鍜屾媶鍖呴棶棰樸 + +![TCP鐨勭矘鍖呭拰鎷嗗寘](https://files.mdnice.com/user/3535/cf617d8f-70c3-4687-bb20-1bc3518bed11.png) + + +**涓轰粈涔堜細浜х敓绮樺寘鍜屾媶鍖呭憿?** + +- 瑕佸彂閫佺殑鏁版嵁灏忎簬TCP鍙戦佺紦鍐插尯鐨勫ぇ灏忥紝TCP灏嗗娆″啓鍏ョ紦鍐插尯鐨勬暟鎹竴娆″彂閫佸嚭鍘伙紝灏嗕細鍙戠敓绮樺寘锛 +- 鎺ユ敹鏁版嵁绔殑搴旂敤灞傛病鏈夊強鏃惰鍙栨帴鏀剁紦鍐插尯涓殑鏁版嵁锛屽皢鍙戠敓绮樺寘锛 +- 瑕佸彂閫佺殑鏁版嵁澶т簬TCP鍙戦佺紦鍐插尯鍓╀綑绌洪棿澶у皬锛屽皢浼氬彂鐢熸媶鍖咃紱 +- 寰呭彂閫佹暟鎹ぇ浜嶮SS锛堟渶澶ф姤鏂囬暱搴︼級锛孴CP鍦ㄤ紶杈撳墠灏嗚繘琛屾媶鍖呫傚嵆TCP鎶ユ枃闀垮害-TCP澶撮儴闀垮害>MSS銆 + +**瑙e喅鏂规锛** + +- 鍙戦佺灏嗘瘡涓暟鎹寘灏佽涓哄浐瀹氶暱搴 +- 鍦ㄦ暟鎹熬閮ㄥ鍔犵壒娈婂瓧绗﹁繘琛屽垎鍓 +- 灏嗘暟鎹垎涓轰袱閮ㄥ垎锛屼竴閮ㄥ垎鏄ご閮紝涓閮ㄥ垎鏄唴瀹逛綋锛涘叾涓ご閮ㄧ粨鏋勫ぇ灏忓浐瀹氾紝涓旀湁涓涓瓧娈靛0鏄庡唴瀹逛綋鐨勫ぇ灏忋 + +### 鍙傝冧笌鎰熻阿 +- [TCP 鐨勯偅浜涗簨鍎匡紙涓嬶級](https://coolshell.cn/articles/11609.html "TCP 鐨勯偅浜涗簨鍎匡紙涓嬶級") +- [闈㈣瘯澶存潯浣犻渶瑕佹噦鐨 TCP 鎷ュ鎺у埗鍘熺悊](https://zhuanlan.zhihu.com/p/76023663 "闈㈣瘯澶存潯浣犻渶瑕佹噦鐨 TCP 鎷ュ鎺у埗鍘熺悊") +- [30寮犲浘瑙o細 TCP 閲嶄紶銆佹粦鍔ㄧ獥鍙c佹祦閲忔帶鍒躲佹嫢濉炴帶鍒跺彂鎰乚(https://zhuanlan.zhihu.com/p/133307545 "30寮犲浘瑙o細 TCP 閲嶄紶銆佹粦鍔ㄧ獥鍙c佹祦閲忔帶鍒躲佹嫢濉炴帶鍒跺彂鎰") +- [TCP鍗忚鐏甸瓊涔嬮棶锛屽珐鍥轰綘鐨勭綉璺簳灞傚熀纭](https://juejin.cn/post/6844904070889603085 "TCP鍗忚鐏甸瓊涔嬮棶锛屽珐鍥轰綘鐨勭綉璺簳灞傚熀纭") +- [TCP绮樺寘鍜屾媶鍖匽(https://blog.csdn.net/ailunlee/article/details/95944377 "TCP绮樺寘鍜屾媶鍖") +- 鐧惧害鐧剧 + + + From 726441dc408342ae76d78f1d738457a75094e410 Mon Sep 17 00:00:00 2001 From: whx123 <327658337@qq.com> Date: Sun, 11 Jul 2021 21:24:19 +0800 Subject: [PATCH 04/52] =?UTF-8?q?Redis=E5=BF=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...10\350\277\231\344\271\210\345\277\253.md" | 175 ++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 "Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/\347\274\223\345\255\230,Redis/Redis\344\270\272\344\273\200\344\271\210\350\277\231\344\271\210\345\277\253.md" diff --git "a/Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/\347\274\223\345\255\230,Redis/Redis\344\270\272\344\273\200\344\271\210\350\277\231\344\271\210\345\277\253.md" "b/Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/\347\274\223\345\255\230,Redis/Redis\344\270\272\344\273\200\344\271\210\350\277\231\344\271\210\345\277\253.md" new file mode 100644 index 0000000..a3f6b30 --- /dev/null +++ "b/Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/\347\274\223\345\255\230,Redis/Redis\344\270\272\344\273\200\344\271\210\350\277\231\344\271\210\345\277\253.md" @@ -0,0 +1,175 @@ + +## 鍓嶈█ + +澶у濂藉憖锛屾垜鏄崱鐢拌灪鐨勫皬鐢峰銆傛垜浠兘鐭ラ亾Redis寰堝揩锛屽畠QPS鍙揪10涓囷紙姣忕璇锋眰鏁帮級銆**Redis涓轰粈涔堣繖涔堝揩鍛**,鏈枃灏嗚窡澶у涓璧峰涔犮 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3880491879ed4a228d8f4213d987f6a3~tplv-k3u1fbpfcp-zoom-1.image) + + +- 鍏紬鍙凤細**鎹$敯铻虹殑灏忕敺瀛** +- [github鍦板潃](https://github.com/whx123/JavaHome)锛屾劅璋㈡瘡涓棰梥tar + +## 鍩轰簬鍐呭瓨瀹炵幇 + +鎴戜滑閮界煡閬撳唴瀛樿鍐欐槸姣旂鐩樿鍐欏揩寰堝鐨勩俁edis鏄熀浜庡唴瀛樺瓨鍌ㄥ疄鐜扮殑鏁版嵁搴擄紝鐩稿浜庢暟鎹瓨鍦ㄧ鐩樼殑鏁版嵁搴擄紝灏辩渷鍘荤鐩樼鐩業/O鐨勬秷鑰椼侻ySQL绛夌鐩樻暟鎹簱锛岄渶瑕佸缓绔嬬储寮曟潵鍔犲揩鏌ヨ鏁堢巼锛岃孯edis鏁版嵁瀛樻斁鍦ㄥ唴瀛橈紝鐩存帴鎿嶄綔鍐呭瓨锛屾墍浠ュ氨寰堝揩銆 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0d7be13173814a43a60960fe59a48c61~tplv-k3u1fbpfcp-zoom-1.image) + +## 楂樻晥鐨勬暟鎹粨鏋 + +鎴戜滑鐭ラ亾锛孧ySQL绱㈠紩涓轰簡鎻愰珮鏁堢巼锛岄夋嫨浜咮+鏍戠殑鏁版嵁缁撴瀯銆傚叾瀹炲悎鐞嗙殑鏁版嵁缁撴瀯锛屽氨鏄彲浠ヨ浣犵殑搴旂敤/绋嬪簭鏇村揩銆傚厛鐪嬩笅Redis鐨勬暟鎹粨鏋&鍐呴儴缂栫爜鍥撅細 + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4ddd7723cc0e4953b746b13db7a5cea3~tplv-k3u1fbpfcp-zoom-1.image) + + +### SDS绠鍗曞姩鎬佸瓧绗︿覆 + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0e68a18c50f149dda136fc9b1aa73ab8~tplv-k3u1fbpfcp-zoom-1.image) + +``` +struct sdshdr { //SDS绠鍗曞姩鎬佸瓧绗︿覆 + int len; //璁板綍buf涓凡浣跨敤鐨勭┖闂 + int free; // buf涓┖闂茬┖闂撮暱搴 + char buf[]; //瀛樺偍鐨勫疄闄呭唴瀹 +} +``` + + +#### 瀛楃涓查暱搴﹀鐞 + +鍦–璇█涓紝瑕佽幏鍙朻``鎹$敯铻虹殑灏忕敺瀛ー``杩欎釜瀛楃涓茬殑闀垮害锛岄渶瑕佷粠澶村紑濮嬮亶鍘嗭紝澶嶆潅搴︿负O锛坣锛; +鍦≧edis涓紝 宸茬粡鏈変竴涓**len**瀛楁璁板綍褰撳墠瀛楃涓茬殑闀垮害鍟︼紝鐩存帴鑾峰彇鍗冲彲锛屾椂闂村鏉傚害涓篛(1)銆 + +#### 鍑忓皯鍐呭瓨閲嶆柊鍒嗛厤鐨勬鏁 + +鍦–璇█涓紝淇敼涓涓瓧绗︿覆锛岄渶瑕侀噸鏂板垎閰嶅唴瀛橈紝淇敼瓒婇绻侊紝鍐呭瓨鍒嗛厤灏辫秺棰戠箒锛岃屽垎閰嶅唴瀛樻槸浼**娑堣楁ц兘**鐨勩傝屽湪Redis涓紝SDS鎻愪緵浜嗕袱绉嶄紭鍖栫瓥鐣ワ細绌洪棿棰勫垎閰嶅拰鎯版х┖闂撮噴鏀俱 + +**绌洪棿棰勫垎閰** + +褰揝DS绠鍗曞姩鎬佸瓧绗︿覆淇敼鍜岀┖闂存墿鍏呮椂锛岄櫎浜嗗垎閰嶅繀闇鐨勫唴瀛樼┖闂达紝杩樹細棰濆鍒嗛厤鏈娇鐢ㄧ殑绌洪棿銆傚垎閰嶈鍒欐槸閰辩传鐨勶細 + +> - SDS淇敼鍚庯紝len鐨勯暱搴﹀皬浜1M锛岄偅涔堝皢棰濆鍒嗛厤涓巐en鐩稿悓闀垮害鐨勬湭浣跨敤绌洪棿銆傛瘮濡俵en=100锛岄噸鏂板垎閰嶅悗锛宐uf 鐨勫疄闄呴暱搴︿細鍙樹负100(宸蹭娇鐢ㄧ┖闂)+100(棰濆绌洪棿)+1(绌哄瓧绗)=201銆 +> - SDS淇敼鍚, len闀垮害澶т簬1M锛岄偅涔堢▼搴忓皢鍒嗛厤1M鐨勬湭浣跨敤绌洪棿銆 + +**鎯版х┖闂撮噴鏀** + +褰揝DS缂╃煭鏃讹紝涓嶆槸鍥炴敹澶氫綑鐨勫唴瀛樼┖闂达紝鑰屾槸鐢╢ree璁板綍涓嬪浣欑殑绌洪棿銆傚悗缁啀鏈変慨鏀规搷浣滐紝鐩存帴浣跨敤free涓殑绌洪棿锛屽噺灏戝唴瀛樺垎閰嶃 + +#### 鍝堝笇 + +Redis 浣滀负涓涓狵-V鐨勫唴瀛樻暟鎹簱锛屽畠浣跨敤鐢ㄤ竴寮犲叏灞鐨勫搱甯屾潵淇濆瓨鎵鏈夌殑閿煎銆傝繖寮犲搱甯岃〃锛屾湁澶氫釜鍝堝笇妗剁粍鎴愶紝鍝堝笇妗朵腑鐨別ntry鍏冪礌淇濆瓨浜哷``*key```鍜宍``*value```鎸囬拡锛屽叾涓璥``*key```鎸囧悜浜嗗疄闄呯殑閿紝```*value```鎸囧悜浜嗗疄闄呯殑鍊笺 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/13924387cd9e4a2d96d873dba1cc3ca9~tplv-k3u1fbpfcp-zoom-1.image) + +鍝堝笇琛ㄦ煡鎵鹃熺巼寰堝揩鐨勶紝鏈夌偣绫讳技浜嶫ava涓殑**HashMap**锛屽畠璁╂垜浠湪**O(1)** 鐨勬椂闂村鏉傚害蹇熸壘鍒伴敭鍊煎銆傞鍏堥氳繃key璁$畻鍝堝笇鍊硷紝鎵惧埌瀵瑰簲鐨勫搱甯屾《浣嶇疆锛岀劧鍚庡畾浣嶅埌entry锛屽湪entry鎵惧埌瀵瑰簲鐨勬暟鎹 + +鏈変簺灏忎紮浼村彲鑳戒細鏈夌枒闂細浣犲線鍝堝笇琛ㄤ腑鍐欏叆澶ч噺鏁版嵁鏃讹紝涓嶆槸浼氶亣鍒**鍝堝笇鍐茬獊**闂鍢涳紝閭f晥鐜囧氨浼氶檷涓嬫潵鍟︺ +> **鍝堝笇鍐茬獊锛** 閫氳繃涓嶅悓鐨刱ey锛岃绠楀嚭涓鏍风殑鍝堝笇鍊硷紝瀵艰嚧钀藉湪鍚屼竴涓搱甯屾《涓 + +Redis涓轰簡瑙e喅鍝堝笇鍐茬獊锛岄噰鐢ㄤ簡**閾惧紡鍝堝笇**銆傞摼寮忓搱甯屾槸鎸囧悓涓涓搱甯屾《涓紝澶氫釜鍏冪礌鐢ㄤ竴涓摼琛ㄦ潵淇濆瓨锛屽畠浠箣闂翠緷娆$敤鎸囬拡杩炴帴銆 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/131951cd80354c24b62584d71b8fe9f9~tplv-k3u1fbpfcp-zoom-1.image) + +鏈変簺灏忎紮浼村彲鑳借繕浼氭湁鐤戦棶锛氬搱甯屽啿绐侀摼涓婄殑鍏冪礌鍙兘閫氳繃鎸囬拡閫愪竴鏌ユ壘鍐嶆搷浣溿傚綋寰鍝堝笇琛ㄦ彃鍏ユ暟鎹緢澶氾紝鍐茬獊涔熶細瓒婂锛屽啿绐侀摼琛ㄥ氨浼氳秺闀匡紝閭f煡璇㈡晥鐜囧氨浼氶檷浣庝簡銆 + +涓轰簡淇濇寔楂樻晥锛孯edis 浼氬鍝堝笇琛ㄥ仛**rehash鎿嶄綔**锛屼篃灏辨槸澧炲姞鍝堝笇妗讹紝鍑忓皯鍐茬獊銆備负浜唕ehash鏇撮珮鏁堬紝Redis杩橀粯璁や娇鐢ㄤ簡涓や釜鍏ㄥ眬鍝堝笇琛紝涓涓敤浜庡綋鍓嶄娇鐢紝绉颁负涓诲搱甯岃〃锛屼竴涓敤浜庢墿瀹癸紝绉颁负澶囩敤鍝堝笇琛ㄣ + +#### 璺宠穬琛 + +璺宠穬琛ㄦ槸Redis鐗规湁鐨勬暟鎹粨鏋勶紝瀹冨叾瀹炲氨鏄湪**閾捐〃鐨勫熀纭涓婏紝澧炲姞澶氱骇绱㈠紩**锛屼互鎻愰珮鏌ユ壘鏁堢巼銆傝烦璺冭〃鐨勭畝鍗曞師鐞嗗浘濡備笅: + +![](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0b62d59ffbd945e18f6dfcbf650a6eed~tplv-k3u1fbpfcp-watermark.image) + +- 姣忎竴灞傞兘鏈変竴鏉℃湁搴忕殑閾捐〃锛屾渶搴曞眰鐨勯摼琛ㄥ寘鍚簡鎵鏈夌殑鍏冪礌銆 +- 璺宠穬琛ㄦ敮鎸佸钩鍧 O锛坙ogN锛,鏈鍧 O锛圢锛夊鏉傚害鐨勮妭鐐规煡鎵撅紝杩樺彲浠ラ氳繃椤哄簭鎬ф搷浣滄壒閲忓鐞嗚妭鐐广 + + +#### 鍘嬬缉鍒楄〃ziplist + +鍘嬬缉鍒楄〃ziplist鏄垪琛ㄩ敭鍜屽瓧鍏搁敭鐨勭殑搴曞眰瀹炵幇涔嬩竴銆傚畠鏄敱涓绯诲垪鐗规畩缂栫爜鐨勫唴瀛樺潡鏋勬垚鐨勫垪琛紝 涓涓獄iplist鍙互鍖呭惈澶氫釜entry锛 姣忎釜entry鍙互淇濆瓨涓涓暱搴﹀彈闄愮殑瀛楃鏁扮粍鎴栬呮暣鏁帮紝濡備笅锛 + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4ce3da7cddbe4e6e94a775151664ed93~tplv-k3u1fbpfcp-zoom-1.image) + +- zlbytes 锛氳褰曟暣涓帇缂╁垪琛ㄥ崰鐢ㄧ殑鍐呭瓨瀛楄妭鏁 +- zltail: 灏捐妭鐐硅嚦璧峰鑺傜偣鐨勫亸绉婚噺 +- zllen : 璁板綍鏁翠釜鍘嬬缉鍒楄〃鍖呭惈鐨勮妭鐐规暟閲 +- entryX: 鍘嬬缉鍒楄〃鍖呭惈鐨勫悇涓妭鐐 +- zlend : 鐗规畩鍊0xFF(鍗佽繘鍒255)锛岀敤浜庢爣璁板帇缂╁垪琛ㄦ湯绔 + +鐢变簬鍐呭瓨鏄**杩炵画鍒嗛厤**鐨勶紝鎵浠ラ亶鍘嗛熷害寰堝揩銆傘 + + +## 鍚堢悊鐨勬暟鎹紪鐮 + +Redis鏀寔澶氱鏁版嵁鍩烘湰绫诲瀷锛屾瘡绉嶅熀鏈被鍨嬪搴斾笉鍚岀殑鏁版嵁缁撴瀯锛屾瘡绉嶆暟鎹粨鏋勫搴斾笉涓鏍风殑缂栫爜銆備负浜嗘彁楂樻ц兘锛孯edis璁捐鑰呮荤粨鍑猴紝鏁版嵁缁撴瀯鏈閫傚悎鐨勭紪鐮佹惌閰嶃 + +Redis鏄娇鐢ㄥ璞★紙redisObject锛夋潵琛ㄧず鏁版嵁搴撲腑鐨勯敭鍊硷紝褰撴垜浠湪 Redis 涓垱寤轰竴涓敭鍊煎鏃讹紝鑷冲皯鍒涘缓涓や釜瀵硅薄锛屼竴涓璞℃槸鐢ㄥ仛閿煎鐨勯敭瀵硅薄锛屽彟涓涓槸閿煎鐨勫煎璞° +``` +//鍏虫敞鍏紬鍙凤細鎹$敯铻虹殑灏忕敺瀛 +typedef struct redisObject{ + //绫诲瀷 + unsigned type:4; + //缂栫爜 + unsigned encoding:4; + //鎸囧悜搴曞眰鏁版嵁缁撴瀯鐨勬寚閽 + void *ptr; + //... + }robj; +``` + +redisObject涓紝**type** 瀵瑰簲鐨勬槸瀵硅薄绫诲瀷锛屽寘鍚玈tring瀵硅薄銆丩ist瀵硅薄銆丠ash瀵硅薄銆丼et瀵硅薄銆亃set瀵硅薄銆**encoding** 瀵瑰簲鐨勬槸缂栫爜銆 + +- String锛氬鏋滃瓨鍌ㄦ暟瀛楃殑璇濓紝鏄敤int绫诲瀷鐨勭紪鐮;濡傛灉瀛樺偍闈炴暟瀛楋紝灏忎簬绛変簬39瀛楄妭鐨勫瓧绗︿覆锛屾槸embstr锛涘ぇ浜39涓瓧鑺傦紝鍒欐槸raw缂栫爜銆 +- List锛氬鏋滃垪琛ㄧ殑鍏冪礌涓暟灏忎簬512涓紝鍒楄〃姣忎釜鍏冪礌鐨勫奸兘灏忎簬64瀛楄妭锛堥粯璁わ級锛屼娇鐢▃iplist缂栫爜锛屽惁鍒欎娇鐢╨inkedlist缂栫爜 +- Hash锛氬搱甯岀被鍨嬪厓绱犱釜鏁板皬浜512涓紝鎵鏈夊煎皬浜64瀛楄妭鐨勮瘽锛屼娇鐢▃iplist缂栫爜,鍚﹀垯浣跨敤hashtable缂栫爜銆 +- Set锛氬鏋滈泦鍚堜腑鐨勫厓绱犻兘鏄暣鏁颁笖鍏冪礌涓暟灏忎簬512涓紝浣跨敤intset缂栫爜锛屽惁鍒欎娇鐢╤ashtable缂栫爜銆 +- Zset锛氬綋鏈夊簭闆嗗悎鐨勫厓绱犱釜鏁板皬浜128涓紝姣忎釜鍏冪礌鐨勫煎皬浜64瀛楄妭鏃讹紝浣跨敤ziplist缂栫爜锛屽惁鍒欎娇鐢╯kiplist锛堣烦璺冭〃锛夌紪鐮 + +## 鍚堢悊鐨勭嚎绋嬫ā鍨 + + +### 鍗曠嚎绋嬫ā鍨嬶細閬垮厤浜嗕笂涓嬫枃鍒囨崲 + +Redis鏄崟绾跨▼鐨勶紝鍏跺疄鏄寚**Redis鐨勭綉缁淚O鍜岄敭鍊煎璇诲啓**鏄敱涓涓嚎绋嬫潵瀹屾垚鐨勩備絾Redis鐨勫叾浠栧姛鑳斤紝姣斿鎸佷箙鍖栥佸紓姝ュ垹闄ゃ侀泦缇ゆ暟鎹悓姝ョ瓑绛夛紝瀹為檯鏄敱棰濆鐨勭嚎绋嬫墽琛岀殑銆 + +Redis鐨勫崟绾跨▼妯″瀷锛岄伩鍏嶄簡**CPU涓嶅繀瑕佺殑涓婁笅鏂囧垏鎹**鍜**绔炰簤閿佺殑娑堣**銆備篃姝e洜涓烘槸鍗曠嚎绋嬶紝濡傛灉鏌愪釜鍛戒护鎵ц杩囬暱锛堝hgetall鍛戒护锛夛紝浼氶犳垚闃诲銆俁edis鏄潰鍚戝揩閫熸墽琛屽満鏅殑鍐呭瓨鏁版嵁搴擄紝鎵浠ヨ鎱庣敤濡俵range鍜宻members銆乭getall绛夊懡浠ゃ + +浠涔堟槸**涓婁笅鏂囧垏鎹**锛熶妇涓矡瀛愶細 + +> - 姣斿浣犲湪鐪嬩竴鏈嫳鏂囧皬璇达紝浣犵湅鍒版煇涓椤碉紝鍙戠幇鏈変釜鍗曡瘝涓嶄細璇伙紝浣犲姞浜嗕釜涔︾锛岀劧鍚庡幓鏌ュ瓧鍏搞傛煡瀹屽瓧鍏稿悗锛屼綘鍥炴潵浠庝功绛鹃偅閲岀户缁紑濮嬭锛岃繖涓祦绋嬪氨寰堣垝鐣呫 +> - 濡傛灉浣犱竴涓汉璇昏繖鏈功锛岃偗瀹氭病鍟ラ棶棰樸備絾鏄鏋滀綘鍘绘煡瀛楀吀鐨勬椂鍊欙紝鍒殑灏忎紮浼寸炕浜嗕竴涓嬩綘鐨勪功锛岀劧鍚庢簻浜嗐備綘鍐嶅洖鏉ョ湅鐨勬椂鍊欙紝鍙戠幇涔︿笉鏄綘鐪嬬殑閭d竴椤典簡锛屼綘寰楄姳鏃堕棿鎵惧埌浣犵殑閭d竴椤点 +> - 涓鏈功锛屼綘涓涓汉鎬庝箞鐪嬫庝箞鎵撴爣绛鹃兘娌′簨锛屼絾鏄汉澶氫簡缈绘潵缈诲幓锛岃繖鏈功鍚勭鏍囪灏卞緢涔变簡銆傚彲鑳借繖涓В閲婂緢绮楃硻锛屼絾鏄亾鐞嗗簲璇ユ槸涓鏍风殑銆 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/053215e73f844b8da8c2880205947fc1~tplv-k3u1fbpfcp-zoom-1.image) + +### I/O 澶氳矾澶嶇敤 + +浠涔堟槸I/O澶氳矾澶嶇敤锛 +- I/O 锛氱綉缁 I/O +- 澶氳矾 锛氬涓綉缁滆繛鎺 +- 澶嶇敤锛氬鐢ㄥ悓涓涓嚎绋嬨 +- IO澶氳矾澶嶇敤鍏跺疄灏辨槸涓绉嶅悓姝O妯″瀷锛屽畠瀹炵幇浜嗕竴涓嚎绋嬪彲浠ョ洃瑙嗗涓枃浠跺彞鏌勶紱涓鏃︽煇涓枃浠跺彞鏌勫氨缁紝灏辫兘澶熼氱煡搴旂敤绋嬪簭杩涜鐩稿簲鐨勮鍐欐搷浣滐紱鑰屾病鏈夋枃浠跺彞鏌勫氨缁椂,灏变細闃诲搴旂敤绋嬪簭锛屼氦鍑篶pu銆 + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/07838d0a48ef4b38acccb7b52e5435e1~tplv-k3u1fbpfcp-zoom-1.image) + + +> 澶氳矾I/O澶嶇敤鎶鏈彲浠ヨ鍗曚釜绾跨▼楂樻晥鐨勫鐞嗗涓繛鎺ヨ姹傦紝鑰孯edis浣跨敤鐢╡poll浣滀负I/O澶氳矾澶嶇敤鎶鏈殑瀹炵幇銆傚苟涓擱edis鑷韩鐨勪簨浠跺鐞嗘ā鍨嬪皢epoll涓殑杩炴帴銆佽鍐欍佸叧闂兘杞崲涓轰簨浠讹紝涓嶅湪缃戠粶I/O涓婃氮璐硅繃澶氱殑鏃堕棿銆 + +## 铏氭嫙鍐呭瓨鏈哄埗 + +Redis鐩存帴鑷繁鏋勫缓浜哣M鏈哄埗 锛屼笉浼氬儚涓鑸殑绯荤粺浼氳皟鐢ㄧ郴缁熷嚱鏁板鐞嗭紝浼氭氮璐逛竴瀹氱殑鏃堕棿鍘荤Щ鍔ㄥ拰璇锋眰銆 + +**Redis鐨勮櫄鎷熷唴瀛樻満鍒舵槸鍟ュ憿锛** +> 铏氭嫙鍐呭瓨鏈哄埗灏辨槸鏆傛椂鎶婁笉缁忓父璁块棶鐨勬暟鎹(鍐锋暟鎹)浠庡唴瀛樹氦鎹㈠埌纾佺洏涓紝浠庤岃吘鍑哄疂璐电殑鍐呭瓨绌洪棿鐢ㄤ簬鍏跺畠闇瑕佽闂殑鏁版嵁(鐑暟鎹)銆傞氳繃VM鍔熻兘鍙互瀹炵幇鍐风儹鏁版嵁鍒嗙锛屼娇鐑暟鎹粛鍦ㄥ唴瀛樹腑銆佸喎鏁版嵁淇濆瓨鍒扮鐩樸傝繖鏍峰氨鍙互閬垮厤鍥犱负鍐呭瓨涓嶈冻鑰岄犳垚璁块棶閫熷害涓嬮檷鐨勯棶棰樸 + +### 鍙傝冧笌鎰熻阿 + +- [Redis涔媀M鏈哄埗](https://www.codenong.com/cs106843764/) +- [涓鏂囨彮绉樺崟绾跨▼鐨凴edis涓轰粈涔堣繖涔堝揩?](https://zhuanlan.zhihu.com/p/57089960) +- [娲炲療|Redis鏄崟绾跨▼鐨勶紝浣哛edis涓轰粈涔堣繖涔堝揩锛焆(https://zhuanlan.zhihu.com/p/42272979) + + From 1b8d1314deb883bc8dcf1ba547334a82d9f0e5e7 Mon Sep 17 00:00:00 2001 From: whx123 <327658337@qq.com> Date: Sun, 11 Jul 2021 21:26:23 +0800 Subject: [PATCH 05/52] =?UTF-8?q?Redis=E5=BF=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../order by\350\257\246\350\247\243.md" | 348 ++++++++++++++++++ 1 file changed, 348 insertions(+) create mode 100644 "Mysql\345\237\272\347\241\200\345\255\246\344\271\240/order by\350\257\246\350\247\243.md" diff --git "a/Mysql\345\237\272\347\241\200\345\255\246\344\271\240/order by\350\257\246\350\247\243.md" "b/Mysql\345\237\272\347\241\200\345\255\246\344\271\240/order by\350\257\246\350\247\243.md" new file mode 100644 index 0000000..3aeda16 --- /dev/null +++ "b/Mysql\345\237\272\347\241\200\345\255\246\344\271\240/order by\350\257\246\350\247\243.md" @@ -0,0 +1,348 @@ +## 鍓嶈█ + +鏃ュ父寮鍙戜腑锛屾垜浠粡甯镐細浣跨敤鍒皁rder by锛屼翰鐖辩殑灏忎紮浼达紝浣犳槸鍚︾煡閬搊rder by 鐨勫伐浣滃師鐞嗗憿锛無rder by鐨勪紭鍖栨濊矾鏄庢牱鐨勫憿锛熶娇鐢╫rder by鏈夊摢浜涙敞鎰忕殑闂鍛紵鏈枃灏嗚窡澶у涓璧锋潵瀛︿範锛屾敾鍏媜rder by~ + + +![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3b1eda4fbc6c458c9182545d93cb6f15~tplv-k3u1fbpfcp-watermark.image) + +- 寰俊鍏紬鍙凤細**鎹$敯铻虹殑灏忕敺瀛** +- [github鍦板潃锛屾劅璋㈡瘡涓棰梥tar](https://github.com/whx123/JavaHome) +- 濡傛灉瑙夊緱鏈夋敹鑾凤紝甯繖鐐硅禐锛岃浆鍙戜笅鍝堬紝鎰熻阿鎰熻阿 + + +## 涓涓娇鐢╫rder by 鐨勭畝鍗曚緥瀛 + +鍋囪鐢ㄤ竴寮犲憳宸ヨ〃锛岃〃缁撴瀯濡備笅锛 + +``` +CREATE TABLE `staff` ( +`id` BIGINT ( 11 ) AUTO_INCREMENT COMMENT '涓婚敭id', +`id_card` VARCHAR ( 20 ) NOT NULL COMMENT '韬唤璇佸彿鐮', +`name` VARCHAR ( 64 ) NOT NULL COMMENT '濮撳悕', +`age` INT ( 4 ) NOT NULL COMMENT '骞撮緞', +`city` VARCHAR ( 64 ) NOT NULL COMMENT '鍩庡競', +PRIMARY KEY ( `id`), +INDEX idx_city ( `city` ) +) ENGINE = INNODB COMMENT '鍛樺伐琛'; + +``` + +琛ㄦ暟鎹涓嬶細 + + +![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/aadfe321a1b74141a418f4a4c2f75e82~tplv-k3u1fbpfcp-watermark.image) + +鎴戜滑鐜板湪鏈夎繖涔堜竴涓渶姹傦細**鏌ヨ鍓10涓紝鏉ヨ嚜娣卞湷鍛樺伐鐨勫鍚嶃佸勾榫勩佸煄甯傦紝骞朵笖鎸夌収骞撮緞灏忓埌澶ф帓搴**銆傚搴旂殑 SQL 璇彞灏卞彲浠ヨ繖涔堝啓锛 + +``` +select name,age,city from staff where city = '娣卞湷' order by age limit 10; +``` + +杩欐潯璇彞鐨勯昏緫寰堟竻妤氾紝浣嗘槸瀹冪殑**搴曞眰鎵ц娴佺▼**鏄庢牱鐨勫憿锛 + +## order by 宸ヤ綔鍘熺悊 + +![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/582926f8d02e44d4b94e23a3fafc0ec8~tplv-k3u1fbpfcp-watermark.image) + +### explain 鎵ц璁″垝 + +鎴戜滑鍏堢敤**Explain**鍏抽敭瀛楁煡鐪嬩竴涓嬫墽琛岃鍒 + + +![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2da79360c7204f5d8fada7f8ec2d21ba~tplv-k3u1fbpfcp-watermark.image) + +- 鎵ц璁″垝鐨**key**杩欎釜瀛楁锛岃〃绀轰娇鐢ㄥ埌绱㈠紩idx_city +- Extra 杩欎釜瀛楁鐨 **Using index condition** 琛ㄧず绱㈠紩鏉′欢 +- Extra 杩欎釜瀛楁鐨 **Using filesort**琛ㄧず鐢ㄥ埌鎺掑簭 + +鎴戜滑鍙互鍙戠幇锛岃繖鏉QL浣跨敤鍒颁簡绱㈠紩锛屽苟涓斾篃鐢ㄥ埌鎺掑簭銆傞偅涔堝畠鏄**鎬庝箞鎺掑簭**鐨勫憿锛 + +### 鍏ㄥ瓧娈垫帓搴 + +MySQL 浼氱粰姣忎釜鏌ヨ绾跨▼鍒嗛厤涓鍧楀皬**鍐呭瓨**锛岀敤浜**鎺掑簭**鐨勶紝绉颁负 **sort_buffer**銆備粈涔堟椂鍊欐妸瀛楁鏀捐繘鍘绘帓搴忓憿锛屽叾瀹炴槸閫氳繃```idx_city```绱㈠紩鎵惧埌瀵瑰簲鐨勬暟鎹紝鎵嶆妸鏁版嵁鏀捐繘鍘诲暒銆 + +鎴戜滑鍥為【涓嬬储寮曟槸鎬庝箞鎵惧埌鍖归厤鐨勬暟鎹殑锛岀幇鍦ㄥ厛鎶婄储寮曟爲鐢诲嚭鏉ュ惂锛**idx_city**绱㈠紩鏍戝涓嬶細 + + +![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/773e727c45254b7a858a780fdeff8a7c~tplv-k3u1fbpfcp-watermark.image) + +idx_city绱㈠紩鏍戯紝鍙跺瓙鑺傜偣瀛樺偍鐨勬槸**涓婚敭id**銆 杩樻湁涓妫礽d涓婚敭鑱氭棌绱㈠紩鏍戯紝鎴戜滑鍐嶇敾鍑鸿仛鏃忕储寮曟爲鍥惧惂锛 + + +![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f12ea50032b6428c899ee143663aa3de~tplv-k3u1fbpfcp-watermark.image) + + +**鎴戜滑鐨勬煡璇㈣鍙ユ槸鎬庝箞鎵惧埌鍖归厤鏁版嵁鐨勫憿**锛熷厛閫氳繃**idx_city**绱㈠紩鏍戯紝鎵惧埌瀵瑰簲鐨勪富閿甶d锛岀劧鍚庡啀閫氳繃鎷垮埌鐨勪富閿甶d锛屾悳绱**id涓婚敭绱㈠紩鏍**锛屾壘鍒板搴旂殑琛屾暟鎹 + +鍔犱笂**order by**涔嬪悗锛屾暣浣撶殑鎵ц娴佺▼灏辨槸锛 + +1. MySQL 涓哄搴旂殑绾跨▼鍒濆鍖**sort_buffer**锛屾斁鍏ラ渶瑕佹煡璇㈢殑name銆乤ge銆乧ity瀛楁锛 +2. 浠**绱㈠紩鏍慽dx_city**锛 鎵惧埌绗竴涓弧瓒 city='娣卞湷鈥欐潯浠剁殑涓婚敭 id锛屼篃灏辨槸鍥句腑鐨刬d=9锛 +3. 鍒**涓婚敭 id 绱㈠紩鏍**鎷垮埌id=9鐨勮繖涓琛屾暟鎹紝 鍙杗ame銆乤ge銆乧ity涓変釜瀛楁鐨勫硷紝瀛樺埌sort_buffer锛 +4. 浠**绱㈠紩鏍慽dx_city** 鎷垮埌涓嬩竴涓褰曠殑涓婚敭 id锛屽嵆鍥句腑鐨刬d=13锛 +5. 閲嶅姝ラ 3銆4 鐩村埌**city鐨勫间笉绛変簬娣卞湷**涓烘锛 +6. 鍓嶉潰5姝ュ凡缁忔煡鎵惧埌浜嗘墍鏈**city涓烘繁鍦**鐨勬暟鎹紝鍦 sort_buffer涓紝灏嗘墍鏈夋暟鎹牴鎹產ge杩涜鎺掑簭锛 +7. 鎸夌収鎺掑簭缁撴灉鍙栧墠10琛岃繑鍥炵粰瀹㈡埛绔 + +鎵ц绀烘剰鍥惧涓嬶細 + +![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6d8760fdf99741b492ab032cd3d0d87c~tplv-k3u1fbpfcp-watermark.image) + +灏嗘煡璇㈡墍闇鐨勫瓧娈靛叏閮ㄨ鍙栧埌sort_buffer涓紝灏辨槸**鍏ㄥ瓧娈垫帓搴**銆傝繖閲岄潰锛屾湁浜涘皬浼欎即鍙兘浼氭湁涓枒闂,鎶婃煡璇㈢殑鎵鏈夊瓧娈甸兘鏀惧埌sort_buffer锛岃宻ort_buffer鏄竴鍧楀唴瀛樻潵鐨勶紝濡傛灉鏁版嵁閲忓お澶э紝sort_buffer鏀句笉涓嬫庝箞鍔炲憿锛 + +### 纾佺洏涓存椂鏂囦欢杈呭姪鎺掑簭 + +瀹為檯涓婏紝sort_buffer鐨勫ぇ灏忔槸鐢变竴涓弬鏁版帶鍒剁殑锛**sort_buffer_size**銆傚鏋滆鎺掑簭鐨勬暟鎹皬浜巗ort_buffer_size锛屾帓搴忓湪**sort_buffer** 鍐呭瓨涓畬鎴愶紝濡傛灉瑕佹帓搴忕殑鏁版嵁澶т簬sort_buffer_size锛屽垯**鍊熷姪纾佺洏鏂囦欢鏉ヨ繘琛屾帓搴** + +濡備綍纭畾鏄惁浣跨敤浜嗙鐩樻枃浠舵潵杩涜鎺掑簭鍛紵 鍙互浣跨敤浠ヤ笅杩欏嚑涓懡浠 + +``` +## 鎵撳紑optimizer_trace锛屽紑鍚粺璁 +set optimizer_trace = "enabled=on"; +## 鎵цSQL璇彞 +select name,age,city from staff where city = '娣卞湷' order by age limit 10; +## 鏌ヨ杈撳嚭鐨勭粺璁′俊鎭 +select * from information_schema.optimizer_trace +``` + +鍙互浠 **number_of_tmp_files** 涓湅鍑猴紝鏄惁浣跨敤浜嗕复鏃舵枃浠躲 + + + +![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c876d88537ce4b67bcf8f991df17aa94~tplv-k3u1fbpfcp-watermark.image) + +**number_of_tmp_files** 琛ㄧず浣跨敤鏉ユ帓搴忕殑纾佺洏涓存椂鏂囦欢鏁般傚鏋渘umber_of_tmp_files>0锛屽垯琛ㄧず浣跨敤浜嗙鐩樻枃浠舵潵杩涜鎺掑簭銆 + +浣跨敤浜嗙鐩樹复鏃舵枃浠讹紝鏁翠釜鎺掑簭杩囩▼鍙堟槸鎬庢牱鐨勫憿锛 + +1. 浠**涓婚敭Id绱㈠紩鏍**锛屾嬁鍒伴渶瑕佺殑鏁版嵁锛屽苟鏀惧埌**sort_buffer鍐呭瓨**鍧椾腑銆傚綋sort_buffer蹇婊℃椂锛屽氨瀵箂ort_buffer涓殑鏁版嵁鎺掑簭锛屾帓瀹屽悗锛屾妸鏁版嵁涓存椂鏀惧埌纾佺洏涓涓皬鏂囦欢涓 +2. 缁х画鍥炲埌涓婚敭 id 绱㈠紩鏍戝彇鏁版嵁锛岀户缁斁鍒皊ort_buffer鍐呭瓨涓紝鎺掑簭鍚庯紝涔熸妸杩欎簺鏁版嵁鍐欏叆鍒扮鐩樹复鏃跺皬鏂囦欢涓 +3. 缁х画寰幆锛岀洿鍒板彇鍑烘墍鏈夋弧瓒虫潯浠剁殑鏁版嵁銆傛渶鍚庢妸纾佺洏鐨勪复鏃舵帓濂藉簭鐨勫皬鏂囦欢锛屽悎骞舵垚涓涓湁搴忕殑澶ф枃浠躲 + + +**TPS:** 鍊熷姪纾佺洏涓存椂灏忔枃浠舵帓搴忥紝瀹為檯涓婁娇鐢ㄧ殑鏄**褰掑苟鎺掑簭**绠楁硶銆 + +灏忎紮浼翠滑鍙兘浼氭湁涓枒闂紝鏃㈢劧**sort_buffer**鏀句笉涓嬶紝灏遍渶瑕佺敤鍒颁复鏃剁鐩樻枃浠讹紝杩欎細褰卞搷鎺掑簭鏁堢巼銆傞偅涓轰粈涔堣繕瑕佹妸鎺掑簭涓嶇浉鍏崇殑瀛楁锛坣ame锛宑ity锛夋斁鍒皊ort_buffer涓憿锛熷彧鏀炬帓搴忕浉鍏崇殑age瀛楁锛屽畠**涓嶉**鍚楋紵 鍙互浜嗚В涓**rowid 鎺掑簭**銆 + + +### rowid 鎺掑簭 + +rowid 鎺掑簭灏辨槸锛屽彧鎶婃煡璇QL**闇瑕佺敤浜庢帓搴忕殑瀛楁鍜屼富閿甶d**锛屾斁鍒皊ort_buffer涓傞偅鎬庝箞纭畾璧扮殑鏄叏瀛楁鎺掑簭杩樻槸rowid 鎺掑簭鎺掑簭鍛紵 + +瀹為檯涓婃湁涓弬鏁版帶鍒剁殑銆傝繖涓弬鏁板氨鏄**max_length_for_sort_data**锛屽畠琛ㄧずMySQL鐢ㄤ簬鎺掑簭琛屾暟鎹殑闀垮害鐨勪竴涓弬鏁帮紝濡傛灉鍗曡鐨勯暱搴﹁秴杩囪繖涓硷紝MySQL 灏辫涓哄崟琛屽お澶э紝灏辨崲rowid 鎺掑簭銆傛垜浠彲浠ラ氳繃鍛戒护鐪嬩笅杩欎釜鍙傛暟鍙栧笺 + + +``` +show variables like 'max_length_for_sort_data'; +``` + +![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ce8fc30884e74dd5b09c0028640ce7ea~tplv-k3u1fbpfcp-watermark.image) + +**max_length_for_sort_data** 榛樿鍊兼槸1024銆傚洜涓烘湰鏂囩ず渚嬩腑name,age,city闀垮害=64+4+64 =132 < 1024, 鎵浠ヨ蛋鐨勬槸鍏ㄥ瓧娈垫帓搴忋傛垜浠潵鏀逛笅杩欎釜鍙傛暟锛屾敼灏忎竴鐐癸紝 + +``` +## 淇敼鎺掑簭鏁版嵁鏈澶у崟琛岄暱搴︿负32 +set max_length_for_sort_data = 32; +## 鎵ц鏌ヨSQL +select name,age,city from staff where city = '娣卞湷' order by age limit 10; +``` + +浣跨敤rowid 鎺掑簭鐨勮瘽锛屾暣涓猄QL鎵ц娴佺▼鍙堟槸鎬庢牱鐨勫憿锛 + +1. MySQL 涓哄搴旂殑绾跨▼鍒濆鍖**sort_buffer**锛屾斁鍏ラ渶瑕佹帓搴忕殑age瀛楁锛屼互鍙婁富閿甶d锛 +2. 浠**绱㈠紩鏍慽dx_city**锛 鎵惧埌绗竴涓弧瓒 city='娣卞湷鈥欐潯浠剁殑涓婚敭 id锛屼篃灏辨槸鍥句腑鐨刬d=9锛 +3. 鍒**涓婚敭 id 绱㈠紩鏍**鎷垮埌id=9鐨勮繖涓琛屾暟鎹紝 鍙朼ge鍜屼富閿甶d鐨勫硷紝瀛樺埌sort_buffer锛 +4. 浠**绱㈠紩鏍慽dx_city** 鎷垮埌涓嬩竴涓褰曠殑涓婚敭 id锛屽嵆鍥句腑鐨刬d=13锛 +5. 閲嶅姝ラ 3銆4 鐩村埌**city鐨勫间笉绛変簬娣卞湷**涓烘锛 +6. 鍓嶉潰5姝ュ凡缁忔煡鎵惧埌浜嗘墍鏈塩ity涓烘繁鍦崇殑鏁版嵁锛屽湪 **sort_buffer**涓紝灏嗘墍鏈夋暟鎹牴鎹產ge杩涜鎺掑簭锛 +7. 閬嶅巻鎺掑簭缁撴灉锛屽彇鍓10琛岋紝骞舵寜鐓 id 鐨勫**鍥炲埌鍘熻〃**涓紝鍙栧嚭city銆乶ame 鍜 age 涓変釜瀛楁杩斿洖缁欏鎴风銆 + + +鎵ц绀烘剰鍥惧涓嬶細 + + +![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2addcf67082741e19637dae2e69ee515~tplv-k3u1fbpfcp-watermark.image) + + +瀵规瘮涓涓**鍏ㄥ瓧娈垫帓搴**鐨勬祦绋嬶紝rowid 鎺掑簭澶氫簡涓娆**鍥炶〃**銆 + +> 浠涔堟槸鍥炶〃锛熸嬁鍒颁富閿啀鍥炲埌涓婚敭绱㈠紩鏌ヨ鐨勮繃绋嬶紝灏卞彨鍋氬洖琛 + + +鎴戜滑閫氳繃**optimizer_trace**锛屽彲浠ョ湅鍒版槸鍚︿娇鐢ㄤ簡rowid鎺掑簭鐨勶細 + + +``` +## 鎵撳紑optimizer_trace锛屽紑鍚粺璁 +set optimizer_trace = "enabled=on"; +## 鎵цSQL璇彞 +select name,age,city from staff where city = '娣卞湷' order by age limit 10; +## 鏌ヨ杈撳嚭鐨勭粺璁′俊鎭 +select * from information_schema.optimizer_trace + +``` + +![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/446258ee4bfa40e6ad80596202c8d5a0~tplv-k3u1fbpfcp-watermark.image) + + +### 鍏ㄥ瓧娈垫帓搴忎笌rowid鎺掑簭瀵规瘮 + + +- 鍏ㄥ瓧娈垫帓搴忥細 sort_buffer鍐呭瓨涓嶅鐨勮瘽锛屽氨闇瑕佺敤鍒扮鐩樹复鏃舵枃浠讹紝閫犳垚**纾佺洏璁块棶**銆 +- rowid鎺掑簭锛 sort_buffer鍙互鏀炬洿澶氭暟鎹紝浣嗘槸闇瑕佸啀鍥炲埌鍘熻〃鍘诲彇鏁版嵁锛屾瘮鍏ㄥ瓧娈垫帓搴忓涓娆**鍥炶〃**銆 + +涓鑸儏鍐典笅锛屽浜嶪nnoDB瀛樺偍寮曟搸锛屼細浼樺厛浣**鐢ㄥ叏瀛楁**鎺掑簭銆傚彲浠ュ彂鐜 **max_length_for_sort_data** 鍙傛暟璁剧疆涓1024锛岃繖涓暟姣旇緝澶х殑銆備竴鑸儏鍐典笅锛屾帓搴忓瓧娈典笉浼氳秴杩囪繖涓硷紝涔熷氨鏄兘浼氳蛋**鍏ㄥ瓧娈**鎺掑簭銆 + + +## order by鐨勪竴浜涗紭鍖栨濊矾 + +鎴戜滑濡備綍浼樺寲order by璇彞鍛紵 + + +- 鍥犱负鏁版嵁鏄棤搴忕殑锛屾墍浠ュ氨闇瑕佹帓搴忋傚鏋滄暟鎹湰韬槸鏈夊簭鐨勶紝閭e氨涓嶇敤鎺掍簡銆傝岀储寮曟暟鎹湰韬槸鏈夊簭鐨勶紝鎴戜滑閫氳繃寤虹珛**鑱斿悎绱㈠紩**锛屼紭鍖杘rder by 璇彞銆 +- 鎴戜滑杩樺彲浠ラ氳繃璋冩暣**max_length_for_sort_data**绛夊弬鏁颁紭鍖栵紱 + + +### 鑱斿悎绱㈠紩浼樺寲 + +鍐嶅洖椤句笅绀轰緥SQL鐨勬煡璇㈣鍒 + +``` +explain select name,age,city from staff where city = '娣卞湷' order by age limit 10; +``` + +![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7fce894de9024dd5913e98116dca832f~tplv-k3u1fbpfcp-watermark.image) + +鎴戜滑缁欐煡璇㈡潯浠禶``city```鍜屾帓搴忓瓧娈礰``age```锛屽姞涓仈鍚堢储寮**idx_city_age**銆傚啀鍘绘煡鐪嬫墽琛岃鍒 + +``` +alter table staff add index idx_city_age(city,age); +explain select name,age,city from staff where city = '娣卞湷' order by age limit 10; +``` + +![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/33621e91730b44e5bb88c27b74614b89~tplv-k3u1fbpfcp-watermark.image) + +鍙互鍙戠幇锛屽姞涓**idx_city_age**鑱斿悎绱㈠紩锛屽氨涓嶉渶瑕**Using filesort**鎺掑簭浜嗐備负浠涔堝憿锛熷洜涓**绱㈠紩鏈韩鏄湁搴忕殑**锛屾垜浠彲浠ョ湅涓**idx_city_age**鑱斿悎绱㈠紩绀烘剰鍥撅紝濡備笅锛 + + + +![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/19b368a039a34678aeea8e297eee05e8~tplv-k3u1fbpfcp-watermark.image) + +鏁翠釜SQL鎵ц娴佺▼鍙樻垚閰辩传锛 +1. 浠庣储寮昳dx_city_age鎵惧埌婊¤冻**city='娣卞湷鈥** 鐨勪富閿 id +2. 鍒**涓婚敭 id绱㈠紩**鍙栧嚭鏁磋锛屾嬁鍒 name銆乧ity銆乤ge 涓変釜瀛楁鐨勫硷紝浣滀负缁撴灉闆嗙殑涓閮ㄥ垎鐩存帴杩斿洖 +3. 浠庣储寮**idx_city_age**鍙栦笅涓涓褰曚富閿甶d +4. 閲嶅姝ラ 2銆3锛岀洿鍒版煡鍒**绗10鏉**璁板綍锛屾垨鑰呮槸**涓嶆弧瓒砪ity='娣卞湷鈥** 鏉′欢鏃跺惊鐜粨鏉熴 + +娴佺▼绀烘剰鍥惧涓嬶細 + +![image.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/95f6a85904934d9688598d436fbcc1ee~tplv-k3u1fbpfcp-watermark.image) + + +浠庣ず鎰忓浘鐪嬫潵锛岃繕鏄湁涓娆″洖琛ㄦ搷浣溿傞拡瀵规湰娆$ず渚嬶紝鏈夋病鏈夋洿楂樻晥鐨勬柟妗堝憿锛熸湁鐨勶紝鍙互浣跨敤**瑕嗙洊绱㈠紩**锛 + +> 瑕嗙洊绱㈠紩锛氬湪鏌ヨ鐨勬暟鎹垪閲岄潰锛屼笉闇瑕佸洖琛ㄥ幓鏌ワ紝鐩存帴浠庣储寮曞垪灏辫兘鍙栧埌鎯宠鐨勭粨鏋溿傛崲鍙ヨ瘽璇达紝浣燬QL鐢ㄥ埌鐨勭储寮曞垪鏁版嵁锛岃鐩栦簡鏌ヨ缁撴灉鐨勫垪锛屽氨绠椾笂瑕嗙洊绱㈠紩浜嗐 + +鎴戜滑缁檆ity锛宯ame锛宎ge 缁勬垚涓涓仈鍚堢储寮曪紝鍗冲彲鐢ㄥ埌浜嗚鐩栫储寮曪紝杩欐椂鍊橲QL鎵ц鏃讹紝杩炲洖琛ㄦ搷浣滈兘鍙互鐪佸幓鍟︺ + +### 璋冩暣鍙傛暟浼樺寲 + +鎴戜滑杩樺彲浠ラ氳繃璋冩暣鍙傛暟锛屽幓浼樺寲order by鐨勬墽琛屻傛瘮濡傚彲浠ヨ皟鏁磗ort_buffer_size鐨勫笺傚洜涓簊ort_buffer鍊煎お灏忥紝鏁版嵁閲忓ぇ鐨勮瘽锛屼細鍊熷姪纾佺洏涓存椂鏂囦欢鎺掑簭銆傚鏋淢ySQL鏈嶅姟鍣ㄩ厤缃珮鐨勮瘽锛屽彲浠ヤ娇鐢ㄧ◢寰皟鏁村ぇ鐐广 + +鎴戜滑杩樺彲浠ヨ皟鏁磎ax_length_for_sort_data鐨勫硷紝杩欎釜鍊煎お灏忕殑璇濓紝order by浼氳蛋rowid鎺掑簭锛屼細鍥炶〃锛岄檷浣庢煡璇㈡ц兘銆傛墍浠ax_length_for_sort_data鍙互閫傚綋澶т竴鐐广 + +褰撶劧锛屽緢澶氭椂鍊欙紝杩欎簺MySQL鍙傛暟鍊硷紝鎴戜滑鐩存帴閲囩敤榛樿鍊煎氨鍙互浜嗐 + +## 浣跨敤order by 鐨勪竴浜涙敞鎰忕偣 + +### 娌℃湁where鏉′欢锛宱rder by瀛楁闇瑕佸姞绱㈠紩鍚 + +鏃ュ父寮鍙戣繃绋嬩腑锛屾垜浠彲鑳戒細閬囧埌娌℃湁where鏉′欢鐨刼rder by锛岄偅涔堬紝杩欐椂鍊檕rder by鍚庨潰鐨勫瓧娈垫槸鍚﹂渶瑕佸姞绱㈠紩鍛€傚鏈夎繖涔堜竴涓猄QL锛宑reate_time鏄惁闇瑕佸姞绱㈠紩锛 + +``` +select * from A order by create_time; +``` + +鏃犳潯浠舵煡璇㈢殑璇濓紝鍗充娇create_time涓婃湁绱㈠紩,涔熶笉浼氫娇鐢ㄥ埌銆傚洜涓篗ySQL浼樺寲鍣ㄨ涓鸿蛋鏅氫簩绾х储寮曪紝鍐嶅幓鍥炶〃鎴愭湰姣斿叏琛ㄦ壂鎻忔帓搴忔洿楂樸傛墍浠ラ夋嫨璧板叏琛ㄦ壂鎻,鐒跺悗鏍规嵁鍏ㄥ瓧娈垫帓搴忔垨鑰卹owid鎺掑簭鏉ヨ繘琛屻 + +濡傛灉鏌ヨSQL淇敼涓涓嬶細 + +``` +select * from A order by create_time limit m; +``` +- 鏃犳潯浠舵煡璇,濡傛灉m鍊艰緝灏,鏄彲浠ヨ蛋绱㈠紩鐨.鍥犱负MySQL浼樺寲鍣ㄨ涓猴紝鏍规嵁绱㈠紩鏈夊簭鎬у幓鍥炶〃鏌ユ暟鎹,鐒跺悗寰楀埌m鏉℃暟鎹,灏卞彲浠ョ粓姝㈠惊鐜,閭d箞鎴愭湰姣斿叏琛ㄦ壂鎻忓皬,鍒欓夋嫨璧颁簩绾х储寮曘 + + +### 鍒嗛〉limit杩囧ぇ鏃讹紝浼氬鑷村ぇ閲忔帓搴忔庝箞鍔? + +鍋囪SQL濡備笅锛 +``` +select * from A order by a limit 100000,10 +``` + +- 鍙互璁板綍涓婁竴椤垫渶鍚庣殑id锛屼笅涓椤垫煡璇㈡椂锛屾煡璇㈡潯浠跺甫涓奿d锛屽锛 where id > 涓婁竴椤垫渶鍚巌d limit 10銆 +- 涔熷彲浠ュ湪涓氬姟鍏佽鐨勬儏鍐典笅锛岄檺鍒堕〉鏁般 + + +### 绱㈠紩瀛樺偍椤哄簭涓巓rder by涓嶄竴鑷达紝濡備綍浼樺寲锛 + +鍋囪鏈夎仈鍚堢储寮 idx_age_name, 鎴戜滑闇姹備慨鏀逛负杩欐牱锛**鏌ヨ鍓10涓憳宸ョ殑濮撳悕銆佸勾榫勶紝骞朵笖鎸夌収骞撮緞灏忓埌澶ф帓搴忥紝濡傛灉骞撮緞鐩稿悓锛屽垯鎸夊鍚嶉檷搴忔帓**銆傚搴旂殑 SQL 璇彞灏卞彲浠ヨ繖涔堝啓锛 + +``` +select name,age from staff order by age ,name desc limit 10; +``` +鎴戜滑鐪嬩笅鎵ц璁″垝锛屽彂鐜颁娇鐢ㄥ埌**Using filesort**銆 + +![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/bdc45d41d0744567bc753892661789b7~tplv-k3u1fbpfcp-watermark.image) + +杩欐槸鍥犱负锛宨dx_age_name绱㈠紩鏍戜腑锛宎ge浠庡皬鍒板ぇ鎺掑簭锛屽鏋**age鐩稿悓锛屽啀鎸塶ame浠庡皬鍒板ぇ鎺掑簭**銆傝宱rder by 涓紝鏄寜age浠庡皬鍒板ぇ鎺掑簭锛屽鏋**age鐩稿悓锛屽啀鎸塶ame浠庡ぇ鍒板皬鎺掑簭**銆備篃灏辨槸璇达紝绱㈠紩瀛樺偍椤哄簭涓巓rder by涓嶄竴鑷淬 + +鎴戜滑鎬庝箞浼樺寲鍛紵濡傛灉MySQL鏄8.0鐗堟湰锛屾敮鎸**Descending Indexes**锛屽彲浠ヨ繖鏍蜂慨鏀圭储寮曪細 + +``` +CREATE TABLE `staff` ( + `id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT '涓婚敭id', + `id_card` varchar(20) NOT NULL COMMENT '韬唤璇佸彿鐮', + `name` varchar(64) NOT NULL COMMENT '濮撳悕', + `age` int(4) NOT NULL COMMENT '骞撮緞', + `city` varchar(64) NOT NULL COMMENT '鍩庡競', + PRIMARY KEY (`id`), + KEY `idx_age_name` (`age`,`name` desc) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8 COMMENT='鍛樺伐琛'; +``` + + +### 浣跨敤浜唅n鏉′欢澶氫釜灞炴ф椂锛孲QL鎵ц鏄惁鏈夋帓搴忚繃绋 + +濡傛灉鎴戜滑鏈**鑱斿悎绱㈠紩idx_city_name**锛屾墽琛岃繖涓猄QL鐨勮瘽锛屾槸涓嶄細璧版帓搴忚繃绋嬬殑锛屽涓嬶細 + +``` +select * from staff where city in ('娣卞湷') order by age limit 10; +``` + +![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0d5c0099035f48529075b6bc9d396cca~tplv-k3u1fbpfcp-watermark.image) + + + +浣嗘槸锛屽鏋滀娇鐢╥n鏉′欢锛屽苟涓旀湁澶氫釜鏉′欢鏃讹紝灏变細鏈夋帓搴忚繃绋嬨 + +``` + explain select * from staff where city in ('娣卞湷','涓婃捣') order by age limit 10; +``` + +![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1813404917da4dc9898ab7a14afb811f~tplv-k3u1fbpfcp-watermark.image) + +杩欐槸鍥犱负:in鏈変袱涓潯浠讹紝鍦ㄦ弧瓒虫繁鍦虫椂锛宎ge鏄帓濂藉簭鐨勶紝浣嗘槸鎶婃弧瓒充笂娴风殑age涔熷姞杩涙潵锛屽氨涓嶈兘淇濊瘉婊¤冻鎵鏈夌殑age閮芥槸鎺掑ソ搴忕殑銆傚洜姝ら渶瑕乁sing filesort銆 + +## 鏈鍚 + +- 濡傛灉瑙夊緱鏈夋敹鑾凤紝甯繖鐐硅禐锛岃浆鍙戜笅鍝堬紝鎰熻阿鎰熻阿 +- 寰俊鎼滅储鍏紬鍙凤細**鎹$敯铻虹殑灏忕敺瀛**锛屽姞涓ソ鍙嬶紝杩涙妧鏈氦娴佺兢 + + +### 鍙傝冧笌鎰熻阿 + +- MySQL瀹炴垬45璁 + + + From 46430483bac498e923f85ac4768040d32e72eff8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Sun, 10 Oct 2021 23:16:51 +0800 Subject: [PATCH 06/52] Add files via upload --- ...23\345\215\260\350\247\204\350\214\203.md" | 269 ++++++++++++++++++ 1 file changed, 269 insertions(+) create mode 100644 "\345\267\245\344\275\234\346\200\273\347\273\223/\346\227\245\345\277\227\346\211\223\345\215\260\350\247\204\350\214\203.md" diff --git "a/\345\267\245\344\275\234\346\200\273\347\273\223/\346\227\245\345\277\227\346\211\223\345\215\260\350\247\204\350\214\203.md" "b/\345\267\245\344\275\234\346\200\273\347\273\223/\346\227\245\345\277\227\346\211\223\345\215\260\350\247\204\350\214\203.md" new file mode 100644 index 0000000..4577332 --- /dev/null +++ "b/\345\267\245\344\275\234\346\200\273\347\273\223/\346\227\245\345\277\227\346\211\223\345\215\260\350\247\204\350\214\203.md" @@ -0,0 +1,269 @@ +## 前言 + +大家好,我是**捡田螺的小男孩**。日志是快速定位问题的好帮手,是**撕逼和甩锅**的利器!打印好日志非常重要。今天我们来聊聊**日志打印**的15个好建议~ + +- 公众号:**捡田螺的小男孩** + + +## 1. 选择恰当的日志级别 + +常见的日志级别有5种,分别是error、warn、info、debug、trace。日常开发中,我们需要选择恰当的日志级别,不要反手就是打印info哈~ + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c4502943568747e79ac4091b4d2868ea~tplv-k3u1fbpfcp-zoom-1.image) + +- error:错误日志,指比较严重的错误,对正常业务有影响,需要**运维配置监控的**; +- warn:警告日志,一般的错误,对业务影响不大,但是需要**开发关注**; +- info:信息日志,记录排查问题的关键信息,如调用时间、出参入参等等; +- debug:用于开发DEBUG的,关键逻辑里面的运行时数据; +- trace:最详细的信息,一般这些信息只记录到日志文件中。 + + +## 2. 日志要打印出方法的入参、出参 + +我们并不需要打印很多很多日志,只需要打印可以**快速定位问题的有效日志**。有效的日志,是甩锅的利器! + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c59f66bfc09d42ffa8528c16145952b8~tplv-k3u1fbpfcp-zoom-1.image) + +哪些算得的上**有效关键**的日志呢?比如说,方法进来的时候,打印**入参**。再然后呢,在方法返回的时候,就是**打印出参,返回值**。入参的话,一般就是**userId或者bizSeq这些关键**信息。正例如下: + +``` +public String testLogMethod(Document doc, Mode mode){ + log.debug(“method enter param:{}”,userId); + String id = "666"; + log.debug(“method exit param:{}”,id); + return id; +} +``` + + +## 3. 选择合适的日志格式 + +理想的日志格式,应当包括这些最基本的信息:如当**前时间戳**(一般毫秒精确度)、**日志级别**,**线程名字**等等。在logback日志里可以这么配置: + +``` + + + %d{HH:mm:ss.SSS} %-5level [%thread][%logger{0}] %m%n + + +``` + +如果我们的日志格式,连当前时间都沒有记录,那**连请求的时间点都不知道了**? + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6ecfebbe1a0b411e8186d46edaddbd38~tplv-k3u1fbpfcp-zoom-1.image) + + +## 4. 遇到if...else...等条件时,每个分支首行都尽量打印日志 + +当你碰到**if...else...或者switch**这样的条件时,可以在分支的首行就打印日志,这样排查问题时,就可以通过日志,确定进入了哪个分支,代码逻辑更清晰,也更方便排查问题了。 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/60bc12dfb6324c089b86a9dc05acc2f3~tplv-k3u1fbpfcp-zoom-1.image) + + +正例: +``` +if(user.isVip()){ + log.info("该用户是会员,Id:{},开始处理会员逻辑",user,getUserId()); + //会员逻辑 +}else{ + log.info("该用户是非会员,Id:{},开始处理非会员逻辑",user,getUserId()) + //非会员逻辑 +} +``` + +## 5.日志级别比较低时,进行日志开关判断 + +对于trace/debug这些比较低的日志级别,必须进行日志级别的开关判断。 + +正例: +``` +User user = new User(666L, "公众号", "捡田螺的小男孩"); +if (log.isDebugEnabled()) { + log.debug("userId is: {}", user.getId()); +} +``` + +因为当前有如下的日志代码: +``` +logger.debug("Processing trade with id: " + id + " and symbol: " + symbol); +``` + +如果**配置的日志级别是warn**的话,上述日志不会打印,但是会执行字符串拼接操作,如果```symbol```是对象, +还会执行```toString()```方法,浪费了系统资源,执行了上述操作,最终日志却没有打印,因此建议**加日志开关判断。** + +## 6. 不能直接使用日志系统(Log4j、Logback)中的 API,而是使用日志框架SLF4J中的API。 + +SLF4J 是门面模式的日志框架,有利于维护和各个类的日志处理方式统一,并且可以在保证不修改代码的情况下,很方便的实现底层日志框架的更换。 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9846b8d9ddd2485483e41b7134954f91~tplv-k3u1fbpfcp-zoom-1.image) + +正例: +``` +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +private static final Logger logger = LoggerFactory.getLogger(TianLuoBoy.class); +``` + +## 7. 建议使用参数占位{},而不是用+拼接。 + +反例: +``` +logger.info("Processing trade with id: " + id + " and symbol: " + symbol); +``` + +上面的例子中,使用```+```操作符进行字符串的拼接,有一定的**性能损耗**。 + +正例如下: +``` +logger.info("Processing trade with id: {} and symbol : {} ", id, symbol); +``` +我们使用了大括号```{}```来作为日志中的占位符,比于使用```+```操作符,更加优雅简洁。并且,**相对于反例**,使用占位符仅是替换动作,可以有效提升性能。 + +## 8. 建议使用异步的方式来输出日志。 + +- 日志最终会输出到文件或者其它输出流中的,IO性能会有要求的。如果异步,就可以显著提升IO性能。 +- 除非有特殊要求,要不然建议使用异步的方式来输出日志。以logback为例吧,要配置异步很简单,使用AsyncAppender就行 +``` + + + +``` + +## 9. 不要使用e.printStackTrace() + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e2aeaca5e0f44c08ad25fb92e75222dc~tplv-k3u1fbpfcp-zoom-1.image) + + +反例: +``` +try{ + // 业务代码处理 +}catch(Exception e){ + e.printStackTrace(); +} +``` +正例: +``` +try{ + // 业务代码处理 +}catch(Exception e){ + log.error("你的程序有异常啦",e); +} +``` + +**理由:** + +- e.printStackTrace()打印出的堆栈日志跟业务代码日志是交错混合在一起的,通常排查异常日志不太方便。 +- e.printStackTrace()语句产生的字符串记录的是堆栈信息,如果信息太长太多,字符串常量池所在的内存块没有空间了,即内存满了,那么,用户的请求就卡住啦~ + +## 10. 异常日志不要只打一半,要输出全部错误信息 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/420f0da65bac44b5b340a96facfd5c11~tplv-k3u1fbpfcp-zoom-1.image) + +反例1: + +``` +try { + //业务代码处理 +} catch (Exception e) { + // 错误 + LOG.error('你的程序有异常啦'); +} + +``` +- 异常e都没有打印出来,所以压根不知道出了什么类型的异常。 + +反例2: +``` +try { + //业务代码处理 +} catch (Exception e) { + // 错误 + LOG.error('你的程序有异常啦', e.getMessage()); +} +``` + +- ```e.getMessage()```不会记录详细的堆栈异常信息,只会记录错误基本描述信息,不利于排查问题。 + +正例: + +``` +try { + //业务代码处理 +} catch (Exception e) { + // 错误 + LOG.error('你的程序有异常啦', e); +} +``` + +## 11. 禁止在线上环境开启 debug + +禁止在线上环境开启debug,这一点非常重要。 + + +因为一般系统的debug日志会很多,并且各种框架中也大量使用 debug的日志,线上开启debug不久可能会打满磁盘,影响业务系统的正常运行。 + +## 12.不要记录了异常,又抛出异常 + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/671289ecaa4b4eb39dca1139b657f8cd~tplv-k3u1fbpfcp-zoom-1.image) + + +反例如下: +``` +log.error("IO exception", e); +throw new MyException(e); +``` + +- 这样实现的话,通常会把栈信息打印两次。这是因为捕获了MyException异常的地方,还会再打印一次。 +- 这样的日志记录,或者包装后再抛出去,不要同时使用!否则你的日志看起来会让人很迷惑。 + + +## 13.避免重复打印日志 + +避免重复打印日志,酱紫会浪费磁盘空间。如果你已经有一行日志清楚表达了意思,**避免再冗余打印**,反例如下: + +``` +if(user.isVip()){ + log.info("该用户是会员,Id:{}",user,getUserId()); + //冗余,可以跟前面的日志合并一起 + log.info("开始处理会员逻辑,id:{}",user,getUserId()); + //会员逻辑 +}else{ + //非会员逻辑 +} +``` + +如果你是使用log4j日志框架,务必在```log4j.xml```中设置 additivity=false,因为可以避免重复打印日志 + +正例: +``` + +``` + +## 14.日志文件分离 + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/12a2cbe6cf7f4ba981ba7103f9d81858~tplv-k3u1fbpfcp-zoom-1.image) + + +- 我们可以把不同类型的日志分离出去,比如access.log,或者error级别error.log,都可以单独打印到一个文件里面。 +- 当然,也可以根据不同的业务模块,打印到不同的日志文件里,这样我们排查问题和做数据统计的时候,都会比较方便啦。 + + +## 15. 核心功能模块,建议打印较完整的日志 + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c6f26259cda042edb98400145d208d12~tplv-k3u1fbpfcp-zoom-1.image) + + +- 我们日常开发中,如果核心或者逻辑复杂的代码,建议添加详细的注释,以及较详细的日志。 +- 日志要多详细呢?脑洞一下,如果你的核心程序哪一步出错了,通过日志可以定位到,那就可以啦。 + + + + + + From 93194b68365941438a9d904fa1b3e9c258f7e28a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Sun, 10 Oct 2021 23:17:47 +0800 Subject: [PATCH 07/52] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6018cc3..214c8ab 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ## 涓汉鍏紬鍙 -![image](https://user-gold-cdn.xitu.io/2019/7/28/16c381c89b127bbb?w=344&h=344&f=jpeg&s=8943) +寰俊鎼滐細鎹$敯铻虹殑灏忕敺瀛 - 濡傛灉浣犳槸涓埍瀛︿範鐨勫ソ瀛╁瓙锛屽彲浠ュ叧娉ㄦ垜鍏紬鍙凤紝涓璧峰涔犺璁哄搱~~ From 6cd2682a3f262f88a9db736c5402df01c6aefc20 Mon Sep 17 00:00:00 2001 From: whx123 <327658337@qq.com> Date: Mon, 6 Jun 2022 08:23:10 +0800 Subject: [PATCH 08/52] mhouduansiwei --- ...36\344\270\252\351\224\246\345\233\212.md" | 540 ++++++++++++++++ ...03\347\224\250\346\250\241\346\235\277.md" | 599 ++++++++++++++++++ 2 files changed, 1139 insertions(+) create mode 100644 "\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207/\345\220\216\347\253\257\346\200\235\347\273\264\344\270\200\357\274\232\350\256\276\350\256\241\346\216\245\345\217\243\347\232\20436\344\270\252\351\224\246\345\233\212.md" create mode 100644 "\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207\344\272\214\357\274\232\346\211\213\346\212\212\346\211\213\346\225\231\344\275\240\345\256\236\347\216\260\344\270\200\344\270\252\345\271\266\350\241\214\350\260\203\347\224\250\346\250\241\346\235\277.md" diff --git "a/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207/\345\220\216\347\253\257\346\200\235\347\273\264\344\270\200\357\274\232\350\256\276\350\256\241\346\216\245\345\217\243\347\232\20436\344\270\252\351\224\246\345\233\212.md" "b/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207/\345\220\216\347\253\257\346\200\235\347\273\264\344\270\200\357\274\232\350\256\276\350\256\241\346\216\245\345\217\243\347\232\20436\344\270\252\351\224\246\345\233\212.md" new file mode 100644 index 0000000..f999d6b --- /dev/null +++ "b/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207/\345\220\216\347\253\257\346\200\235\347\273\264\344\270\200\357\274\232\350\256\276\350\256\241\346\216\245\345\217\243\347\232\20436\344\270\252\351\224\246\345\233\212.md" @@ -0,0 +1,540 @@ +## 前言 + +大家好,我是捡田螺的小男孩。作为后端开发,不管是什么语言,```Java```、```Go```还是```C++```,其背后的后端思想都是类似的。后面打算出一个后端思想的技术专栏,主要包括后端的一些设计、或者后端规范相关的,希望对大家日常工作有帮助哈。 + +我们做后端开发工程师,主要工作就是:**如何把一个接口设计好**。所以,今天就给大家介绍,设计好接口的36个锦囊。本文就是后端思想专栏的第一篇哈。 + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1bfc8123cee34de2ad82b736121165d2~tplv-k3u1fbpfcp-zoom-1.image) + +- 公众号:捡田螺的小男孩 + + +## 1. 接口参数校验 + +入参出参校验是每个程序员必备的基本素养。你设计的接口,必须先校验参数。比如入参是否允许为空,入参长度是否符合你的预期长度。这个要养成习惯哈,日常开发中,很多低级bug都是不校验参数导致的。 + +> 比如你的数据库表字段设置为```varchar(16)```,对方传了一个32位的字符串过来,如果你不校验参数,**插入数据库直接异常了**。 + +出参也是,比如你定义的接口报文,参数是不为空的,但是你的接口返回参数,没有做校验,因为程序某些原因,直返回别人一个```null```值。。。 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/bfd3392f3ce6408daa1940cc185f0d5f~tplv-k3u1fbpfcp-zoom-1.image) + +## 2. 修改老接口时,注意接口的兼容性 + +很多bug都是因为修改了对外旧接口,但是却**不做兼容**导致的。关键这个问题多数是比较严重的,可能直接导致系统发版失败的。新手程序员很容易犯这个错误哦~ + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/701ac23b5dd04149b277c4001721fb87~tplv-k3u1fbpfcp-zoom-1.image) + +所以,如果你的需求是在原来接口上修改,尤其这个接口是对外提供服务的话,一定要考虑接口兼容。举个例子吧,比如dubbo接口,原本是只接收A,B参数,现在你加了一个参数C,就可以考虑这样处理: + +``` +//老接口 +void oldService(A,B){ + //兼容新接口,传个null代替C + newService(A,B,null); +} + +//新接口,暂时不能删掉老接口,需要做兼容。 +void newService(A,B,C){ + ... +} +``` + +## 3. 设计接口时,充分考虑接口的可扩展性 + +要根据实际业务场景设计接口,充分考虑接口的可扩展性。 + +比如你接到一个需求:是用户添加或者修改员工时,需要刷脸。那你是反手提供一个员工管理的提交刷脸信息接口?还是先思考:提交刷脸是不是通用流程呢?比如转账或者一键贴现需要接入刷脸的话,你是否需要重新实现一个接口呢?还是当前按业务类型划分模块,复用这个接口就好,保留接口的可扩展性。 + +如果按模块划分的话,未来如果其他场景比如一键贴现接入刷脸的话,不用再搞一套新的接口,只需要新增枚举,然后复用刷脸通过流程接口,实现一键贴现刷脸的差异化即可。 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cd3ee52ecaa34de384bb529cbb358889~tplv-k3u1fbpfcp-zoom-1.image) + + +## 4.接口考虑是否需要防重处理 + +如果前端重复请求,你的逻辑如何处理?是不是考虑接口去重处理。 + +当然,如果是查询类的请求,其实不用防重。如果是更新修改类的话,尤其金融转账类的,就要过滤重复请求了。简单点,你可以使用Redis防重复请求,同样的请求方,一定时间间隔内的相同请求,考虑是否过滤。当然,转账类接口,并发不高的话,**推荐使用数据库防重表**,以**唯一流水号作为主键或者唯一索引**。 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/059928f565ba4d27a17c54f451b0235d~tplv-k3u1fbpfcp-zoom-1.image) + + +## 5. 重点接口,考虑线程池隔离。 + +一些登陆、转账交易、下单等重要接口,考虑线程池隔离哈。如果你所有业务都共用一个线程池,有些业务出bug导致线程池阻塞打满的话,那就杯具了,**所有业务都影响了**。因此进行线程池隔离,重要业务分配多一点的核心线程,就更好保护重要业务。 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1d30804afc044026b4eb7bad23689c42~tplv-k3u1fbpfcp-zoom-1.image) + + +## 6. 调用第三方接口要考虑异常和超时处理 + +如果你调用第三方接口,或者分布式远程服务的的话,需要考虑: + +- 异常处理 + +> 比如,你调别人的接口,如果异常了,怎么处理,是重试还是当做失败还是告警处理。 + +- 接口超时 + +> 没法预估对方接口一般多久返回,一般设置个超时断开时间,以保护你的接口。**之前见过一个生产问题**,就是http调用不设置超时时间,最后响应方进程假死,请求一直占着线程不释放,拖垮线程池。 + +- 重试次数 +> 你的接口调失败,需不需要重试?重试几次?需要站在业务上角度思考这个问题 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/25ec61c10c324ada9252745fa4017ad6~tplv-k3u1fbpfcp-zoom-1.image) + + +## 7. 接口实现考虑熔断和降级 + +当前互联网系统一般都是分布式部署的。而分布式系统中经常会出现某个基础服务不可用,最终导致整个系统不可用的情况, 这种现象被称为**服务雪崩效应**。 + +比如分布式调用链路```A->B->C....```,下图所示: + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/65240791c94c44b6aab143178eeb790c~tplv-k3u1fbpfcp-zoom-1.image) + +> 如果服务C出现问题,比如是**因为慢SQL导致调用缓慢**,那将导致B也会延迟,从而A也会延迟。堵住的A请求会消耗占用系统的线程、IO等资源。 当请求A的服务越来越多,占用计算机的资源也越来越多,最终会导致系统瓶颈出现,造成其他的请求同样不可用,最后导致业务系统崩溃。 + +为了应对服务雪崩, 常见的做法是**熔断和降级**。最简单是加开关控制,当下游系统出问题时,开关降级,不再调用下游系统。还可以选用开源组件```Hystrix```。 + +## 8. 日志打印好,接口的关键代码,要有日志保驾护航。 + +关键业务代码无论身处何地,都应该有足够的日志保驾护航。 +比如:你实现转账业务,转个几百万,然后转失败了,接着客户投诉,然后你还没有打印到日志,想想那种水深火热的困境下,你却毫无办法。。。 + +那么,你的转账业务都需要那些日志信息呢?至少,方法调用前,入参需要打印需要吧,接口调用后,需要捕获一下异常吧,同时打印异常相关日志吧,如下: +``` +public void transfer(TransferDTO transferDTO){ + log.info("invoke tranfer begin"); + //打印入参 + log.info("invoke tranfer,paramters:{}",transferDTO); + try { + res= transferService.transfer(transferDTO); + }catch(Exception e){ + log.error("transfer fail,account:{}", + transferDTO.getAccount()) + log.error("transfer fail,exception:{}",e); + } + log.info("invoke tranfer end"); + } +``` + +之前写过一篇打印日志的15个建议,大家可以看看哈:[工作总结!日志打印的15个建议](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247494838&idx=1&sn=cdb15fd346bddf3f8c1c99f0efbd67d8&chksm=cf22339ff855ba891616c79d4f4855e228e34a9fb45088d7acbe421ad511b8d090a90f5b019f&token=162724582&lang=zh_CN&scene=21#wechat_redirect) + +## 9. 接口的功能定义要具备单一性 + +单一性是指接口做的事情比较单一、专一。比如一个登陆接口,它做的事情就只是校验账户名密码,然后返回登陆成功以及```userId```即可。**但是如果你为了减少接口交互,把一些注册、一些配置查询等全放到登陆接口,就不太妥。** + +其实这也是微服务一些思想,接口的功能单一、明确。比如订单服务、积分、商品信息相关的接口都是划分开的。将来拆分微服务的话,是不是就比较简便啦。 + + +## 10.接口有些场景,使用异步更合理 + +举个简单的例子,比如你实现一个用户注册的接口。用户注册成功时,发个邮件或者短信去通知用户。这个邮件或者发短信,就更适合异步处理。因为总不能一个通知类的失败,导致注册失败吧。 + +至于做异步的方式,简单的就是**用线程池**。还可以使用消息队列,就是用户注册成功后,生产者产生一个注册成功的消息,消费者拉到注册成功的消息,就发送通知。 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/585b098a67b349d495e6e8579ea85e4c~tplv-k3u1fbpfcp-zoom-1.image) + + +不是所有的接口都适合设计为同步接口。比如你要做一个转账的功能,如果你是单笔的转账,你是可以把接口设计同步。用户发起转账时,客户端在静静等待转账结果就好。如果你是批量转账,一个批次一千笔,甚至一万笔的,你则可以把接口设计为异步。就是用户发起批量转账时,持久化成功就先返回受理成功。然后用户隔十分钟或者十五分钟等再来查转账结果就好。又或者,批量转账成功后,再回调上游系统。 + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1ae74868492344c4bcbab9b480904c47~tplv-k3u1fbpfcp-zoom-1.image) + + +## 11. 优化接口耗时,远程串行考虑改并行调用 + +假设我们设计一个APP首页的接口,它需要查用户信息、需要查banner信息、需要查弹窗信息等等。那你是一个一个接口串行调,还是并行调用呢? + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d118e2b09e1f4fc6a1003fd44a43e4c7~tplv-k3u1fbpfcp-zoom-1.image) + +如果是串行一个一个查,比如查用户信息200ms,查banner信息100ms、查弹窗信息50ms,那一共就耗时```350ms```了,如果还查其他信息,那耗时就更大了。这种场景是可以改为并行调用的。也就是说查用户信息、查banner信息、查弹窗信息,可以同时发起。 + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/83561366219b48a2a85a6bb0419f82a3~tplv-k3u1fbpfcp-zoom-1.image) + +在Java中有个异步编程利器:```CompletableFuture```,就可以很好实现这个功能。有兴趣的小伙伴可以看我之前这个文章哈:[CompletableFuture详解](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490456&idx=1&sn=95836324db57673a4d7aea4fb233c0d2&chksm=cf21c4b1f8564da72dc7b39279362bcf965b1374540f3b339413d138599f7de59a5f977e3b0e&token=1260947715&lang=zh_CN#rd) + +## 12. 接口合并或者说考虑批量处理思想 + +数据库操作或或者是远程调用时,能批量操作就不要for循环调用。 +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/855cd5cf57d047be909dbc41ddacc021~tplv-k3u1fbpfcp-zoom-1.image) + +一个简单例子,我们平时一个列表明细数据插入数据库时,不要在for循环一条一条插入,建议一个批次几百条,进行批量插入。同理远程调用也类似想法,比如你查询营销标签是否命中,可以一个标签一个标签去查,也可以批量标签去查,那批量进行,效率就更高嘛。 + +``` +//反例 +for(int i=0;i 比如一些平时变动很小或者说几乎不会变的商品信息,可以放到缓存,请求过来时,先查询缓存,如果没有再查数据库,并且把数据库的数据更新到缓存。但是,使用缓存增加了需要考虑这些点:缓存和数据库一致性如何保证、集群、缓存击穿、缓存雪奔、缓存穿透等问题。 + +- 保证数据库和缓存一致性:**缓存延时双删、删除缓存重试机制、读取biglog异步删除缓存** +- 缓存击穿:设置数据永不过期 +- 缓存雪奔:Redis集群高可用、均匀设置过期时间 +- 缓存穿透:接口层校验、查询为空设置个默认空值标记、布隆过滤器。 + +一般用```Redis```分布式缓存,当然有些时候也可以考虑使用本地缓存,如```Guava Cache、Caffeine```等。使用本地缓存有些缺点,就是无法进行大数据存储,并且应用进程的重启,缓存会失效。 + +## 14. 接口考虑热点数据隔离性 + +瞬时间的高并发,可能会打垮你的系统。可以做一些热点数据的隔离。比如**业务隔离、系统隔离、用户隔离、数据隔离**等。 + +- 业务隔离性,比如12306的分时段售票,将热点数据分散处理,降低系统负载压力。 +- 系统隔离:比如把系统分成了用户、商品、社区三个板块。这三个块分别使用不同的域名、服务器和数据库,做到从接入层到应用层再到数据层三层完全隔离。 +- 用户隔离:重点用户请求到配置更好的机器。 +- 数据隔离:使用单独的缓存集群或者数据库服务热点数据。 + +## 15. 可变参数配置化,比如红包皮肤切换等 + +假如产品经理提了个红包需求,圣诞节的时候,红包皮肤为圣诞节相关的,春节的时候,为春节红包皮肤等。 + +如果在代码写死控制,可有类似以下代码: +``` +if(duringChristmas){ + img = redPacketChristmasSkin; +}else if(duringSpringFestival){ + img = redSpringFestivalSkin; +} +``` +如果到了元宵节的时候,运营小姐姐突然又有想法,红包皮肤换成灯笼相关的,这时候,是不是要去修改代码了,重新发布了? + +从一开始接口设计时,可以实现**一张红包皮肤的配置表**,将红包皮肤做成配置化呢?更换红包皮肤,只需修改一下表数据就好了。 + +当然,还有一些场景适合一些配置化的参数:一个分页多少数量控制、某个抢红包多久时间过期这些,都可以搞到参数配置化表里面。**这也是扩展性思想的一种体现。** + +## 16.接口考虑幂等性 + +接口是需要考虑幂等性的,尤其抢红包、转账这些重要接口。最直观的业务场景,就是**用户连着点击两次**,你的接口有没有**hold住**。或者消息队列出现重复消费的情况,你的业务逻辑怎么控制? + +回忆下,**什么是幂等?** + +> 计算机科学中,幂等表示一次和多次请求某一个资源应该具有同样的副作用,或者说,多次请求所产生的影响与一次请求执行的影响效果相同。 + +大家别搞混哈,**防重和幂等设计其实是有区别的**。防重主要为了避免产生重复数据,把重复请求拦截下来即可。而幂等设计除了拦截已经处理的请求,还要求每次相同的请求都返回一样的效果。不过呢,很多时候,它们的处理流程、方案是类似的哈。 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f8c3d0d5a653455198ba3259ef221387~tplv-k3u1fbpfcp-zoom-1.image) + + +接口幂等实现方案主要有8种: + +- select+insert+主键/唯一索引冲突 +- 直接insert + 主键/唯一索引冲突 +- 状态机幂等 +- 抽取防重表 +- token令牌 +- 悲观锁 +- 乐观锁 +- 分布式锁 + +大家可以看我这篇文章哈:[聊聊幂等设计](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497427&idx=1&sn=2ed160c9917ad989eee1ac60d6122855&chksm=cf2229faf855a0ecf5eb34c7335acdf6420426490ee99fc2b602d54ff4ffcecfdab24eeab0a3&token=1260947715&lang=zh_CN#rd) + +## 17. 读写分离,优先考虑读从库,注意主从延迟问题 + +我们的数据库都是集群部署的,有主库也有从库,当前一般都是读写分离的。比如你写入数据,肯定是写入主库,但是对于读取实时性要求不高的数据,则优先考虑读从库,因为可以分担主库的压力。 + +如果读取从库的话,需要考虑主从延迟的问题。 + +## 18.接口注意返回的数据量,如果数据量大需要分页 + +一个接口返回报文,不应该包含过多的数据量。过多的数据量不仅处理复杂,并且数据量传输的压力也非常大。因此数量实在是比较大,可以分页返回,如果是功能不相关的报文,那应该考虑接口拆分。 + +## 19. 好的接口实现,离不开SQL优化 + +我们做后端的,写好一个接口,离不开SQL优化。 + +SQL优化从这几个维度思考: + +- explain 分析SQL查询计划(重点关注type、extra、filtered字段) +- show profile分析,了解SQL执行的线程的状态以及消耗的时间 +- 索引优化 (覆盖索引、最左前缀原则、隐式转换、order by以及group by的优化、join优化) +- 大分页问题优化(延迟关联、记录上一页最大ID) +- 数据量太大(**分库分表**、同步到es,用es查询) + +## 20.代码锁的粒度控制好 + +什么是加锁粒度呢? + +> 其实就是就是你要锁住的范围是多大。比如你在家上卫生间,你只要锁住卫生间就可以了吧,不需要将整个家都锁起来不让家人进门吧,卫生间就是你的加锁粒度。 + +我们写代码时,如果不涉及到共享资源,就没有必要锁住的。这就好像你上卫生间,不用把整个家都锁住,锁住卫生间门就可以了。 + +比如,在业务代码中,有一个ArrayList因为涉及到多线程操作,所以需要加锁操作,假设刚好又有一段比较耗时的操作(代码中的```slowNotShare```方法)不涉及线程安全问题,你会如何加锁呢? + +反例: +``` +//不涉及共享资源的慢方法 +private void slowNotShare() { + try { + TimeUnit.MILLISECONDS.sleep(100); + } catch (InterruptedException e) { + } +} + +//错误的加锁方法 +public int wrong() { + long beginTime = System.currentTimeMillis(); + IntStream.rangeClosed(1, 10000).parallel().forEach(i -> { + //加锁粒度太粗了,slowNotShare其实不涉及共享资源 + synchronized (this) { + slowNotShare(); + data.add(i); + } + }); + log.info("cosume time:{}", System.currentTimeMillis() - beginTime); + return data.size(); +} +``` + +正例: +``` +public int right() { + long beginTime = System.currentTimeMillis(); + IntStream.rangeClosed(1, 10000).parallel().forEach(i -> { + slowNotShare();//可以不加锁 + //只对List这部分加锁 + synchronized (data) { + data.add(i); + } + }); + log.info("cosume time:{}", System.currentTimeMillis() - beginTime); + return data.size(); +} +``` + +## 21.接口状态和错误需要统一明确 + +提供必要的接口调用状态信息。比如你的一个转账接口调用是成功、失败、处理中还是受理成功等,需要明确告诉客户端。如果接口失败,那么具体失败的原因是什么。这些必要的信息都必须要告诉给客户端,因此需要定义明确的错误码和对应的描述。同时,尽量对报错信息封装一下,不要把后端的异常信息完全抛出到客户端。 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/20a1080126274c04aa31802178c01bb0~tplv-k3u1fbpfcp-zoom-1.image) + + +## 22.接口要考虑异常处理 + +实现一个好的接口,离不开优雅的异常处理。对于异常处理,提十个小建议吧: + +- 尽量不要使用```e.printStackTrace()```,而是使用```log```打印。因为```e.printStackTrace()```语句可能会导致内存占满。 +- ```catch```住异常时,建议打印出具体的```exception```,利于更好定位问题 +- 不要用一个```Exception```捕捉所有可能的异常 +- 记得使用```finally```关闭流资源或者直接使用```try-with-resource``` +- 捕获异常与抛出异常必须是完全匹配,或者捕获异常是抛异常的父类 +- 捕获到的异常,不能忽略它,至少打点日志吧 +- 注意异常对你的代码层次结构的侵染 +- 自定义封装异常,不要丢弃原始异常的信息```Throwable cause``` +- 运行时异常```RuntimeException``` ,不应该通过```catch```的方式来处理,而是先预检查,比如:```NullPointerException```处理 +- 注意异常匹配的顺序,优先捕获具体的异常 + +小伙伴们有兴趣可以看下我之前写的这篇文章哈:[Java 异常处理的十个建议](https://mp.weixin.qq.com/s/3mqY77c8iXWvJFzkVQi9Og) + +## 23. 优化程序逻辑 + +优化程序逻辑这块还是挺重要的,也就是说,你实现的业务代码,**如果是比较复杂的话,建议把注释写清楚**。还有,代码逻辑尽量清晰,代码尽量高效。 + +> 比如,你要使用用户信息的属性,你根据session已经获取到```userId```了,然后就把用户信息从数据库查询出来,使用完后,后面可能又要用到用户信息的属性,有些小伙伴没想太多,反手就把```userId```再传进去,再查一次数据库。。。我在项目中,见过这种代码。。。直接把用户对象传下来不好嘛。。 + +反例伪代码: + +``` +public Response test(Session session){ + UserInfo user = UserDao.queryByUserId(session.getUserId()); + + if(user==null){ + reutrn new Response(); + } + + return do(session.getUserId()); +} + +public Response do(String UserId){ + //多查了一次数据库 + UserInfo user = UserDao.queryByUserId(session.getUserId()); + ...... + return new Response(); +} + +``` + +正例: + +``` +public Response test(Session session){ + UserInfo user = UserDao.queryByUserId(session.getUserId()); + + if(user==null){ + reutrn new Response(); + } + + return do(session.getUserId()); +} + +//直接传UserInfo对象过来即可,不用再多查一次数据库 +public Response do(UserInfo user){ + ...... + return new Response(); +} +``` + +当然,这只是一些很小的一个例子,还有很多类似的例子,需要大家开发过程中,多点思考的哈。 + + +## 24. 接口实现过程汇中,注意大文件、大事务、大对象 + +- 读取大文件时,不要```Files.readAllBytes```直接读取到内存,这样会OOM的,建议使用```BufferedReader```一行一行来。 +- 大事务可能导致死锁、回滚时间长、主从延迟等问题,开发中尽量避免大事务。 +- 注意一些大对象的使用,因为大对象是直接进入老年代的,会触发fullGC + +## 25. 你的接口,需要考虑限流 + +如果你的系统每秒扛住的请求是1000,如果一秒钟来了十万请求呢?换个角度就是说,高并发的时候,流量洪峰来了,超过系统的承载能力,怎么办呢? + +如果不采取措施,所有的请求打过来,系统CPU、内存、Load负载飚的很高,最后请求处理不过来,所有的请求无法正常响应。 + +针对这种场景,我们可以采用限流方案。就是为了保护系统,多余的请求,直接丢弃。 + +限流定义: +> 在计算机网络中,限流就是控制网络接口发送或接收请求的速率,它可防止DoS攻击和限制Web爬虫。限流,也称流量控制。是指系统在面临高并发,或者大流量请求的情况下,限制新的请求对系统的访问,从而保证系统的稳定性。 + +可以使用Guava的```RateLimiter```单机版限流,也可以使用```Redis```分布式限流,还可以使用阿里开源组件```sentinel```限流 + +大家可以看下我之前这篇文章哈:[4种经典限流算法讲解](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490393&idx=1&sn=98189caa486406f8fa94d84ba0667604&chksm=cf21c470f8564d665ce04ccb9dc7502633246da87a0541b07ba4ac99423b28ce544cdd6c036b&token=162724582&lang=zh_CN&scene=21#wechat_redirect) + + +## 26.代码实现时,注意运行时异常(比如空指针、下标越界等) + +日常开发中,我们需要采取措施**规避数组边界溢出,被零整除,空指针**等运行时错误。类似代码比较常见: +``` +String name = list.get(1).getName(); //list可能越界,因为不一定有2个元素哈 +``` + +应该采取措施,预防一下数组边界溢出。正例如下: +``` +if(CollectionsUtil.isNotEmpty(list)&& list.size()>1){ + String name = list.get(1).getName(); +} +``` +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/10199365140845ea8f7b29a07fbaf3cc~tplv-k3u1fbpfcp-zoom-1.image) + + +## 27.保证接口安全性 + +如果你的API接口是对外提供的,需要保证接口的安全性。保证接口的安全性有**token机制和接口签名**。 + +**token机制身份验证**方案还比较简单的,就是 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9b468f89cdaf4040b84e432182903fd9~tplv-k3u1fbpfcp-zoom-1.image) + +1. 客户端发起请求,申请获取token。 +2. 服务端生成全局唯一的token,保存到redis中(一般会设置一个过期时间),然后返回给客户端。 +3. 客户端带着token,发起请求。 +4. 服务端去redis确认token是否存在,一般用 redis.del(token)的方式,如果存在会删除成功,即处理业务逻辑,如果删除失败不处理业务逻辑,直接返回结果。 + +**接口签名**的方式,就是把接口请求相关信息(请求报文,包括请求时间戳、版本号、appid等),客户端私钥加签,然后服务端用公钥验签,验证通过才认为是合法的、没有被篡改过的请求。 + +有关于加签验签的,大家可以看下我这篇文章哈:[程序员必备基础:加签验签](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488022&idx=1&sn=70484a48173d36006c8db1dfb74ab64d&chksm=cf21cd3ff8564429a1205f6c1d78757faae543111c8461d16c71aaee092fe3e0fed870cc5e0e&token=162724582&lang=zh_CN&scene=21#wechat_redirect) + +处了**加签验签和token机制,接口报文一般是要加密的**。当然,用https协议是会对报文加密的。如果是我们服务层的话,如何加解密呢? +> 可以参考HTTPS的原理,就是服务端把公钥给客户端,然后客户端生成对称密钥,接着客户端用服务端的公钥加密对称密钥,再发到服务端,服务端用自己的私钥解密,得到客户端的对称密钥。这时候就可以愉快传输报文啦,客户端用**对称密钥加密请求报文**,**服务端用对应的对称密钥解密报文**。 + +有时候,接口的安全性,还包括**手机号、身份证等信息的脱敏**。就是说,**用户的隐私数据,不能随便暴露**。 + +## 28.分布式事务,如何保证 + +> 分布式事务:就是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。简单来说,分布式事务指的就是分布式系统中的事务,它的存在就是为了保证不同数据库节点的数据一致性。 + +分布式事务的几种解决方案: +- 2PC(二阶段提交)方案、3PC +- TCC(Try、Confirm、Cancel) +- 本地消息表 +- 最大努力通知 +- seata + +大家可以看下这篇文章哈:[看一遍就理解:分布式事务详解](https://mp.weixin.qq.com/s/3r9MfIz2RAtdFhYzwwZxjA) + +## 29. 事务失效的一些经典场景 + +我们的接口开发过程中,经常需要使用到事务。所以需要避开事务失效的一些经典场景。 + +- 方法的访问权限必须是public,其他private等权限,事务失效 +- 方法被定义成了final的,这样会导致事务失效。 +- 在同一个类中的方法直接内部调用,会导致事务失效。 +- 一个方法如果没交给spring管理,就不会生成spring事务。 +- 多线程调用,两个方法不在同一个线程中,获取到的数据库连接不一样的。 +- 表的存储引擎不支持事务 +- 如果自己try...catch误吞了异常,事务失效。 +- 错误的传播特性 + +推荐大家看下这篇文章:[聊聊spring事务失效的12种场景,太坑了](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247494570&idx=2&sn=17357bcd328b2d1d83f4a72c47daac1b&chksm=cf223483f855bd95351a778d5f48ddd37917ce2790ebbbcd1d6ee4f27f7f4b147f0d41101dcc&token=2044040586&lang=zh_CN&scene=21#wechat_redirect) + + +## 30. 掌握常用的设计模式 + +把代码写好,还是需要熟练常用的设计模式,比如策略模式、工厂模式、模板方法模式、观察者模式等等。设计模式,是代码设计经验的总结。使用设计模式可以可重用代码、让代码更容易被他人理解、保证代码可靠性。 + +我之前写过一篇总结工作中常用设计模式的文章,写得挺不错的,大家可以看下:[实战!工作中常用到哪些设计模式](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247495616&idx=1&sn=e74c733d26351eab22646e44ea74d233&chksm=cf2230e9f855b9ffe1ddb9fe15f72a273d5de02ed91cc97f3066d4162af027299718e2bf748e&token=1260947715&lang=zh_CN#rd) + +## 31. 写代码时,考虑线性安全问题 + +在**高并发**情况下,```HashMap```可能会出现死循环。因为它是非线性安全的,可以考虑使用```ConcurrentHashMap```。所以这个也尽量养成习惯,不要上来反手就是一个```new HashMap()```; + +> - Hashmap、Arraylist、LinkedList、TreeMap等都是线性不安全的; +> - Vector、Hashtable、ConcurrentHashMap等都是线性安全的 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1ba0cab945874264a8d8e87b7d7c4a1b~tplv-k3u1fbpfcp-zoom-1.image) + + +## 32.接口定义清晰易懂,命名规范。 + +我们写代码,不仅仅是为了实现当前的功能,也要有利于后面的维护。说到维护,代码不仅仅是写给自己看的,也是给别人看的。所以接口定义要清晰易懂,命名规范。 + +## 33. 接口的版本控制 + +接口要做好版本控制。就是说,请求基础报文,应该包含```version```接口版本号字段,方便未来做接口兼容。其实这个点也算接口扩展性的一个体现点吧。 + +比如客户端APP某个功能优化了,新老版本会共存,这时候我们的```version```版本号就派上用场了,对```version```做升级,做好版本控制。 + +## 34. 注意代码规范问题 + +注意一些常见的代码坏味道: +- 大量重复代码(抽公用方法,设计模式) +- 方法参数过多(可封装成一个DTO对象) +- 方法过长(抽小函数) +- 判断条件太多(优化if...else) +- 不处理没用的代码 +- 不注重代码格式 +- 避免过度设计 + +代码的坏味道,这里我都写到啦:[25种代码坏味道总结+优化示例](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490148&idx=1&sn=00a181bf74313f751b3ea15ebc303545&chksm=cf21c54df8564c5bc5b4600fce46619f175f7ae557956f449629c470a08e20580feef4ea8d53&token=162724582&lang=zh_CN&scene=21#wechat_redirect) + +## 35.保证接口正确性,其实就是保证更少的bug + +保证接口的正确性,换个角度讲,就是保证更少的bug,甚至是没有bug。所以接口开发完后,一般需要开发**自测一下**。然后的话,接口的正确还体现在,多线程并发的时候,**保证数据的正确性**,等等。比如你做一笔转账交易,扣减余额的时候,可以通过CAS乐观锁的方式保证余额扣减正确吧。 + +如果你是实现秒杀接口,得防止超卖问题吧。你可以使用Redis分布式锁防止超卖问题。使用Redis分布式锁,有几个注意要点,大家可以看下我之前这篇文章哈:[七种方案!探讨Redis分布式锁的正确使用姿势](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488142&idx=1&sn=79a304efae7a814b6f71bbbc53810c0c&chksm=cf21cda7f85644b11ff80323defb90193bc1780b45c1c6081f00da85d665fd9eb32cc934b5cf&token=162724582&lang=zh_CN&scene=21#wechat_redirect) + +## 36.学会沟通,跟前端沟通,跟产品沟通 + +我把这一点放到最后,学会沟通是非常非常重要的。比如你开发定义接口时,**一定不能上来就自己埋头把接口定义完了**,**需要跟客户端先对齐接口**。遇到一些难点时,跟技术leader对齐方案。实现需求的过程中,有什么问题,及时跟产品沟通。 + +总之就是,开发接口过程中,一定要沟通好~ + + +## 最后(求关注,别白嫖我) + +如果这篇文章对您有所帮助,或者有所启发的话,欢迎关注我的公众号:捡田螺的小男孩 + + diff --git "a/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207\344\272\214\357\274\232\346\211\213\346\212\212\346\211\213\346\225\231\344\275\240\345\256\236\347\216\260\344\270\200\344\270\252\345\271\266\350\241\214\350\260\203\347\224\250\346\250\241\346\235\277.md" "b/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207\344\272\214\357\274\232\346\211\213\346\212\212\346\211\213\346\225\231\344\275\240\345\256\236\347\216\260\344\270\200\344\270\252\345\271\266\350\241\214\350\260\203\347\224\250\346\250\241\346\235\277.md" new file mode 100644 index 0000000..762cb1b --- /dev/null +++ "b/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207\344\272\214\357\274\232\346\211\213\346\212\212\346\211\213\346\225\231\344\275\240\345\256\236\347\216\260\344\270\200\344\270\252\345\271\266\350\241\214\350\260\203\347\224\250\346\250\241\346\235\277.md" @@ -0,0 +1,599 @@ +## 前言 + +大家好,我是捡田螺的小男孩。 + +本文是后端思维专栏的第二篇哈。上一篇[36个设计接口的锦囊](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499388&idx=1&sn=49a22120a3238e13ad7c3d3b73d9e453&chksm=cf222155f855a8434026b2c460d963c406186578c2527ca8f2bb829bbe849d87a2392a525a9b&token=1380536362&lang=zh_CN#rd),得到非常多小伙伴的认可。 +36个设计接口的锦囊中也提到一个点:就是**使用并行调用优化接口**。所以接下来就快马加鞭,写第二篇:手把手教你写一个并行调用模板。 + +- 一个串行调用的例子(App首页信息查询) +- CompletionService实现并行调用 +- 抽取通用的并行调用方法 +- 代码思考以及设计模式应用 +- 思考总结 +- 公众号:**捡田螺的小男孩** + + +## 1. 一个串行调用的例子 + +如果让你设计一个APP首页查询的接口,它需要查用户信息、需要查```banner```信息、需要查标签信息等等。一般情况,小伙伴会实现如下: + +``` +public AppHeadInfoResponse queryAppHeadInfo(AppInfoReq req) { + //查用户信息 + UserInfoParam userInfoParam = buildUserParam(req); + UserInfoDTO userInfoDTO = userService.queryUserInfo(userInfoParam); + //查banner信息 + BannerParam bannerParam = buildBannerParam(req); + BannerDTO bannerDTO = bannerService.queryBannerInfo(bannerParam); + //查标签信息 + LabelParam labelParam = buildLabelParam(req); + LabelDTO labelDTO = labelService.queryLabelInfo(labelParam); + //组装结果 + return buildResponse(userInfoDTO,bannerDTO,labelDTO); +} +``` + +这段代码会有什么问题嘛? 其实这是一段挺正常的代码,但是这个方法实现中,查询用户、banner、标签信息,**是串行的**,如果查询用户信息```200ms```,查询banner信息```100ms```,查询标签信息```200ms```的话,耗时就是```500ms```啦。 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/35fa8e071a7048d5ae7d8e3e7f339532~tplv-k3u1fbpfcp-zoom-1.image) + +其实为了优化性能,我们可以修改为**并行调用**的方式,耗时可以降为```200ms```,如下图所示: + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e8559cfd7bb2449dbab91c0b38a3d78e~tplv-k3u1fbpfcp-zoom-1.image) + + +## 2. CompletionService实现并行调用 + +对于上面的例子,**如何实现并行调用呢?** + +有小伙伴说,可以使用```Future+Callable```实现多个任务的并行调用。但是线程池执行批量任务时,返回值用```Future的get()```获取是阻塞的,如果前一个任务执行比较耗时的话,```get()```方法会阻塞,形成排队等待的情况。 + +而```CompletionService```是对定义```ExecutorService```进行了包装,可以一边生成任务,一边获取任务的返回值。让这两件事分开执行,任务之间不会互相阻塞,可以获取最先完成的任务结果。 + + +> ```CompletionService```的实现原理比较简单,底层通过FutureTask+阻塞队列,实现了任务先完成的话,可优先获取到。也就是说任务执行结果按照完成的先后顺序来排序,先完成可以优化获取到。内部有一个先进先出的阻塞队列,用于保存已经执行完成的Future,你调用```CompletionService```的poll或take方法即可获取到一个已经执行完成的Future,进而通过调用Future接口实现类的```get```方法获取最终的结果。 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/10e375f58f5d490193888b0c5375e0f0~tplv-k3u1fbpfcp-zoom-1.image) + + +接下来,我们来看下,如何用```CompletionService```,实现并行查询APP首页信息哈。思考步骤如下: + +1. 我们先把查询用户信息的任务,放到线程池,如下: +``` +ExecutorService executor = Executors.newFixedThreadPool(10); +//查询用户信息 +CompletionService userDTOCompletionService = new ExecutorCompletionService(executor); +Callable userInfoDTOCallableTask = () -> { + UserInfoParam userInfoParam = buildUserParam(req); + return userService.queryUserInfo(userInfoParam); + }; +userDTOCompletionService.submit(userInfoDTOCallableTask); +``` + +2. 但是如果想把查询```banner```信息的任务,也放到这个线程池的话,发现不好放了,因为返回类型不一样,一个是```UserInfoDTO```,另外一个是```BannerDTO```。那这时候,我们是不是把泛型声明为Object即可,因为所有对象都是继承于Object的?如下: + +``` +ExecutorService executor = Executors.newFixedThreadPool(10); +//查询用户信息 +CompletionService baseDTOCompletionService = new ExecutorCompletionService(executor); +Callable userInfoDTOCallableTask = () -> { + UserInfoParam userInfoParam = buildUserParam(req); + return userService.queryUserInfo(userInfoParam); +}; +//banner信息任务 +Callable bannerDTOCallableTask = () -> { + BannerParam bannerParam = buildBannerParam(req); + return bannerService.queryBannerInfo(bannerParam); +}; + +//提交用户信息任务 +baseDTOCompletionService.submit(userInfoDTOCallableTask); +//提交banner信息任务 +baseDTOCompletionService.submit(bannerDTOCallableTask); +``` +3. 这里会有个问题,就是获取**返回值的时候**,我们不知道哪个```Object```是用户信息的DTO,哪个是```BannerDTO```?**怎么办呢?**这时候,我们可以在参数里面做个扩展嘛,即参数声明为一个基础对象BaseRspDTO,再搞个泛型放Object数据的,然后基础对象BaseRspDTO有个区分是UserDTO还是BannerDTO的**唯一标记属性key**。代码如下: + +``` +public class BaseRspDTO { + + //区分是DTO返回的唯一标记,比如是UserInfoDTO还是BannerDTO + private String key; + //返回的data + private T data; + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } +} + +//并行查询App首页信息 +public AppHeadInfoResponse parallelQueryAppHeadPageInfo(AppInfoReq req) { + + long beginTime = System.currentTimeMillis(); + System.out.println("开始并行查询app首页信息,开始时间:" + beginTime); + + ExecutorService executor = Executors.newFixedThreadPool(10); + CompletionService> baseDTOCompletionService = new ExecutorCompletionService>(executor); + + //查询用户信息任务 + Callable> userInfoDTOCallableTask = () -> { + UserInfoParam userInfoParam = buildUserParam(req); + UserInfoDTO userInfoDTO = userService.queryUserInfo(userInfoParam); + BaseRspDTO userBaseRspDTO = new BaseRspDTO(); + userBaseRspDTO.setKey("userInfoDTO"); + userBaseRspDTO.setData(userInfoDTO); + return userBaseRspDTO; + }; + + //banner信息查询任务 + Callable> bannerDTOCallableTask = () -> { + BannerParam bannerParam = buildBannerParam(req); + BannerDTO bannerDTO = bannerService.queryBannerInfo(bannerParam); + BaseRspDTO bannerBaseRspDTO = new BaseRspDTO(); + bannerBaseRspDTO.setKey("bannerDTO"); + bannerBaseRspDTO.setData(bannerDTO); + return bannerBaseRspDTO; + }; + + //label信息查询任务 + Callable> labelDTODTOCallableTask = () -> { + LabelParam labelParam = buildLabelParam(req); + LabelDTO labelDTO = labelService.queryLabelInfo(labelParam); + BaseRspDTO labelBaseRspDTO = new BaseRspDTO(); + labelBaseRspDTO.setKey("labelDTO"); + labelBaseRspDTO.setData(labelDTO); + return labelBaseRspDTO; + }; + + //提交用户信息任务 + baseDTOCompletionService.submit(userInfoDTOCallableTask); + //提交banner信息任务 + baseDTOCompletionService.submit(bannerDTOCallableTask); + //提交label信息任务 + baseDTOCompletionService.submit(labelDTODTOCallableTask); + + UserInfoDTO userInfoDTO = null; + BannerDTO bannerDTO = null; + LabelDTO labelDTO = null; + + try { + //因为提交了3个任务,所以获取结果次数是3 + for (int i = 0; i < 3; i++) { + Future> baseRspDTOFuture = baseDTOCompletionService.poll(1, TimeUnit.SECONDS); + BaseRspDTO baseRspDTO = baseRspDTOFuture.get(); + if ("userInfoDTO".equals(baseRspDTO.getKey())) { + userInfoDTO = (UserInfoDTO) baseRspDTO.getData(); + } else if ("bannerDTO".equals(baseRspDTO.getKey())) { + bannerDTO = (BannerDTO) baseRspDTO.getData(); + } else if ("labelDTO".equals(baseRspDTO.getKey())) { + labelDTO = (LabelDTO) baseRspDTO.getData(); + } + } + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + e.printStackTrace(); + } + + System.out.println("结束并行查询app首页信息,总耗时:" + (System.currentTimeMillis() - beginTime)); + return buildResponse(userInfoDTO, bannerDTO, labelDTO); +} +``` + +到这里为止,一个基于```CompletionService```实现并行调用的例子已经实现啦。是不是很开心,哈哈。 + +## 3. 抽取通用的并行调用方法 + +我们回过来观察下第2小节,查询app首页信息的demo:```CompletionService```实现了并行调用。大家有没有什么其他想法呢?比如,假设别的业务场景,也想通过并行调用优化,那是不是也得搞一套类似第2小节的代码。所以,**我们是不是可以抽取一个通用的并行方法,让别的场景也可以用,对吧?这就是后端思维啦**! + +基于第2小节的代码,我们如何抽取通用并行调用方法呢。 + +首先,这个通用的并行调用方法,**不能跟业务相关的属性挂钩**,对吧,所以方法的入参应该有哪些呢? + +> 方法的入参,可以有```Callable```对吧。因为并行,肯定是多个Callable任务的。所以,入参应该是一个```Callable```的数组。再然后,基于上面的APP首页查询的例子,```Callable```里面得带```BaseRspDTO```泛型,对吧?因此入参就是```List>> list```。 + +那并行调用的出参呢? 你有多个```Callable```的任务,是不是得有多个对应的返回,因此,你的出参可以是```List>```。我们抽取的通用并行调用模板,就可以写成酱紫: + +``` + public List> executeTask(List>> taskList) { + + List> resultList = new ArrayList<>(); + //校验参数 + if (taskList == null || taskList.size() == 0) { + return resultList; + } + + ExecutorService executor = Executors.newFixedThreadPool(10); + CompletionService> baseDTOCompletionService = new ExecutorCompletionService>(executor); + //提交任务 + for (Callable> task : taskList) { + baseDTOCompletionService.submit(task); + } + + try { + //遍历获取结果 + for (int i = 0; i < taskList.size(); i++) { + Future> baseRspDTOFuture = baseDTOCompletionService.poll(2, TimeUnit.SECONDS); + resultList.add(baseRspDTOFuture.get()); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + e.printStackTrace(); + } + + return resultList; + } +``` +既然我们是抽取通用的并行调用方法,那以上的方法是否还有**哪些地方需要改进**的呢? + +- 第一个可以优化的地方,就是```executor线程池```,比如有些业务场景想用```A线程池```,有些业务想用```B线程池```,那么,这个方法,就不通用啦,对吧。我们可以把线程池以参数的实行提供出来,给调用方自己控制。 +- 第二个可以优化的地方,就是```CompletionService```的```poll```方法获取时,超时时间是写死的。因为不同业务场景,超时时间可能不一样。所以,超时时间也是可以以参数形式放出来,给调用方自己控制。 + +我们再次优化一下这个通用的并行调用模板,代码如下: +``` +public List> executeTask(List>> taskList, long timeOut, ExecutorService executor) { + + List> resultList = new ArrayList<>(); + //校验参数 + if (taskList == null || taskList.size() == 0) { + return resultList; + } + if (executor == null) { + return resultList; + } + if (timeOut <= 0) { + return resultList; + } + + //提交任务 + CompletionService> baseDTOCompletionService = new ExecutorCompletionService>(executor); + for (Callable> task : taskList) { + baseDTOCompletionService.submit(task); + } + + try { + //遍历获取结果 + for (int i = 0; i < taskList.size(); i++) { + Future> baseRspDTOFuture = baseDTOCompletionService.poll(timeOut, TimeUnit.SECONDS); + resultList.add(baseRspDTOFuture.get()); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + e.printStackTrace(); + } + + return resultList; +} +``` + +以后别的场景也需要用到并行调用的话,直接调用你的这个方法即可,是不是有点小小的成就感啦,哈哈。 + +## 4. 代码思考以及设计模式应用 + +我们把抽取的那个公用的并行调用方法,应用到```App首页信息查询```的例子,代码如下: + +``` +public AppHeadInfoResponse parallelQueryAppHeadPageInfo1(AppInfoReq req) { + + long beginTime = System.currentTimeMillis(); + System.out.println("开始并行查询app首页信息,开始时间:" + beginTime); + //用户信息查询任务 + Callable> userInfoDTOCallableTask = () -> { + UserInfoParam userInfoParam = buildUserParam(req); + UserInfoDTO userInfoDTO = userService.queryUserInfo(userInfoParam); + BaseRspDTO userBaseRspDTO = new BaseRspDTO(); + userBaseRspDTO.setKey("userInfoDTO"); + userBaseRspDTO.setData(userInfoDTO); + return userBaseRspDTO; + }; + + //banner信息查询任务 + Callable> bannerDTOCallableTask = () -> { + BannerParam bannerParam = buildBannerParam(req); + BannerDTO bannerDTO = bannerService.queryBannerInfo(bannerParam); + BaseRspDTO bannerBaseRspDTO = new BaseRspDTO(); + bannerBaseRspDTO.setKey("bannerDTO"); + bannerBaseRspDTO.setData(bannerDTO); + return bannerBaseRspDTO; + }; + + //label信息查询任务 + Callable> labelDTODTOCallableTask = () -> { + LabelParam labelParam = buildLabelParam(req); + LabelDTO labelDTO = labelService.queryLabelInfo(labelParam); + BaseRspDTO labelBaseRspDTO = new BaseRspDTO(); + labelBaseRspDTO.setKey("labelDTO"); + labelBaseRspDTO.setData(labelDTO); + return labelBaseRspDTO; + }; + + List>> taskList = new ArrayList<>(); + taskList.add(userInfoDTOCallableTask); + taskList.add(bannerDTOCallableTask); + taskList.add(labelDTODTOCallableTask); + ExecutorService executor = Executors.newFixedThreadPool(10); + List> resultList = parallelInvokeCommonService.executeTask(taskList, 3, executor); + if (resultList == null || resultList.size() == 0) { + return new AppHeadInfoResponse(); + } + + UserInfoDTO userInfoDTO = null; + BannerDTO bannerDTO = null; + LabelDTO labelDTO = null; + + //遍历结果 + for (int i = 0; i < resultList.size(); i++) { + BaseRspDTO baseRspDTO = resultList.get(i); + if ("userInfoDTO".equals(baseRspDTO.getKey())) { + userInfoDTO = (UserInfoDTO) baseRspDTO.getData(); + } else if ("bannerDTO".equals(baseRspDTO.getKey())) { + bannerDTO = (BannerDTO) baseRspDTO.getData(); + } else if ("labelDTO".equals(baseRspDTO.getKey())) { + labelDTO = (LabelDTO) baseRspDTO.getData(); + } + } + + System.out.println("结束并行查询app首页信息,总耗时:" + (System.currentTimeMillis() - beginTime)); + return buildResponse(userInfoDTO, bannerDTO, labelDTO); + } + +``` + +基于以上代码,小伙伴们,是否还有其他方面的优化想法呢? 比如这几个```Callable```查询任务,我们是不是也可以抽取一下?让代码更加简洁。 + +> 二话不说,现在我们直接建一个```BaseTaskCommand```类,实现```Callable```接口,把查询用户信息、查询banner信息、label标签信息的查询任务放进去。 + +代码如下: + +``` +public class BaseTaskCommand implements Callable> { + + private String key; + private AppInfoReq req; + private IUserService userService; + private IBannerService bannerService; + private ILabelService labelService; + + public BaseTaskCommand(String key, AppInfoReq req, IUserService userService, IBannerService bannerService, ILabelService labelService) { + this.key = key; + this.req = req; + this.userService = userService; + this.bannerService = bannerService; + this.labelService = labelService; + } + + @Override + public BaseRspDTO call() throws Exception { + + if ("userInfoDTO".equals(key)) { + UserInfoParam userInfoParam = buildUserParam(req); + UserInfoDTO userInfoDTO = userService.queryUserInfo(userInfoParam); + BaseRspDTO userBaseRspDTO = new BaseRspDTO(); + userBaseRspDTO.setKey("userInfoDTO"); + userBaseRspDTO.setData(userInfoDTO); + return userBaseRspDTO; + } else if ("bannerDTO".equals(key)) { + BannerParam bannerParam = buildBannerParam(req); + BannerDTO bannerDTO = bannerService.queryBannerInfo(bannerParam); + BaseRspDTO bannerBaseRspDTO = new BaseRspDTO(); + bannerBaseRspDTO.setKey("bannerDTO"); + bannerBaseRspDTO.setData(bannerDTO); + return bannerBaseRspDTO; + } else if ("labelDTO".equals(key)) { + LabelParam labelParam = buildLabelParam(req); + LabelDTO labelDTO = labelService.queryLabelInfo(labelParam); + BaseRspDTO labelBaseRspDTO = new BaseRspDTO(); + labelBaseRspDTO.setKey("labelDTO"); + labelBaseRspDTO.setData(labelDTO); + return labelBaseRspDTO; + } + + return null; + } + + + private UserInfoParam buildUserParam(AppInfoReq req) { + return new UserInfoParam(); + } + + private BannerParam buildBannerParam(AppInfoReq req) { + return new BannerParam(); + } + + private LabelParam buildLabelParam(AppInfoReq req) { + return new LabelParam(); + } +} +``` +以上这块代码,构造函数还是有**比较多的参数**,并且```call()```方法中,有多个```if...else...```,如果新增一个分支(**比如查询浮层信息**),那又得在```call```方法里修改了,并且**BaseTaskCommand的构造器也要修改了**。 + +> 大家是否有印象,多程序中出现多个if...else...时,我们就可以考虑使用**策略模式+工厂模式**优化。 + +我们声明多个策略实现类,如下: + +``` + +public interface IBaseTask { + + //返回每个策略类的key,如 + String getTaskType(); + + BaseRspDTO execute(AppInfoReq req); + +} + +//用户信息策略类 +@Service +public class UserInfoStrategyTask implements IBaseTask { + + @Autowired + private IUserService userService; + + @Override + public String getTaskType() { + return "userInfoDTO"; + } + + @Override + public BaseRspDTO execute(AppInfoReq req) { + UserInfoParam userInfoParam = userService.buildUserParam(req); + UserInfoDTO userInfoDTO = userService.queryUserInfo(userInfoParam); + BaseRspDTO userBaseRspDTO = new BaseRspDTO(); + userBaseRspDTO.setKey(getTaskType()); + userBaseRspDTO.setData(userBaseRspDTO); + return userBaseRspDTO; + } +} + +/** + * banner信息策略实现类 + **/ +@Service +public class BannerStrategyTask implements IBaseTask { + + @Autowired + private IBannerService bannerService; + + @Override + public String getTaskType() { + return "bannerDTO"; + } + + @Override + public BaseRspDTO execute(AppInfoReq req) { + BannerParam bannerParam = bannerService.buildBannerParam(req); + BannerDTO bannerDTO = bannerService.queryBannerInfo(bannerParam); + BaseRspDTO bannerBaseRspDTO = new BaseRspDTO(); + bannerBaseRspDTO.setKey(getTaskType()); + bannerBaseRspDTO.setData(bannerDTO); + return bannerBaseRspDTO; + } +} + +... +``` +然后这几个策略实现类,怎么交给```spring```管理呢? 我们可以实现```ApplicationContextAware```接口,把策略的实现类注入到一个map,然后根据请求方不同的策略请求类型(即DTO的类型),去实现不同的策略类调用。其实这类似于工厂模式的思想。代码如下: + +``` +/** + * 策略工厂类 + **/ +@Component +public class TaskStrategyFactory implements ApplicationContextAware { + + private Map map = new ConcurrentHashMap<>(); + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + Map tempMap = applicationContext.getBeansOfType(IBaseTask.class); + tempMap.values().forEach(iBaseTask -> { + map.put(iBaseTask.getTaskType(), iBaseTask); + }); + } + + public BaseRspDTO executeTask(String key, AppInfoReq req) { + IBaseTask baseTask = map.get(key); + if (baseTask != null) { + System.out.println("工厂策略实现类执行"); + return baseTask.execute(req); + } + return null; + } +} +``` + +有了策略工厂类```TaskStrategyFactory```,我们再回来优化下```BaseTaskCommand```类的代码。它的构造器已经不需要多个```IUserService userService, IBannerService bannerService, ILabelService labelService```啦,只需要策略工厂类```TaskStrategyFactory```即可。同时策略也不需要多个```if...else...```判断了,用策略工厂类```TaskStrategyFactory```代替即可。优化后的代码如下: + +``` +public class BaseTaskCommand implements Callable> { + + private String key; + private AppInfoReq req; + private TaskStrategyFactory taskStrategyFactory; + + public BaseTaskCommand(String key, AppInfoReq req, TaskStrategyFactory taskStrategyFactory) { + this.key = key; + this.req = req; + this.taskStrategyFactory = taskStrategyFactory; + } + + @Override + public BaseRspDTO call() throws Exception { + return taskStrategyFactory.executeTask(key, req); + } +} +``` + +因此整个```app首页信息并行```查询,就可以优化成这样啦,如下: + +``` +public AppHeadInfoResponse parallelQueryAppHeadPageInfo2(AppInfoReq req) { + long beginTime = System.currentTimeMillis(); + System.out.println("开始并行查询app首页信息(最终版本),开始时间:" + beginTime); + List>> taskList = new ArrayList<>(); + //用户信息查询任务 + taskList.add(new BaseTaskCommand("userInfoDTO", req, taskStrategyFactory)); + //banner查询任务 + taskList.add(new BaseTaskCommand("bannerDTO", req, taskStrategyFactory)); + //标签查询任务 + taskList.add(new BaseTaskCommand("labelDTO", req, taskStrategyFactory)); + + ExecutorService executor = Executors.newFixedThreadPool(10); + List> resultList = parallelInvokeCommonService.executeTask(taskList, 3, executor); + + if (resultList == null || resultList.size() == 0) { + return new AppHeadInfoResponse(); + } + + UserInfoDTO userInfoDTO = null; + BannerDTO bannerDTO = null; + LabelDTO labelDTO = null; + + for (BaseRspDTO baseRspDTO : resultList) { + if ("userInfoDTO".equals(baseRspDTO.getKey())) { + userInfoDTO = (UserInfoDTO) baseRspDTO.getData(); + } else if ("bannerDTO".equals(baseRspDTO.getKey())) { + bannerDTO = (BannerDTO) baseRspDTO.getData(); + } else if ("labelDTO".equals(baseRspDTO.getKey())) { + labelDTO = (LabelDTO) baseRspDTO.getData(); + } + } + + System.out.println("结束并行查询app首页信息(最终版本),总耗时:" + (System.currentTimeMillis() - beginTime)); + return buildResponse(userInfoDTO, bannerDTO, labelDTO); + } +``` + + +## 5. 思考总结 + +以上代码整体优化下来,已经很简洁啦。那还有没有别的优化思路呢。 +> 其实还是有的,比如,把唯一标记的```key```定义为枚举,而不是写死的字符串```"userInfoDTO"、"bannerDTO","labelDTO"```。还有,除了```CompletionService```,有些小伙伴喜欢用```CompletableFuture```实行并行调用。 + +本文大家学到了哪些知识呢? +1. 如何优化接口性能?某些场景下,可以使用并行调用代替串行。 +2. 如何实现并行调用呢? 可以使用```CompletionService```。 +3. 学到的后端思维是? 日常开发中,要学会抽取通用的方法、或者工具。 +4. 策略模式和工厂模式的应用 + +本文的话,设计模式这块还不是很详细,然后下一篇,给大家讲讲,我是如何在现有代码基础上,抽取设计模式的哈。然后,如果大家需要本文的完整代码的话,可以关注我的公众号:**捡田螺的小男孩**,里面有我的联系方式哈。 + + + + + From e8ce3c8cd9f26c0383fdab490c3f7557ae38aeb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Sun, 17 Jul 2022 20:56:21 +0800 Subject: [PATCH 09/52] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 214c8ab..8787f10 100644 --- a/README.md +++ b/README.md @@ -9,3 +9,4 @@ ## 涓鍒嗕篃鏄埍锛岃阿璋㈠ぇ瀹剁殑鏀寔鍝垀 ![](https://user-gold-cdn.xitu.io/2020/7/15/1735311bf66cecd8?w=430&h=580&f=jpeg&s=35456) +![image](https://user-images.githubusercontent.com/20244922/179399354-8a9fd2a8-42ba-4303-9ce5-04891e899e6d.png) From 17f5ef1c1964e24a4029654f3e4e0af261dd2a20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Sun, 17 Jul 2022 20:56:43 +0800 Subject: [PATCH 10/52] Update README.md --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 8787f10..1c37b37 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,4 @@ - 濡傛灉浣犳槸涓埍瀛︿範鐨勫ソ瀛╁瓙锛屽彲浠ュ叧娉ㄦ垜鍏紬鍙凤紝涓璧峰涔犺璁哄搱~~ -## 涓鍒嗕篃鏄埍锛岃阿璋㈠ぇ瀹剁殑鏀寔鍝垀 -![](https://user-gold-cdn.xitu.io/2020/7/15/1735311bf66cecd8?w=430&h=580&f=jpeg&s=35456) - ![image](https://user-images.githubusercontent.com/20244922/179399354-8a9fd2a8-42ba-4303-9ce5-04891e899e6d.png) From cce5493aedfd9f6942ddefdd7a7eeecf3e8dc4dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Sun, 17 Jul 2022 20:57:25 +0800 Subject: [PATCH 11/52] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1c37b37..6290566 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,6 @@ 寰俊鎼滐細鎹$敯铻虹殑灏忕敺瀛 -- 濡傛灉浣犳槸涓埍瀛︿範鐨勫ソ瀛╁瓙锛屽彲浠ュ叧娉ㄦ垜鍏紬鍙凤紝涓璧峰涔犺璁哄搱~~ +- 濡傛灉浣犳槸涓埍瀛︿範鐨勫ソ瀛╁瓙锛屽彲浠ュ叧娉ㄦ垜鍏紬鍙凤紙鎵弿涓涓嬩簩缁寸爜锛岃繕鏈夊緢澶氬緢澶氬共璐ф枃绔狅級锛屼竴璧峰涔犺璁哄搱~~ ![image](https://user-images.githubusercontent.com/20244922/179399354-8a9fd2a8-42ba-4303-9ce5-04891e899e6d.png) From 3f3cc5fb02dfa5c91d72868f73970d7e02f75ad9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Sun, 17 Jul 2022 20:57:38 +0800 Subject: [PATCH 12/52] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6290566..508f437 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,6 @@ 寰俊鎼滐細鎹$敯铻虹殑灏忕敺瀛 -- 濡傛灉浣犳槸涓埍瀛︿範鐨勫ソ瀛╁瓙锛屽彲浠ュ叧娉ㄦ垜鍏紬鍙凤紙鎵弿涓涓嬩簩缁寸爜锛岃繕鏈夊緢澶氬緢澶氬共璐ф枃绔狅級锛屼竴璧峰涔犺璁哄搱~~ +- 濡傛灉浣犳槸涓埍瀛︿範鐨勫ソ瀛╁瓙锛屽彲浠ュ叧娉ㄦ垜鍏紬鍙凤紙鎵弿涓嬮潰浜岀淮鐮侊紝杩樻湁寰堝寰堝骞茶揣鏂囩珷锛夛紝涓璧峰涔犺璁哄搱~~ ![image](https://user-images.githubusercontent.com/20244922/179399354-8a9fd2a8-42ba-4303-9ce5-04891e899e6d.png) From 59a6aed48a8c6f9e86f13e5551befc21628f22f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Sat, 23 Jul 2022 07:24:54 +0800 Subject: [PATCH 13/52] Update README.md --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 508f437..7327214 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,12 @@ 鏁寸悊涓浠借秴绾ц缁嗙殑Java闈㈣瘯棰+鍚庣鍩虹+鏃ュ父宸ヤ綔鎬荤粨锛屽仛鏈鏆栧績鐨勭敺瀛╁瓙锛屽悗闈細鎱㈡參鎶婄瓟妗堝畬鍠勶紝甯屾湜澶у鎵惧埌鐞嗘兂offer +猸 鐐瑰彸涓婅缁欎竴涓 Star锛岄紦鍔辨妧鏈汉杈撳嚭鏇村骞茶揣锛岀埍浜 锛 + +浣滆呮崱鐢拌灪鐨勫皬鐢峰锛屾氮杩硅繃鍑犲澶у巶锛屾帢閲戜紭绉鍒涗綔鑰咃紝CSDN鍗氫富銆 + +- 鍘熷垱绮惧搧100绡(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497536&idx=1&sn=3ac9934f607d79e51457fd01f4c8a4ef&chksm=cf222869f855a17fc30c744e5b7ccdeca407f3b7ddcca46bae1c93b1436ffc6fe417ccb8aef4&token=1990771297&lang=zh_CN#rd) + + ## 涓汉鍏紬鍙 寰俊鎼滐細鎹$敯铻虹殑灏忕敺瀛 From 3c57038967fffc6b22563b6017a71c94ab89ff48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Sat, 23 Jul 2022 07:46:54 +0800 Subject: [PATCH 14/52] Add files via upload MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 鍚庣鎬濈淮绡 --- .../README.md" | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 "\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207/README.md" diff --git "a/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207/README.md" "b/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207/README.md" new file mode 100644 index 0000000..c23117d --- /dev/null +++ "b/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207/README.md" @@ -0,0 +1,9 @@ +## 后端思维篇(持续更新中) + +公众号:捡田螺的小男孩 + +- [后端思想篇:设计好接口的36个锦囊!](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499388&idx=1&sn=49a22120a3238e13ad7c3d3b73d9e453&chksm=cf222155f855a8434026b2c460d963c406186578c2527ca8f2bb829bbe849d87a2392a525a9b&scene=178&cur_album_id=2396778860463161350#rd) +- [后端思维篇:手把手教你写一个并行调用模板](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499504&idx=1&sn=bb62226e6cffeb1859efb0100c796050&chksm=cf2221d9f855a8cf23f75cb51c1a407578fb0f279e96ddae74b5b8c84f2f5dc71762425b17cb&scene=178&cur_album_id=2396778860463161350#rd) +- [后端思维篇:如何应用设计模式优化代码](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499524&idx=1&sn=cb4cc48a3e8d9a54b0ebc4c7ad517f14&chksm=cf22202df855a93b37327856ee88b0bf5f6ed7da67964438fc2cf747666260d5026dd62d4a17&scene=178&cur_album_id=2396778860463161350#rd) +- [后端思维篇:统一参数校验、异常处理、结果返回](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499708&idx=1&sn=808979c495acd9344732d147c0ad40d3&chksm=cf222095f855a983f31d5f6abf401fa3b5967f8839c6775d35cefc5cc6244fb4135563ff1090&scene=178&cur_album_id=2396778860463161350#rd) +- [后端思维篇:如何抽一个观察者模板](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247500159&idx=1&sn=a5328372e580b22c939a5b3084aef164&chksm=cf221e56f85597401e8c99b8dd1bc1af97fcf69207ceaa04c5c26e028ac47d1658b79ae32291&scene=178&cur_album_id=2396778860463161350#rd) From be59b4dc80220143cd5e2d17b31713149ddd9679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Sat, 23 Jul 2022 08:56:53 +0800 Subject: [PATCH 15/52] =?UTF-8?q?Java=E5=9F=BA=E7=A1=80=E6=96=87=E7=AB=A0?= =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../README.MD" | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 "Java\345\237\272\347\241\200\345\255\246\344\271\240/README.MD" diff --git "a/Java\345\237\272\347\241\200\345\255\246\344\271\240/README.MD" "b/Java\345\237\272\347\241\200\345\255\246\344\271\240/README.MD" new file mode 100644 index 0000000..0a1609f --- /dev/null +++ "b/Java\345\237\272\347\241\200\345\255\246\344\271\240/README.MD" @@ -0,0 +1,21 @@ +## Java鍩虹绡囷紙鎸佺画鏇存柊涓級 +鈥 +鍏紬鍙凤細鎹$敯铻虹殑灏忕敺瀛 +鈥 +- [涓鏂囪鎳傜嚎绋嬫睜鐨勫伐浣滃師鐞嗭紙鏁呬簨鐧借瘽鏂囷級](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488078&idx=1&sn=0a7cef472002f6582fd2354fba83706a&chksm=cf21cd67f85644716263c3a80cead9b7bb36d9677f6f8b06d0602077ece70fcafa9d20c1cffb&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Synchronized瑙f瀽鈥斺斿鏋滀綘鎰挎剰涓灞備竴灞傚墺寮鎴戠殑蹇僝(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487942&idx=1&sn=bbc68d1b9da23bf6474378e310b1ef1b&chksm=cf21ceeff85647f9ad7a08226849fcba3f9481387d13b17a5787fb94027647de81c349f9e390&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [寮傛缂栫▼鍒╁櫒锛欳ompletableFuture璇﹁В](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490456&idx=1&sn=95836324db57673a4d7aea4fb233c0d2&chksm=cf21c4b1f8564da72dc7b39279362bcf965b1374540f3b339413d138599f7de59a5f977e3b0e&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java鏃ュ父寮鍙戠殑21涓潙锛屼綘韪╄繃鍑犱釜锛焆(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488115&idx=1&sn=bdd4a4ca36bc7ea902106d058e8537fb&chksm=cf21cd5af856444cb36af600705615454b0aaa2b289b97ddb52d594556ac07a1915b73ecce19&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [涓浠絁ava绋嬪簭鍛樼殑鐝嶈棌涔﹀崟锛岃鎮ㄦ敞鎰忔煡鏀禲(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488066&idx=1&sn=44b5a90be1b69d7938dbcf516d85f041&chksm=cf21cd6bf856447d869278386250f59a926881375df848e54f86a21682bdab50f9e09ca56fbd&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java绋嬪簭鍛樺繀澶囧熀纭锛欽DK 5-15閮芥湁鍝簺缁忓吀鏂扮壒鎬(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488058&idx=1&sn=aab4d0dc9020cb62710086474ca90baf&chksm=cf21cd13f8564405040593daa45c62aec218e13f5ff42d679c59f768dd4fcc53ddcf34e0a454&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [绋嬪簭鍛樺繀澶囧熀纭锛欸it 鍛戒护鍏ㄦ柟浣嶅涔燷(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488013&idx=1&sn=7011a51a347e3da2cf8f8540b4d9a5d6&chksm=cf21cd24f8564432d74bc13551ebdeae71a71ea31e339c7a8f1f42f181078b5192475d598626&token=162724582&ang=zh_CN&scene=21#wechat_redirect) +- [缁欎綘鐨凧ava绋嬪簭鎷嶄釜鐗囧瓙鍚э細jstack鍛戒护瑙f瀽](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487990&idx=1&sn=b5b3c565392f39e5ac517696603b2ed9&chksm=cf21cedff85647c960407dce77fe04d08e51f8c7332310ccacd925be5567c187aa761dd1d1c8&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java绋嬪簭鍛樺繀澶囧熀纭缁撴瀯鍥綸(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487985&idx=1&sn=ead28c6c8d81b98e59603b848d250b30&chksm=cf21ced8f85647ce336f19016c7ff1936b21c81066815c8f28b830098716111548edb9767b21&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java绋嬪簭鍛樺繀澶囷細搴忓垪鍖栧叏鏂逛綅瑙f瀽](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487980&idx=1&sn=2a9ce519f87a1ffe1511022e6724208e&chksm=cf21cec5f85647d357c79860171fc1799ef3c44a2bdd0716e8437e31708a17d9000b4224bd36&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [浼樺寲if-else浠g爜鐨勫叓绉嶆柟妗圿(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487970&idx=1&sn=c296bb03419adf93955c6d0f27e56b29&chksm=cf21cecbf85647dd0ef5160559bc0d524a4be004a28bc5d2770a43409e3b090123c0930cf047&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java绋嬪簭鍛樺繀澶囧熀纭锛氭硾鍨嬭В鏋怾(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487964&idx=1&sn=24d7228cc10afc98c52dbf35da61a7b9&chksm=cf21cef5f85647e3d2b3f1e126cdc46d9e889d2e30c09716e0aea016beee3ca6d4c321cf60ae&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java绋嬪簭鍛樺繀澶囧熀纭锛氬唴閮ㄧ被瑙f瀽](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487963&idx=1&sn=a0b49cd49a3dd51b6736c9ffa0a5997a&chksm=cf21cef2f85647e49a4bdb43f27583f03fb9ec4719767512dc084edd05675599c3bec44251fb&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [鑰佹槸閬囧埌涔辩爜闂锛氬畠鏄浣曚骇鐢熺殑锛屽張濡備綍瑙e喅鍛紵](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487962&idx=1&sn=7424e843c80b228283fc08d4d24cc4bb&chksm=cf21cef3f85647e5a9c92d280624ad2564e885561a8b64cbf6722459f7c13da7421765321aa9&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [璋堣皥Java鍙嶅皠锛氫粠鍏ラ棬鍒板疄璺碉紝鍐嶅埌鍘熺悊](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487959&idx=1&sn=778114d611f18b0f307a3f3ab6cd9117&chksm=cf21cefef85647e84b77c0e46620e91cf5ff079785b58a7dc66e5ed7419e21e0da9180699617&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java绋嬪簭鍛樺繀澶囩殑涓浜涙祦绋嬪浘](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487946&idx=1&sn=57a86e1d2fe1a9ecf00594a0bb6baf5f&chksm=cf21cee3f85647f5cf2ba728cc0838923140130a18ad117e248cf9843460614fc855d556968a&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java绋嬪簭鍛樺繀澶囷細鏌ョ湅鏃ュ織甯哥敤鐨刲inux鍛戒护](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487954&idx=1&sn=6c04ff4edfcfea52a82795bcb9ed8efd&chksm=cf21cefbf85647ed8df72a23307315be5d1b3d4974c128f111bfdaa84da37cf7b49ff65c1112&token=162724582&lang=zh_CN&scene=21#wechat_redirect) \ No newline at end of file From ea08f142d10bf19d867d95e10e45fbcc5e188d15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Sat, 23 Jul 2022 09:13:07 +0800 Subject: [PATCH 16/52] =?UTF-8?q?=E4=B9=A6=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../README.MD" | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 "Java\347\250\213\345\272\217\345\221\230\351\234\200\350\246\201\347\234\213\345\223\252\344\272\233\344\271\246/README.MD" diff --git "a/Java\347\250\213\345\272\217\345\221\230\351\234\200\350\246\201\347\234\213\345\223\252\344\272\233\344\271\246/README.MD" "b/Java\347\250\213\345\272\217\345\221\230\351\234\200\350\246\201\347\234\213\345\223\252\344\272\233\344\271\246/README.MD" new file mode 100644 index 0000000..d01ff96 --- /dev/null +++ "b/Java\347\250\213\345\272\217\345\221\230\351\234\200\350\246\201\347\234\213\345\223\252\344\272\233\344\271\246/README.MD" @@ -0,0 +1,5 @@ +## Java鍩虹绡囷紙鎸佺画鏇存柊涓級 +鈥 +鍏紬鍙凤細鎹$敯铻虹殑灏忕敺瀛 +鈥 +- [涓浠絁ava绋嬪簭鍛樼殑鐝嶈棌涔﹀崟锛岃鎮ㄦ敞鎰忔煡鏀禲(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488066&idx=1&sn=44b5a90be1b69d7938dbcf516d85f041&chksm=cf21cd6bf856447d869278386250f59a926881375df848e54f86a21682bdab50f9e09ca56fbd&token=162724582&lang=zh_CN&scene=21#wechat_redirect) From 307e6e9f4e45cc79468ee1b93b7effda87411a82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Sat, 23 Jul 2022 09:13:40 +0800 Subject: [PATCH 17/52] Update README.MD --- .../README.MD" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java\347\250\213\345\272\217\345\221\230\351\234\200\350\246\201\347\234\213\345\223\252\344\272\233\344\271\246/README.MD" "b/Java\347\250\213\345\272\217\345\221\230\351\234\200\350\246\201\347\234\213\345\223\252\344\272\233\344\271\246/README.MD" index d01ff96..5ee6e33 100644 --- "a/Java\347\250\213\345\272\217\345\221\230\351\234\200\350\246\201\347\234\213\345\223\252\344\272\233\344\271\246/README.MD" +++ "b/Java\347\250\213\345\272\217\345\221\230\351\234\200\350\246\201\347\234\213\345\223\252\344\272\233\344\271\246/README.MD" @@ -1,4 +1,4 @@ -## Java鍩虹绡囷紙鎸佺画鏇存柊涓級 +## Java绋嬪簭鍛樹功鍗曪紙鎸佺画鏇存柊涓級 鈥 鍏紬鍙凤細鎹$敯铻虹殑灏忕敺瀛 鈥 From 4e853267e0bec5586cf9fb66d8615bc2bfd854b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Sat, 23 Jul 2022 09:38:47 +0800 Subject: [PATCH 18/52] =?UTF-8?q?=E9=9D=A2=E8=AF=95=E9=A2=98=E6=9B=B4?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../README.MD" | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 "Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/README.MD" diff --git "a/Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/README.MD" "b/Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/README.MD" new file mode 100644 index 0000000..78fbb48 --- /dev/null +++ "b/Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/README.MD" @@ -0,0 +1,31 @@ +## 1. 闈㈣瘯鐪熼 + +鍏虫敞鍏紬鍙凤細鎹$敯铻虹殑灏忕敺瀛 +鈥 +- [oppo鍚庣16杩為棶](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498750&idx=1&sn=19fe8b4fff28fe81db14e733053bbc74&chksm=cf2224d7f855adc1d0984980a4e3de31fe33329164a472ca8d8255a8a80b69b2e23850811323&token=2001057130&lang=zh_CN#rd) +- [灏忓巶鍚庣鍗佽繛闂紙闄勭瓟妗堬級](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498316&idx=1&sn=7749b78293b7b2af51eda99844e08a56&chksm=cf222565f855ac7324232e2af459f8b6e6eb5fd5b272c2b29bda08cc579421b6704a0de94b2e&token=2001057130&lang=zh_CN#rd) +- [鑵捐浜戝悗绔15杩為棶锛乚(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498171&idx=1&sn=f5a7ec25a569822be0f73fbcd413e8ba&chksm=cf222692f855af84fba419166fcd4235c0e78af3a2e1ec4c723a4efb1bd1ad6f8a5b9404c599&token=2001057130&lang=zh_CN#rd) +- [绀炬嫑鍚庣21杩為棶锛堜笁骞村伐浣滅粡楠屼竴闈級](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498084&idx=1&sn=96c8148cfeeeb16668ed9e03fa9131cc&chksm=cf22264df855af5b6e81b93738cca28989226a53ec702fcfaa0cc5004dded4208c5ee5ea844a&token=2001057130&lang=zh_CN#rd) +- [涓浠界儹涔庝箮鐨勫瓧鑺傞潰璇曠湡棰榏(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497742&idx=1&sn=18765e7356f446a7f2521f45b467d5d3&chksm=cf222727f855ae31dd2029e3219814211336c41d9228d271a583d3691ddadca586529aca9302&token=2001057130&lang=zh_CN#rd) +- [闈㈣瘯蹇呭锛氳櫨鐨湇鍔$15杩為棶](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497256&idx=1&sn=3b799c2d514aa25e85a6faa60d639a0b&chksm=cf222901f855a017b73356b99b830b8800a7a9172fab891c5759d8dd69a270872ea9480c0b7c&token=2001057130&lang=zh_CN#rd) +- [瀹囧畽鏉′竴闈細鍗侀亾缁忓吀闈㈣瘯棰樿В鏋怾(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247495342&idx=1&sn=54e1c0c16a6467001524c34818025331&chksm=cf223187f855b89140db5ca429e6efc19d0111abf7f36b78a0ecd73b00fded1ff1e7ba32a6f1&token=2001057130&lang=zh_CN#rd) +- [铓傝殎閲戞湇涓闈細鍗侀亾缁忓吀闈㈣瘯棰樿В鏋怾(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247493270&idx=1&sn=1c78a81d6e1bd0f0fd947fe8c3a33e32&chksm=cf2239bff855b0a9627855f20a17799e0506eb7548a409bfa0ee0450328d7519ec70f7b962cc&token=2001057130&lang=zh_CN#rd) +鈥 +## 2. 蹇呰冪粡鍏搁潰璇曢 +鈥 +- [Redis涓讳粠銆佸摠鍏点 Cluster闆嗙兢涓閿呯锛乚(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498254&idx=1&sn=6489360c3b226df9811e66cb40ec7656&chksm=cf222527f855ac3112628bcec7730064fee3fdbe869fbd0a7410c22766a0c036a7e5c1a69fa0&token=2001057130&lang=zh_CN#rd) +- [鎴戜滑涓轰粈涔堣鍒嗗簱鍒嗚〃锛焆(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498625&idx=1&sn=0d7bd9d1b46eeff4c715a6761355e9b0&chksm=cf2224a8f855adbea8931c8e011711f6c70cffeef8ddf8b87729c710eacef11b46eef80fda36&token=2001057130&lang=zh_CN#rd) +- [闈㈣瘯蹇呭锛氳亰鑱奙ySQL鐨勪富浠嶿(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497982&idx=1&sn=bb589329cceb5462fc41f66ec63dbf56&chksm=cf2227d7f855aec16dd4d3b3425c0401850eeaf2c9cdc82e82722d38a00c24ee9ccfa3353774&token=2001057130&lang=zh_CN#rd) +- [娑堟伅闃熷垪缁忓吀鍗佽繛闂甝(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497847&idx=1&sn=29a32672b712e7dfadfa36c9902b2ec7&chksm=cf22275ef855ae484fb3f51a5726e9a4bc45222e8fbbd33631d177dc4b5619c36889ea178463&token=2001057130&lang=zh_CN#rd) +- [鍏骞傜瓑璁捐](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497427&idx=1&sn=2ed160c9917ad989eee1ac60d6122855&chksm=cf2229faf855a0ecf5eb34c7335acdf6420426490ee99fc2b602d54ff4ffcecfdab24eeab0a3&token=2001057130&lang=zh_CN#rd) +- [鐪嬩竴閬嶅氨鐞嗚В锛氶浂鎷疯礉璇﹁В](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247496788&idx=1&sn=f65ddd10d16d8376efa0037762153932&chksm=cf222b7df855a26bad76249e7b77e28da3097b226f9165d79f5031516d9c345827fca901559c&token=2001057130&lang=zh_CN#rd) +- [鐪嬩竴閬嶅氨鐞嗚В锛欼O妯″瀷璇﹁В](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247496448&idx=1&sn=cd502f850290a25949dd4a11ac55a039&chksm=cf222c29f855a53f094bde2868900fa252b07385e73564e9ee9f0510cb4e74387d9d23ab67e6&token=2001057130&lang=zh_CN#rd) +- [鐪嬩竴閬嶅氨鐞嗚В锛歁VCC鍘熺悊璇﹁В](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247495277&idx=1&sn=a1812febb4246f824ce54d778f672025&chksm=cf223144f855b8528ad6cce707dc3a1b4d387817bd751dfab4f79dda90c6640f9763d25f3f33&token=2001057130&lang=zh_CN#rd) +- [2W瀛楋紒璇﹁В20閬揜edis缁忓吀闈㈣瘯棰橈紒锛堢弽钘忕増锛塢(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247494124&idx=1&sn=c185f7d999d5f006608d05707a8a7eea&chksm=cf2236c5f855bfd329c6e2ee27f23f8131ebcd312960190a10f1a819d67f07a21a08ad17f263&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [涓冪鏂规锛佹帰璁≧edis鍒嗗竷寮忛攣鐨勬纭娇鐢ㄥЭ鍔縘(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488142&idx=1&sn=79a304efae7a814b6f71bbbc53810c0c&chksm=cf21cda7f85644b11ff80323defb90193bc1780b45c1c6081f00da85d665fd9eb32cc934b5cf&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [闈㈣瘯蹇呭锛乀CP鍗忚缁忓吀鍗佷簲杩為棶锛乚(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490868&idx=1&sn=96889bfe6a97f9200fa2d682cf2f5d89&chksm=cf21c21df8564b0b0757df584560a69340b1775fe1c70b867439565969ec3aed19c442ff4eeb&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [2W瀛楋紒姊崇悊50閬撶粡鍏歌绠楁満缃戠粶闈㈣瘯棰橈紙鏀惰棌鐗堬級](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247492832&idx=1&sn=601fa1c340a313bc0f74bb75cdb6a95a&chksm=cf223bc9f855b2dfb8d0e74f3360e2edfe25c3a728fe17e9e80b6022340994fd9d9e1ca83ca8&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [ZooKeeper鐨勫崄浜岃繛闂紝浣犻《寰椾簡鍢涳紵](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488047&idx=1&sn=4913c7e1c3b8835f7512d8dc6b845727&chksm=cf21cd06f8564410cce6121230256facb1ab3b5a9ed35579896f428d84bdea7b86836109d575&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [50閬揓ava闆嗗悎缁忓吀闈㈣瘯棰橈紙鏀惰棌鐗堬級](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488007&idx=1&sn=c5c16c8ec916c791e776216f3177c7e2&chksm=cf21cd2ef85644382a985e9fed1956d6ee60c86ce69e65f31f775318435fdb86bf368e26edf2&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [100閬揗ySQL鏁版嵁搴撶粡鍏搁潰璇曢瑙f瀽锛堟敹钘忕増锛塢(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488000&idx=1&sn=1c38db7fd110bbcc1ffb2d72a56aaf25&chksm=cf21cd29f856443f25a3fe98ae8e888faceef9bee45df045969b2cffb105363dcc2a4480bb74&token=1495321435&lang=zh_CN&scene=21#wechat_redirect) +- [Spring 闈㈣瘯63闂甝(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497672&idx=1&sn=6ff0350e23d014b29a47bdec79af9ef5&chksm=cf2228e1f855a1f70fa78d9bd85c53dfbe154c1325aa1e203e4c918132c430d51bb68e961eda&token=2001057130&lang=zh_CN#rd) \ No newline at end of file From 03d9f811710a455cc2d7143459b4ab7ab3690d44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Sat, 23 Jul 2022 10:33:17 +0800 Subject: [PATCH 19/52] =?UTF-8?q?leetcode=E7=AE=97=E6=B3=95=E6=9B=B4?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../README.MD" | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 "letecode\350\247\243\351\242\230\347\256\227\346\263\225\344\273\213\347\273\215/README.MD" diff --git "a/letecode\350\247\243\351\242\230\347\256\227\346\263\225\344\273\213\347\273\215/README.MD" "b/letecode\350\247\243\351\242\230\347\256\227\346\263\225\344\273\213\347\273\215/README.MD" new file mode 100644 index 0000000..921f58b --- /dev/null +++ "b/letecode\350\247\243\351\242\230\347\256\227\346\263\225\344\273\213\347\273\215/README.MD" @@ -0,0 +1,13 @@ +## leetcode锛堟寔缁洿鏂颁腑锛 + +鍏虫敞鍏紬鍙凤細鎹$敯铻虹殑灏忕敺瀛 + +- [鐪嬩竴閬嶅氨鐞嗚В锛氬姩鎬佽鍒掕瑙(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247489016&idx=1&sn=bba3fb1a7a864b6ccefeb9f633751811&chksm=cf21cad1f85643c716c8c9396d3a6711f7722f8f81c8f40f5a91c525c98f73f5c476b7d49dd4&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [绋嬪簭鍛樺繀澶囩殑鍩烘湰绠楁硶锛氶掑綊璇﹁В](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488073&idx=1&sn=ec81b4a1f8b11ea59264b55e571fed91&chksm=cf21cd60f8564476952c5abb8ffa93fc38fde354a61ca5596e1875d35760383f3a92b2879e30&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [鐪嬩竴閬嶅氨鐞嗚В锛屽浘瑙e崟閾捐〃鍙嶈浆](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487967&idx=1&sn=e75373dcb0507081c242ba018b42ca82&chksm=cf21cef6f85647e0cbf0b2072eb1264a44abcaa9f4a0621ef8954a1b1d6719560f7f4cbbce60&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [闈㈣瘯蹇呭锛氬洖婧畻娉曡瑙(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497665&idx=1&sn=39011296fa99eda839ab2bbe83a42cdf&chksm=cf2228e8f855a1fe8f059130dc0b3d9ad34431a27bbe7e16f508b7e9340c24e2e4dfd8b414c2&token=1990771297&lang=zh_CN#rd) +- [leetcode蹇呭绠楁硶锛氳亰鑱婃粦鍔ㄧ獥鍙(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247496003&idx=1&sn=8c40eb3e611514f3bafb8d6873c03fda&chksm=cf222e6af855a77ce2fc36d4e4fc02945286300206f43975e30bc23b65c9ca67b6a1ac9806d1&token=1990771297&lang=zh_CN#rd) +- [浜斿垎閽熸悶瀹氳椽蹇冪畻娉曪紝浠庢涓嶆儳澶у巶闈㈣瘯](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490681&idx=1&sn=0388da1492fe0fdfa3ed6b1a43511328&chksm=cf21c350f8564a466d89578f73886eb462c6dd485f42e7953f126be5f9af49b3fb0be3457d52&token=1990771297&lang=zh_CN#rd) +- [鍙屾寚閽+褰掑苟鎺掑簭锛佸浘瑙f帓搴忛摼琛紒](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247496038&idx=1&sn=96a1a665e43ee9e3337e3d941db49f1e&chksm=cf222e4ff855a75919f0be68e78472199c44d0e9d94de6d5bf621a892ba211738d6f4dbd53ac&token=1990771297&lang=zh_CN#rd) +- [鍙屾寚閽堟妧宸(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488116&idx=1&sn=aeec0553e2317bef76d158d2b0e0b5a5&chksm=cf21cd5df856444b8963efc2745bce6801df4bc547b679ae8366fa8c3cd293f1f7c60c18e4f6&token=1990771297&lang=zh_CN#rd) +- [瀛楃涓插尮閰嶇畻娉曡瑙(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247494506&idx=1&sn=1f13b0cc1f03af464e1063be8ef1cb57&chksm=cf223443f855bd5597898126d12c6039f64da47b8a95714018203ee5e453950c802ebecfabe1&token=1990771297&lang=zh_CN#rd) From 2a7556216eafa7e97eff49ac14b80e1c8bf52943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Sat, 23 Jul 2022 10:35:11 +0800 Subject: [PATCH 20/52] =?UTF-8?q?Delete=20=E5=88=B7leetcode=E5=BF=85?= =?UTF-8?q?=E5=A4=87=E7=AE=97=E6=B3=95=20directory?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...04\345\210\222\350\257\246\350\247\243.md" | 440 ------------------ ...45\210\222\350\257\246\350\247\243.md.bak" | 0 ...22\345\275\222\350\257\246\350\247\243.md" | 380 --------------- 3 files changed, 820 deletions(-) delete mode 100644 "\345\210\267leetcode\345\277\205\345\244\207\347\256\227\346\263\225/\347\234\213\344\270\200\351\201\215\345\260\261\347\220\206\350\247\243\357\274\232\345\212\250\346\200\201\350\247\204\345\210\222\350\257\246\350\247\243.md" delete mode 100644 "\345\210\267leetcode\345\277\205\345\244\207\347\256\227\346\263\225/\347\234\213\344\270\200\351\201\215\345\260\261\347\220\206\350\247\243\357\274\232\345\212\250\346\200\201\350\247\204\345\210\222\350\257\246\350\247\243.md.bak" delete mode 100644 "\345\210\267leetcode\345\277\205\345\244\207\347\256\227\346\263\225/\351\200\222\345\275\222\350\257\246\350\247\243.md" diff --git "a/\345\210\267leetcode\345\277\205\345\244\207\347\256\227\346\263\225/\347\234\213\344\270\200\351\201\215\345\260\261\347\220\206\350\247\243\357\274\232\345\212\250\346\200\201\350\247\204\345\210\222\350\257\246\350\247\243.md" "b/\345\210\267leetcode\345\277\205\345\244\207\347\256\227\346\263\225/\347\234\213\344\270\200\351\201\215\345\260\261\347\220\206\350\247\243\357\274\232\345\212\250\346\200\201\350\247\204\345\210\222\350\257\246\350\247\243.md" deleted file mode 100644 index e8cc9b4..0000000 --- "a/\345\210\267leetcode\345\277\205\345\244\207\347\256\227\346\263\225/\347\234\213\344\270\200\351\201\215\345\260\261\347\220\206\350\247\243\357\274\232\345\212\250\346\200\201\350\247\204\345\210\222\350\257\246\350\247\243.md" +++ /dev/null @@ -1,440 +0,0 @@ - -### 前言 - -我们刷leetcode的时候,经常会遇到动态规划类型题目。动态规划问题非常非常经典,也很有技巧性,一般大厂都非常喜欢问。今天跟大家一起来学习动态规划的套路,文章如果有不正确的地方,欢迎大家指出哈,感谢感谢~ - -- 什么是动态规划? -- 动态规划的核心思想 -- 一个例子走进动态规划 -- 动态规划的解题套路 -- leetcode案例分析 - - -![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/01fdad6c74864d7da07193203c2dcbf4~tplv-k3u1fbpfcp-zoom-1.image) - - -公众号:**捡田螺的小男孩** - -### 什么是动态规划? - - -动态规划(英语:Dynamic programming,简称 DP),是一种在数学、管理科学、计算机科学、经济学和生物信息学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划常常适用于有重叠子问题和最优子结构性质的问题。 - -> dynamic programming is a method for solving a complex problem by breaking it down into a collection of simpler subproblems. - -以上定义来自维基百科,看定义感觉还是有点抽象。简单来说,动态规划其实就是,给定一个问题,我们把它拆成一个个子问题,直到子问题可以直接解决。然后呢,把子问题答案保存起来,以减少重复计算。再根据子问题答案反推,得出原问题解的一种方法。 -> 一般这些子问题很相似,可以通过函数关系式递推出来。然后呢,动态规划就致力于解决每个子问题一次,减少重复计算,比如斐波那契数列就可以看做入门级的经典动态规划问题。 - - -### 动态规划核心思想 - -动态规划最核心的思想,就在于**拆分子问题,记住过往,减少重复计算**。 - -![动态规划在于记住过往](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d26f967ff6e447d291b0b196c4edaa07~tplv-k3u1fbpfcp-watermark.image) - -我们来看下,网上比较流行的一个例子: -> - A : "1+1+1+1+1+1+1+1 =?" -> - A : "上面等式的值是多少" -> - B : 计算 "8" -> - A : 在上面等式的左边写上 "1+" 呢? -> - A : "此时等式的值为多少" -> - B : 很快得出答案 "9" -> - A : "你怎么这么快就知道答案了" -> - A : "只要在8的基础上加1就行了" -> - A : "所以你不用重新计算,因为你记住了第一个等式的值为8!动态规划算法也可以说是 '记住求过的解来节省时间'" - -### 一个例子带你走进动态规划 -- 青蛙跳阶问题 - -#### 暴力递归 - -> leetcode原题:一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 10 级的台阶总共有多少种跳法。 - -有些小伙伴第一次见这个题的时候,可能会有点蒙圈,不知道怎么解决。其实可以试想: -> - 要想跳到第10级台阶,要么是先跳到第9级,然后再跳1级台阶上去;要么是先跳到第8级,然后一次迈2级台阶上去。 -> - 同理,要想跳到第9级台阶,要么是先跳到第8级,然后再跳1级台阶上去;要么是先跳到第7级,然后一次迈2级台阶上去。 -> - 要想跳到第8级台阶,要么是先跳到第7级,然后再跳1级台阶上去;要么是先跳到第6级,然后一次迈2级台阶上去。 - -假设跳到第n级台阶的跳数我们定义为f(n),很显然就可以得出以下公式: - -``` -f(10) = f(9)+f(8) -f (9) = f(8) + f(7) -f (8) = f(7) + f(6) -... -f(3) = f(2) + f(1) - -即通用公式为: f(n) = f(n-1) + f(n-2) -``` - -那f(2) 或者 f(1) 等于多少呢? -- 当只有2级台阶时,有两种跳法,第一种是直接跳两级,第二种是先跳一级,然后再跳一级。即f(2) = 2; -- 当只有1级台阶时,只有一种跳法,即f(1)= 1; - - -因此可以用递归去解决这个问题: -``` -class Solution { - public int numWays(int n) { - if(n == 1){ - return 1; - } - if(n == 2){ - return 2; - } - return numWays(n-1) + numWays(n-2); - } -} -``` - -去leetcode提交一下,发现有问题,超出时间限制了 - -![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3e0608ec89a246568e01c7ba4b8f50d8~tplv-k3u1fbpfcp-zoom-1.image) - - -为什么超时了呢?递归耗时在哪里呢?先画出**递归树**看看: - - -![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2dd95840552e4a7db9536884b7a9b558~tplv-k3u1fbpfcp-zoom-1.image) - -- 要计算原问题 f(10),就需要先计算出子问题 f(9) 和 f(8) -- 然后要计算 f(9),又要先算出子问题 f(8) 和 f(7),以此类推。 -- 一直到 f(2) 和 f(1),递归树才终止。 - -我们先来看看这个递归的时间复杂度吧: - - -``` -递归时间复杂度 = 解决一个子问题时间*子问题个数 -``` - -- 一个子问题时间 = f(n-1)+f(n-2),也就是一个加法的操作,所以复杂度是 O(1); -- 问题个数 = 递归树节点的总数,递归树的总节点 = 2^n-1,所以是复杂度O(2^n)。 - -因此,青蛙跳阶,递归解法的时间复杂度 = O(1) * O(2^n) = O(2^n),就是指数级别的,爆炸增长的,如果n比较大的话,超时很正常的了。 - -回过头来,你仔细观察这颗递归树,你会发现存在大量重复计算,比如f(8)被计算了两次,f(7)被重复计算了3次...所以这个递归算法低效的原因,就是**存在大量的重复计算**! - -既然存在大量重复计算,那么我们可以先把计算好的答案存下来,即造一个备忘录,等到下次需要的话,先去备忘录查一下,如果有,就直接取就好了,备忘录没有才开始计算,那就可以省去重新重复计算的耗时啦!这就是带备忘录的解法。 - - - -#### 带备忘录的递归解法(自顶向下) - -一般使用一个数组或者一个哈希map充当这个**备忘录**。 -- 第一步,f(10)= f(9) + f(8),f(9) 和f(8)都需要计算出来,然后再加到备忘录中,如下: - - - -![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/94484290462e45c799609b0a581b14b0~tplv-k3u1fbpfcp-zoom-1.image) - -- 第二步, f(9) = f(8)+ f(7),f(8)= f(7)+ f(6), 因为 f(8) 已经在备忘录中啦,所以可以省掉,f(7),f(6)都需要计算出来,加到备忘录中~ - - -![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/12900b17d77f4adfbdb71920f729d61a~tplv-k3u1fbpfcp-zoom-1.image) - - -第三步, f(8) = f(7)+ f(6),发现f(8),f(7),f(6)全部都在备忘录上了,所以都可以剪掉。 - - -![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9a8c7ba6b5ae413799c6a33490bb1f8f~tplv-k3u1fbpfcp-zoom-1.image) - -所以呢,用了备忘录递归算法,递归树变成光秃秃的树干咯,如下: - -![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/18a78d6b99a84ff8a1df834f3c085014~tplv-k3u1fbpfcp-zoom-1.image) - -带**备忘录**的递归算法,子问题个数=树节点数=n,解决一个子问题还是O(1),所以带**备忘录**的递归算法的时间复杂度是O(n)。接下来呢,我们用带**备忘录**的递归算法去撸代码,解决这个青蛙跳阶问题的超时问题咯~,代码如下: - - - -``` -public class Solution { - //使用哈希map,充当备忘录的作用 - Map tempMap = new HashMap(); - public int numWays(int n) { - // n = 0 也算1种 - if (n == 0) { - return 1; - } - if (n <= 2) { - return n; - } - //先判断有没计算过,即看看备忘录有没有 - if (tempMap.containsKey(n)) { - //备忘录有,即计算过,直接返回 - return tempMap.get(n); - } else { - // 备忘录没有,即没有计算过,执行递归计算,并且把结果保存到备忘录map中,对1000000007取余(这个是leetcode题目规定的) - tempMap.put(n, (numWays(n - 1) + numWays(n - 2)) % 1000000007); - return tempMap.get(n); - } - } -} -``` -去leetcode提交一下,如图,稳了: - -![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e5f0fb1998c542dc8cb3826de800f443~tplv-k3u1fbpfcp-zoom-1.image) - -其实,还可以用动态规划解决这道题。 - -#### 自底向上的动态规划 - -动态规划跟带备忘录的递归解法基本思想是一致的,都是减少重复计算,时间复杂度也都是差不多。但是呢: -- 带备忘录的递归,是从f(10)往f(1)方向延伸求解的,所以也称为**自顶向下**的解法。 -- 动态规划从较小问题的解,由交叠性质,逐步决策出较大问题的解,它是从f(1)往f(10)方向,往上推求解,所以称为**自底向上**的解法。 - - -动态规划有几个典型特征,**最优子结构、状态转移方程、边界、重叠子问题**。在青蛙跳阶问题中: -- f(n-1)和f(n-2) 称为 f(n) 的最优子结构 -- f(n)= f(n-1)+f(n-2)就称为状态转移方程 -- f(1) = 1, f(2) = 2 就是边界啦 -- 比如f(10)= f(9)+f(8),f(9) = f(8) + f(7) ,f(8)就是重叠子问题。 - -我们来看下自底向上的解法,从f(1)往f(10)方向,想想是不是直接一个for循环就可以解决啦,如下: - -![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8e21b14d47e64afa958506d49972827b~tplv-k3u1fbpfcp-zoom-1.image) - -带备忘录的递归解法,空间复杂度是O(n),但是呢,仔细观察上图,可以发现,f(n)只依赖前面两个数,所以只需要两个变量a和b来存储,就可以满足需求了,因此空间复杂度是O(1)就可以啦 - -![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8b202b2364eb4aae9122cfa8474c045e~tplv-k3u1fbpfcp-zoom-1.image) - -动态规划实现代码如下: - -``` -public class Solution { - public int numWays(int n) { - if (n<= 1) { - return 1; - } - if (n == 2) { - return 2; - } - int a = 1; - int b = 2; - int temp = 0; - for (int i = 3; i <= n; i++) { - temp = (a + b)% 1000000007; - a = b; - b = temp; - } - return temp; - } - } -``` - -### 动态规划的解题套路 - -#### 什么样的问题可以考虑使用动态规划解决呢? - -> 如果一个问题,可以把所有可能的答案穷举出来,并且穷举出来后,发现存在重叠子问题,就可以考虑使用动态规划。 - -比如一些求最值的场景,如**最长递增子序列、最小编辑距离、背包问题、凑零钱问题**等等,都是动态规划的经典应用场景。 - - -### 动态规划的解题思路 - - -动态规划的核心思想就是**拆分子问题,记住过往,减少重复计算。** 并且动态规划一般都是自底向上的,因此到这里,基于**青蛙跳阶**问题,我总结了一下我做动态规划的思路: - -- 穷举分析 -- 确定边界 -- 找出规律,确定最优子结构 -- 写出状态转移方程 - - -#### 1. 穷举分析 - - -- 当台阶数是1的时候,有一种跳法,f(1) =1 -- 当只有2级台阶时,有两种跳法,第一种是直接跳两级,第二种是先跳一级,然后再跳一级。即f(2) = 2; -- 当台阶是3级时,想跳到第3级台阶,要么是先跳到第2级,然后再跳1级台阶上去,要么是先跳到第 1级,然后一次迈 2 级台阶上去。所以f(3) = f(2) + f(1) =3 -- 当台阶是4级时,想跳到第3级台阶,要么是先跳到第3级,然后再跳1级台阶上去,要么是先跳到第 2级,然后一次迈 2 级台阶上去。所以f(4) = f(3) + f(2) =5 -- 当台阶是5级时...... - -![自底向上的动态规划](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/29cd6d0d31514336baf9905f8084a624~tplv-k3u1fbpfcp-zoom-1.image) - - - -#### 2. 确定边界 - -通过穷举分析,我们发现,当台阶数是1的时候或者2的时候,可以明确知道青蛙跳法。f(1) =1,f(2) = 2,当台阶n>=3时,已经呈现出规律f(3) = f(2) + f(1) =3,因此f(1) =1,f(2) = 2就是青蛙跳阶的边界。 - - -#### 3. 找规律,确定最优子结构 - -n>=3时,已经呈现出规律 f(n) = f(n-1) + f(n-2) ,因此,f(n-1)和f(n-2) 称为 f(n) 的最优子结构。什么是最优子结构?有这么一个解释: - -> 一道动态规划问题,其实就是一个递推问题。假设当前决策结果是f(n),则最优子结构就是要让 f(n-k) 最优,最优子结构性质就是能让转移到n的状态是最优的,并且与后面的决策没有关系,即让后面的决策安心地使用前面的局部最优解的一种性质 - - -#### 4, 写出状态转移方程 - -通过前面3步,穷举分析,确定边界,最优子结构,我们就可以得出状态转移方程啦: - -![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4fb4cd7257ff4fcbac9d87be96f353bd~tplv-k3u1fbpfcp-zoom-1.image) - -#### 5. 代码实现 - -我们实现代码的时候,一般注意从底往上遍历哈,然后关注下边界情况,空间复杂度,也就差不多啦。动态规划有个框架的,大家实现的时候,可以考虑适当参考一下: - - -``` -dp[0][0][...] = 边界值 -for(状态1 :所有状态1的值){ - for(状态2 :所有状态2的值){ - for(...){ - //状态转移方程 - dp[状态1][状态2][...] = 求最值 - } - } -} -``` - - -### leetcode案例分析 - -我们一起来分析一道经典leetcode题目吧 - -> 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。 - -示例 1: - -``` -输入:nums = [10,9,2,5,3,7,101,18] -输出:4 -解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。 -``` - -示例 2: - - -``` -输入:nums = [0,1,0,3,2,3] -输出:4 -``` - -我们按照以上动态规划的解题思路, - -- 穷举分析 -- 确定边界 -- 找规律,确定最优子结构 -- 状态转移方程 - - -#### 1.穷举分析 - - -因为动态规划,核心思想包括**拆分子问题,记住过往,减少重复计算。** 所以我们在思考原问题:**数组num[i]的最长递增子序列长度时**,可以思考下**相关子问题**,比如原问题是否跟**子问题**num[i-1]的最长递增子序列长度有关呢? - -##### 自顶向上的穷举 - -这里观察规律,显然是有关系的,我们还是遵循动态规划**自底向上**的原则,基于示例1的数据,从数组只有一个元素开始分析。 - -- 当nums只有一个元素10时,最长递增子序列是[10],长度是1. -- 当nums需要加入一个元素9时,最长递增子序列是[10]或者[9],长度是1。 -- 当nums再加入一个元素2时,最长递增子序列是[10]或者[9]或者[2],长度是1。 -- 当nums再加入一个元素5时,最长递增子序列是[2,5],长度是2。 -- 当nums再加入一个元素3时,最长递增子序列是[2,5]或者[2,3],长度是2。 -- 当nums再加入一个元素7时,,最长递增子序列是[2,5,7]或者[2,3,7],长度是3。 -- 当nums再加入一个元素101时,最长递增子序列是[2,5,7,101]或者[2,3,7,101],长度是4。 -- 当nums再加入一个元素18时,最长递增子序列是[2,5,7,101]或者[2,3,7,101]或者[2,5,7,18]或者[2,3,7,18],长度是4。 -- 当nums再加入一个元素7时,最长递增子序列是[2,5,7,101]或者[2,3,7,101]或者[2,5,7,18]或者[2,3,7,18],长度是4. - -##### 分析找规律,拆分子问题 -通过上面分析,我们可以**发现一个规律**: - -如果新加入一个元素nums[i], 最长递增子序列要么**是以nums[i]结尾的递增子序列**,要么就是**nums[i-1]的最长递增子序列**。看到这个,是不是很开心,nums[i]的最长递增子序列已经跟**子问题** nums[i-1]的最长递增子序列有关联了。 - -``` -原问题数组nums[i]的最长递增子序列 = 子问题数组nums[i-1]的最长递增子序列/nums[i]结尾的最长递增子序列 -``` - -是不是感觉成功了一半呢?但是**如何把nums[i]结尾的递增子序列也转化为对应的子问题**呢?要是nums[i]结尾的递增子序列也跟nums[i-1]的最长递增子序列有关就好了。又或者nums[i]结尾的最长递增子序列,跟前面子问题num[j](0= - nums[3]=5,以```5```结尾的最长子序列就是```[2,5]```,因为从数组下标```0到3```遍历,只找到了子序列```[2]```比```5```小,所以就是```[2]+[5]```啦,即```dp[4]=2``` -> - nums[4]=3,以```3```结尾的最长子序列就是```[2,3]```,因为从数组下标```0到4```遍历,只找到了子序列```[2]```比```3```小,所以就是```[2]+[3]```啦,即```dp[4]=2``` -> - nums[5]=7,以```7```结尾的最长子序列就是```[2,5,7]```和```[2,3,7]```,因为从数组下标```0到5```遍历,找到```2,5和3```都比7小,所以就有```[2,7],[5,7],[3,7],[2,5,7]和[2,3,7]```这些子序列,最长子序列就是```[2,5,7]和[2,3,7]```,它俩不就是以```5```结尾和```3```结尾的最长递增子序列+[7]来的嘛!所以,**```dp[5]=3 =dp[3]+1=dp[4]+1```**。 - - -很显然有这个规律:一个以nums[i]结尾的数组nums -- 如果存在j属于区间[0,i-1],并且num[i]>num[j]的话,则有,dp(i) =max(dp(j))+1, - -#### 最简单的边界情况 - -当nums数组只有一个元素时,最长递增子序列的长度dp(1)=1,当nums数组有两个元素时,dp(2) =2或者1, -因此边界就是dp(1)=1。 - -#### 确定最优子结构 - -从穷举分析,我们可以得出,以下的最优结构: - -``` -dp(i) =max(dp(j))+1,存在j属于区间[0,i-1],并且num[i]>num[j]。 -``` -**max(dp(j))** 就是最优子结构。 - -#### 状态转移方程 - -通过前面分析,我们就可以得出状态转移方程啦: - -![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/457ce281c1ec4e91b8c868aa593e41b6~tplv-k3u1fbpfcp-zoom-1.image) - -所以数组num[i]的最长递增子序列就是: -``` -最长递增子序列 =max(dp[i]) -``` - - - - -#### 代码实现 - -``` -class Solution { - public int lengthOfLIS(int[] nums) { - if (nums.length == 0) { - return 0; - } - int[] dp = new int[nums.length]; - //初始化就是边界情况 - dp[0] = 1; - int maxans = 1; - //自底向上遍历 - for (int i = 1; i < nums.length; i++) { - dp[i] = 1; - //从下标0到i遍历 - for (int j = 0; j < i; j++) { - //找到前面比nums[i]小的数nums[j],即有dp[i]= dp[j]+1 - if (nums[j] < nums[i]) { - //因为会有多个小于nums[i]的数,也就是会存在多种组合了嘛,我们就取最大放到dp[i] - dp[i] = Math.max(dp[i], dp[j] + 1); - } - } - //求出dp[i]后,dp最大那个就是nums的最长递增子序列啦 - maxans = Math.max(maxans, dp[i]); - } - return maxans; - } -} -``` - - - - - - - - - - - - - diff --git "a/\345\210\267leetcode\345\277\205\345\244\207\347\256\227\346\263\225/\347\234\213\344\270\200\351\201\215\345\260\261\347\220\206\350\247\243\357\274\232\345\212\250\346\200\201\350\247\204\345\210\222\350\257\246\350\247\243.md.bak" "b/\345\210\267leetcode\345\277\205\345\244\207\347\256\227\346\263\225/\347\234\213\344\270\200\351\201\215\345\260\261\347\220\206\350\247\243\357\274\232\345\212\250\346\200\201\350\247\204\345\210\222\350\257\246\350\247\243.md.bak" deleted file mode 100644 index e69de29..0000000 diff --git "a/\345\210\267leetcode\345\277\205\345\244\207\347\256\227\346\263\225/\351\200\222\345\275\222\350\257\246\350\247\243.md" "b/\345\210\267leetcode\345\277\205\345\244\207\347\256\227\346\263\225/\351\200\222\345\275\222\350\257\246\350\247\243.md" deleted file mode 100644 index fb5ecdb..0000000 --- "a/\345\210\267leetcode\345\277\205\345\244\207\347\256\227\346\263\225/\351\200\222\345\275\222\350\257\246\350\247\243.md" +++ /dev/null @@ -1,380 +0,0 @@ -### 鍓嶈█ -閫掑綊鏄竴绉嶉潪甯搁噸瑕佺殑绠楁硶鎬濇兂锛屾棤璁轰綘鏄墠绔紑鍙戯紝杩樻槸鍚庣寮鍙戯紝閮介渶瑕佹帉鎻″畠銆傚湪鏃ュ父宸ヤ綔涓紝缁熻鏂囦欢澶瑰ぇ灏忥紝瑙f瀽xml鏂囦欢绛夌瓑锛岄兘闇瑕佺敤鍒伴掑綊绠楁硶銆傚畠澶熀纭澶噸瑕佷簡锛岃繖涔熸槸涓轰粈涔堥潰璇曠殑鏃跺欙紝闈㈣瘯瀹樼粡甯歌鎴戜滑鎵嬪啓閫掑綊绠楁硶銆傛湰鏂囧憿锛屽皢璺熷ぇ瀹朵竴璧峰涔犻掑綊绠楁硶~ - -- 浠涔堟槸閫掑綊锛 -- 閫掑綊鐨勭壒鐐 -- 閫掑綊涓庢爤鐨勫叧绯 -- 閫掑綊搴旂敤鍦烘櫙 -- 閫掑綊瑙i鎬濊矾 -- leetcode妗堜緥鍒嗘瀽 -- 閫掑綊鍙兘瀛樺湪鐨勯棶棰樹互鍙婅В鍐虫柟妗 - - -**鍏紬鍙凤細鎹$敯铻虹殑灏忕敺瀛** - -### 浠涔堟槸閫掑綊锛 - -閫掑綊锛屽湪璁$畻鏈虹瀛︿腑鏄寚涓绉嶉氳繃閲嶅灏嗛棶棰樺垎瑙d负鍚岀被鐨勫瓙闂鑰岃В鍐抽棶棰樼殑鏂规硶銆傜畝鍗曟潵璇达紝閫掑綊琛ㄧ幇涓哄嚱鏁拌皟鐢ㄥ嚱鏁版湰韬傚湪鐭ヤ箮鐪嬪埌涓涓瘮鍠婚掑綊鐨勪緥瀛愶紝涓汉瑙夊緱闈炲父褰㈣薄锛屽ぇ瀹剁湅涓涓嬶細 - -> 閫掑綊鏈鎭板綋鐨勬瘮鍠伙紝灏辨槸鏌ヨ瘝鍏搞傛垜浠娇鐢ㄧ殑璇嶅吀锛屾湰韬氨鏄掑綊锛屼负浜嗚В閲婁竴涓瘝锛岄渶瑕佷娇鐢ㄦ洿澶氱殑璇嶃傚綋浣犳煡涓涓瘝锛屽彂鐜拌繖涓瘝鐨勮В閲婁腑鏌愪釜璇嶄粛鐒朵笉鎳傦紝浜庢槸浣犲紑濮嬫煡杩欑浜屼釜璇嶏紝鍙儨锛岀浜屼釜璇嶉噷浠嶇劧鏈変笉鎳傜殑璇嶏紝浜庢槸鏌ョ涓変釜璇嶏紝杩欐牱鏌ヤ笅鍘伙紝鐩村埌鏈変竴涓瘝鐨勮В閲婃槸浣犲畬鍏ㄨ兘鐪嬫噦鐨勶紝閭d箞閫掑綊璧板埌浜嗗敖澶达紝鐒跺悗浣犲紑濮嬪悗閫锛岄愪釜鏄庣櫧涔嬪墠鏌ヨ繃鐨勬瘡涓涓瘝锛屾渶缁堬紝浣犳槑鐧戒簡鏈寮濮嬮偅涓瘝鐨勬剰鎬濄 - -鏉ヨ瘯璇曟按锛岀湅涓涓掑綊鐨勪唬鐮佷緥瀛愬惂锛屽涓嬶細 -``` -public int sum(int n) { - if (n <= 1) { - return 1; - } - return sum(n - 1) + n; -} -``` - -### 閫掑綊鐨勭壒鐐 - -瀹為檯涓婏紝閫掑綊鏈変袱涓樉钁楃殑鐗瑰緛,缁堟鏉′欢鍜岃嚜韬皟鐢: -- 鑷韩璋冪敤锛氬師闂鍙互鍒嗚В涓哄瓙闂锛屽瓙闂鍜屽師闂鐨勬眰瑙f柟娉曟槸涓鑷寸殑锛屽嵆閮芥槸璋冪敤鑷韩鐨勫悓涓涓嚱鏁般 -- 缁堟鏉′欢锛氶掑綊蹇呴』鏈変竴涓粓姝㈢殑鏉′欢锛屽嵆涓嶈兘鏃犻檺寰幆鍦拌皟鐢ㄦ湰韬 - -缁撳悎浠ヤ笂demo浠g爜渚嬪瓙锛岀湅涓嬮掑綊鐨勭壒鐐癸細 - -![](https://imgkr2.cn-bj.ufileos.com/94f250ad-41ea-4760-ae79-060f91605aeb.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=gQGMVnPTDwM%252F5AX2OrH%252F0ugG9MA%253D&Expires=1602691176) - - -### 閫掑綊涓庢爤鐨勫叧绯 -鍏跺疄锛岄掑綊鐨勮繃绋嬶紝鍙互鐞嗚В涓哄嚭鍏ユ爤鐨勮繃绋嬬殑锛岃繖涓瘮鍠诲憿锛屽彧鏄负浜嗘柟渚胯鑰呮湅鍙嬫洿濂界悊瑙i掑綊鍝堛備互涓婁唬鐮佷緥瀛愯绠梥um锛坣=3锛夌殑鍑哄叆鏍堝浘濡備笅锛 -![](https://imgkr2.cn-bj.ufileos.com/d4f09883-727b-44b6-90e0-dfad9d768b8c.jpg?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=V%252BDCQxqTa24HsCxQcooMJ%252FzuOHc%253D&Expires=1602692111) - - -涓轰簡鏇村鏄撶悊瑙d竴浜涳紝鎴戜滑鏉ョ湅涓涓 鍑芥暟sum锛坣=5锛夌殑閫掑綊鎵ц杩囩▼锛屽涓嬶細 -![](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f587c37fea484be192fec7710634ec47~tplv-k3u1fbpfcp-zoom-1.image) - -- 璁$畻sum锛5锛夋椂锛屽厛sum锛5锛夊叆鏍堬紝鐒跺悗鍘熼棶棰榮um锛5锛夋媶鍒嗕负瀛愰棶棰榮um锛4锛夛紝鍐嶅叆鏍堬紝鐩村埌缁堟鏉′欢sum锛坣=1锛=1锛屽氨寮濮嬪嚭鏍堛 -- sum锛1锛夊嚭鏍堝悗锛宻um锛2锛夊紑濮嬪嚭鏍堬紝鎺ョ潃sum锛3锛夈 -- 鏈鍚庡憿,sum锛1锛夊氨鏄悗杩涘厛鍑猴紝sum锛5锛夋槸鍏堣繘鍚庡嚭锛屽洜姝ら掑綊杩囩▼鍙互鐞嗚В涓烘爤鍑哄叆杩囩▼鍟 - - -### 閫掑綊鐨勭粡鍏稿簲鐢ㄥ満鏅 -鍝簺闂鎴戜滑鍙互鑰冭檻浣跨敤閫掑綊鏉ヨВ鍐冲憿锛熷嵆閫掑綊鐨勫簲鐢ㄥ満鏅竴鑸湁鍝簺鍛紵 -- 闃朵箻闂 -- 浜屽弶鏍戞繁搴 -- 姹夎濉旈棶棰 -- 鏂愭尝閭e鏁板垪 -- 蹇熸帓搴忋佸綊骞舵帓搴忥紙鍒嗘不绠楁硶涔熶娇鐢ㄩ掑綊瀹炵幇锛 -- 閬嶅巻鏂囦欢锛岃В鏋恱ml鏂囦欢 - -### 閫掑綊瑙i鎬濊矾 -瑙e喅閫掑綊闂涓鑸氨涓夋鏇诧紝鍒嗗埆鏄細 -- 绗竴姝ワ紝瀹氫箟鍑芥暟鍔熻兘 -- 绗簩姝ワ紝瀵绘壘閫掑綊缁堟鏉′欢 -- 绗簩姝ワ紝閫掓帹鍑芥暟鐨勭瓑浠峰叧绯诲紡 - -杩欎釜閫掑綊瑙i涓夋澘鏂х悊瑙h捣鏉ユ湁鐐规娊璞★紝鎴戜滑鎷块樁涔橀掑綊渚嬪瓙鏉ュ柕鍠靛惂~ - -#### 1.瀹氫箟鍑芥暟鍔熻兘 -瀹氫箟鍑芥暟鍔熻兘锛屽氨鏄锛屼綘杩欎釜鍑芥暟鏄共鍢涚殑锛屽仛浠涔堜簨鎯咃紝鎹㈠彞璇濊锛屼綘瑕佺煡閬撻掑綊鍘熼棶棰樻槸浠涔堝憖锛熸瘮濡備綘闇瑕佽В鍐抽樁涔橀棶棰橈紝瀹氫箟鐨勫嚱鏁板姛鑳藉氨鏄痭鐨勯樁涔橈紝濡備笅锛 -``` -//n鐨勯樁涔橈紙n涓哄ぇ浜0鐨勮嚜鐒舵暟锛 -int factorial (int n){ - -} -``` - -#### 2.瀵绘壘閫掑綊缁堟鏉′欢 -閫掑綊鐨勪竴涓吀鍨嬬壒寰佸氨鏄繀椤绘湁涓涓粓姝㈢殑鏉′欢锛屽嵆涓嶈兘鏃犻檺寰幆鍦拌皟鐢ㄦ湰韬傛墍浠ワ紝鐢ㄩ掑綊鎬濊矾鍘昏В鍐抽棶棰樼殑鏃跺欙紝灏遍渶瑕佸鎵鹃掑綊缁堟鏉′欢鏄粈涔堛傛瘮濡傞樁涔橀棶棰橈紝褰搉=1鐨勬椂鍊欙紝涓嶇敤鍐嶅線涓嬮掑綊浜嗭紝鍙互璺冲嚭寰幆鍟︼紝n=1灏卞彲浠ヤ綔涓洪掑綊鐨勭粓姝㈡潯浠讹紝濡備笅锛 -``` -//n鐨勯樁涔橈紙n涓哄ぇ浜0鐨勮嚜鐒舵暟锛 -int factorial (int n){ - if(n==1){ - return 1; - } -} -``` - -#### 3.閫掓帹鍑芥暟鐨勭瓑浠峰叧绯诲紡 -閫掑綊鐨**鏈箟**锛屽氨鏄師闂鍙互鎷嗕负鍚岀被涓旀洿瀹规槗瑙e喅鐨勫瓙闂锛屽嵆**鍘熼棶棰樺拰瀛愰棶棰橀兘鍙互鐢ㄥ悓涓涓嚱鏁板叧绯昏〃绀恒傞掓帹鍑芥暟鐨勭瓑浠峰叧绯诲紡锛岃繖涓楠ゅ氨绛変环浜庡鎵惧師闂涓庡瓙闂鐨勫叧绯伙紝濡備綍鐢ㄤ竴涓叕寮忔妸杩欎釜鍑芥暟琛ㄨ揪娓呮**銆傞樁涔樼殑鍏紡灏卞彲浠ヨ〃绀轰负 f(n) = n * f(n-1), 鍥犳锛岄樁涔樼殑閫掑綊绋嬪簭浠g爜灏卞彲浠ュ啓鎴愯繖鏍凤紝濡備笅锛 -``` -int factorial (int n){ - if(n==1){ - return 1; - } - return n * factorial(n-1); -} -``` -**娉ㄦ剰鍟**锛屼笉鏄墍鏈夐掓帹鍑芥暟鐨勭瓑浠峰叧绯婚兘鍍忛樁涔樿繖涔堢畝鍗曪紝涓涓嬪瓙灏辫兘鎺ㄥ鍑烘潵銆傞渶瑕佹垜浠鎺ヨЕ锛屽绉疮锛屽鎬濊冿紝澶氱粌涔犻掑綊棰樼洰婊磣 - -### leetcode妗堜緥鍒嗘瀽 - -鏉ュ垎鏋愪竴閬搇eetcode閫掑綊鐨勭粡鍏搁鐩惂~ -> 鍘熼閾炬帴鍦ㄨ繖閲屽搱锛歨ttps://leetcode-cn.com/problems/invert-binary-tree/ - -**棰樼洰锛** 缈昏浆涓妫典簩鍙夋爲銆 - -杈撳叆锛 -``` - 4 - / \ - 2 7 - / \ / \ -1 3 6 9 -``` -杈撳嚭锛 -``` - 4 - / \ - 7 2 - / \ / \ -9 6 3 1 -``` - -鎴戜滑鎸夌収浠ヤ笂閫掑綊瑙i鐨勪笁鏉挎枾鏉ワ細 - -**1. 瀹氫箟鍑芥暟鍔熻兘** - -鍑芥暟鍔熻兘锛堝嵆杩欎釜閫掑綊鍘熼棶棰樻槸锛夛紝缁欏嚭涓棰楁爲锛岀劧鍚庣炕杞畠锛屾墍浠ワ紝鍑芥暟鍙互瀹氫箟涓猴細 -``` -//缈昏浆涓棰椾簩鍙夋爲 -public TreeNode invertTree(TreeNode root) { -} - -/** - * Definition for a binary tree node. - * public class TreeNode { - * int val; - * TreeNode left; - * TreeNode right; - * TreeNode(int x) { val = x; } - * } - */ -``` - -**2.瀵绘壘閫掑綊缁堟鏉′欢** - -杩欐5鏍戜粈涔堟椂鍊欎笉鐢ㄧ炕杞憿锛熷綋鐒舵槸褰撳墠鑺傜偣涓簄ull鎴栬呭綋鍓嶈妭鐐逛负鍙跺瓙鑺傜偣鐨勬椂鍊欏暒銆傚洜姝わ紝鍔犱笂缁堟鏉′欢灏辨槸锛 -``` -//缈昏浆涓棰椾簩鍙夋爲 -public TreeNode invertTree(TreeNode root) { - if(root==null || (root.left ==null && root.right ==null)){ - return root; - } -} -``` - -**3. 閫掓帹鍑芥暟鐨勭瓑浠峰叧绯诲紡** - -鍘熼棶棰樹箣浣犺缈昏浆涓棰楁爲锛屾槸涓嶆槸鍙互鎷嗗垎涓哄瓙闂锛屽垎鍒炕杞畠鐨勫乏瀛愭爲鍜屽彸瀛愭爲锛熷瓙闂涔嬬炕杞畠鐨勫乏瀛愭爲锛屾槸涓嶆槸鍙堝彲浠ユ媶鍒嗕负锛岀炕杞畠宸﹀瓙鏍戠殑宸﹀瓙鏍戜互鍙婂畠宸﹀瓙鏍戠殑鍙冲瓙鏍戯紵鐒跺悗涓鐩寸炕杞埌鍙跺瓙鑺傜偣涓烘銆傚棷锛岀湅鍥剧悊瑙d竴涓嬪挴~ -![](https://imgkr2.cn-bj.ufileos.com/938b0fcf-7ab2-4c8f-833f-382be7f8b46d.jpg?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=9BiTdqNsNnz%252FqynFWb52CMQkMnU%253D&Expires=1602692880) - - -棣栧厛锛屼綘瑕佺炕杞牴鑺傜偣涓4鐨勬爲锛屽氨闇瑕**缈昏浆瀹冪殑宸﹀瓙鏍戯紙鏍硅妭鐐逛负2锛夊拰鍙冲瓙鏍(鏍硅妭鐐逛负7锛**銆傝繖灏辨槸閫掑綊鐨**閫**鐨勮繃绋嬪暒 -![](https://imgkr2.cn-bj.ufileos.com/381538fe-fe34-4cae-9d1e-b5894ea542b2.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=HK51fa4jYvucnu6r3829BqFWcys%253D&Expires=1602693025) - - -鐒跺悗鍛紝鏍硅妭鐐逛负2鐨勬爲锛屼笉鏄彾瀛愯妭鐐癸紝浣犻渶瑕佺户缁**缈昏浆瀹冪殑宸﹀瓙鏍戯紙鏍硅妭鐐逛负1锛夊拰鍙冲瓙鏍戯紙鏍硅妭鐐逛负3锛**銆傚洜涓鸿妭鐐1鍜3閮芥槸**鍙跺瓙鑺傜偣**浜嗭紝鎵浠ュ氨杩斿洖鍟︺傝繖涔熸槸閫掑綊鐨**閫**鐨勮繃绋媬 - -![](https://imgkr2.cn-bj.ufileos.com/c9195723-d803-4b76-9cb3-bec8192a696f.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=n5Ct31iSBnMmK2HJ7kB0I6ZhEYs%253D&Expires=1602693145) - -鍚岀悊锛屾牴鑺傜偣涓7鐨勬爲锛屼篃涓嶆槸鍙跺瓙鑺傜偣锛屼綘闇瑕佺炕杞**瀹冪殑宸﹀瓙鏍戯紙鏍硅妭鐐逛负6锛夊拰鍙冲瓙鏍戯紙鏍硅妭鐐逛负9锛**銆傚洜涓鸿妭鐐6鍜9閮芥槸鍙跺瓙鑺傜偣浜嗭紝鎵浠ヤ篃杩斿洖鍟︺ - -![](https://imgkr2.cn-bj.ufileos.com/63333c60-747b-45d3-a8eb-dacf0cf36231.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=8NTb2Fj1PBlwVIxwe1InO5YqoWg%253D&Expires=1602693197) - - - -宸﹀瓙鏍戯紙鏍硅妭鐐逛负2锛夊拰鍙冲瓙鏍(鏍硅妭鐐逛负7锛夐兘琚炕杞畬鍚庯紝杩欏嚑涓楠ゅ氨**褰掓潵**锛屽嵆閫掑綊鐨勫綊杩囩▼锛岀炕杞爲鐨勪换鍔″氨瀹屾垚浜唦 - -![](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/afada1b801734cdc899e896b0816b63f~tplv-k3u1fbpfcp-watermark.webp) - -鏄剧劧锛**閫掓帹鍏崇郴寮**灏辨槸锛 -``` -invertTree锛坮oot锛= invertTree锛坮oot.left锛 + invertTree锛坮oot.right锛; -``` - -浜庢槸锛屽緢瀹规槗鍙互寰楀嚭浠ヤ笅浠g爜锛 -``` -//缈昏浆涓棰椾簩鍙夋爲 -public TreeNode invertTree(TreeNode root) { - if(root==null || (root.left ==null && root.right ==null){ - return root; - } - //缈昏浆宸﹀瓙鏍 - TreeNode left = invertTree(root.left); - //缈昏浆鍙冲瓙鏍 - TreeNode right= invertTree(root.right); -} -``` -杩欓噷浠g爜鏈変釜鍦版柟闇瑕佹敞鎰忥紝灏辨槸缈昏浆瀹屼竴妫垫爲鐨勫乏鍙冲瓙鏍戝悗锛岄渶瑕佷氦鎹㈠畠宸﹀彸瀛愭爲鐨勫紩鐢ㄤ綅缃 -``` - root.left = right; - root.right = left; -``` - -鍥犳锛宭eetcode杩欎釜閫掑綊缁忓吀棰樼洰鐨**缁堟瀬瑙e喅浠g爜**濡備笅锛 -``` -class Solution { - public TreeNode invertTree(TreeNode root) { - if(root==null || (root.left ==null && root.right ==null)){ - return root; - } - //缈昏浆宸﹀瓙鏍 - TreeNode left = invertTree(root.left); - //缈昏浆鍙冲瓙鏍 - TreeNode right= invertTree(root.right); - //宸﹀彸瀛愭爲浜ゆ崲浣嶇疆~ - root.left = right; - root.right = left; - return root; - } -} -``` -鎷跨粓鏋佽В鍐充唬鐮佸幓leetcode鎻愪氦涓涓嬶紝閫氳繃鍟 - - -![](https://imgkr2.cn-bj.ufileos.com/3c9bc7ba-1677-4b8b-a389-e7177fd2b747.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=oNJFxSVWmku%252FMg%252BKlGHop%252BQ%252BxIw%253D&Expires=1602693611) - - -### 閫掑綊瀛樺湪鐨勯棶棰 -- 閫掑綊璋冪敤灞傜骇澶锛屽鑷存爤婧㈠嚭闂 -- 閫掑綊閲嶅璁$畻锛屽鑷存晥鐜囦綆涓 - -#### 鏍堟孩鍑洪棶棰 -- 姣忎竴娆″嚱鏁拌皟鐢ㄥ湪鍐呭瓨鏍堜腑鍒嗛厤绌洪棿锛岃屾瘡涓繘绋嬬殑鏍堝閲忔槸鏈夐檺鐨勩 -- 褰撻掑綊璋冪敤鐨勫眰绾уお澶氭椂锛屽氨浼氳秴鍑烘爤鐨勫閲忥紝浠庤屽鑷磋皟鐢ㄦ爤婧㈠嚭銆 -- 鍏跺疄锛屾垜浠湪鍓嶉潰灏忚妭涔熻璁轰簡锛岄掑綊杩囩▼绫讳技浜庡嚭鏍堝叆鏍堬紝濡傛灉閫掑綊娆℃暟杩囧锛屾爤鐨勬繁搴﹀氨闇瑕佽秺娣憋紝鏈鍚庢爤瀹归噺鐪熺殑涓嶅鍜 - -**浠g爜渚嬪瓙濡備笅锛** -``` -/** - * 閫掑綊鏍堟孩鍑烘祴璇 - */ -public class RecursionTest { - - public static void main(String[] args) { - sum(50000); - } - private static int sum(int n) { - if (n <= 1) { - return 1; - } - return sum(n - 1) + n; - } -} -``` -**杩愯缁撴灉:** -``` -Exception in thread "main" java.lang.StackOverflowError - at recursion.RecursionTest.sum(RecursionTest.java:13) -``` - -鎬庝箞瑙e喅杩欎釜鏍堟孩鍑洪棶棰橈紵棣栧厛闇瑕**浼樺寲涓涓嬩綘鐨勯掑綊**锛岀湡鐨勯渶瑕侀掑綊璋冪敤杩欎箞澶氭鍢涳紵濡傛灉鐪熺殑闇瑕侊紝鍏堢◢寰**璋冨ぇJVM鐨勬爤绌洪棿鍐呭瓨**锛屽鏋滆繕鏄笉琛岋紝閭e氨闇瑕佸純鐢ㄩ掑綊锛**浼樺寲涓哄叾浠栨柟妗**鍜瘇 - -#### 閲嶅璁$畻锛屽鑷寸▼搴忔晥鐜囦綆涓 -鎴戜滑鍐嶆潵鐪嬩竴閬撶粡鍏哥殑闈掕洐璺抽樁闂锛氫竴鍙潚铔欎竴娆″彲浠ヨ烦涓1绾у彴闃讹紝涔熷彲浠ヨ烦涓2绾у彴闃躲傛眰璇ラ潚铔欒烦涓婁竴涓 n 绾х殑鍙伴樁鎬诲叡鏈夊灏戠璺虫硶銆 - -缁濆ぇ澶氭暟璇昏呮湅鍙嬶紝寰堝鏄撳氨鎯冲埌浠ヤ笅閫掑綊浠g爜鍘昏В鍐筹細 -``` -class Solution { - public int numWays(int n) { - if (n == 0){ - return 1; - } - if(n <= 2){ - return n; - } - return numWays(n-1) + numWays(n-2); - } -} -``` - -浣嗘槸鍛紝鍘籰eetcode鎻愪氦涓涓嬶紝灏辨湁闂鍟︼紝瓒呭嚭鏃堕棿闄愬埗浜 - - -![](https://imgkr2.cn-bj.ufileos.com/47049001-7fae-4c98-8f4c-2e55aca367f3.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=xELiHeOso7vAsXwthfHEIDarVGs%253D&Expires=1602693967) - - -涓轰粈涔堣秴鏃朵簡鍛紵閫掑綊鑰楁椂鍦ㄥ摢閲屽憿锛熷厛鐢诲嚭**閫掑綊鏍**鐪嬬湅锛 - -![](https://imgkr2.cn-bj.ufileos.com/9539296a-f5b1-433e-94ba-2e23eddfc409.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=Rzlo2ChPE7UEkCSJhbMNTBbtfaA%253D&Expires=1602694031) - - -- 瑕佽绠楀師闂 f(10)锛屽氨闇瑕佸厛璁$畻鍑哄瓙闂 f(9) 鍜 f(8) -- 鐒跺悗瑕佽绠 f(9)锛屽張瑕佸厛绠楀嚭瀛愰棶棰 f(8) 鍜 f(7)锛屼互姝ょ被鎺ㄣ -- 涓鐩村埌 f(2) 鍜 f(1锛夛紝閫掑綊鏍戞墠缁堟銆 - -**閫掑綊鏃堕棿澶嶆潅搴 = 瑙e喅涓涓棶棰樻椂闂*闂涓暟** -- 涓涓棶棰樻椂闂 = f锛坣-1锛+f锛坣-2锛夛紝涔熷氨鏄竴涓姞娉曠殑鎿嶄綔锛屾墍浠ュ鏉傚害鏄 **O(1)**锛 -- 闂涓暟 = 閫掑綊鏍戣妭鐐圭殑鎬绘暟锛岄掑綊鏍戠殑鎬荤粨鐐 = 2^n-1锛屾墍浠ユ槸澶嶆潅搴**O(2^n)**銆 - -鍥犳锛岄潚铔欒烦闃讹紝閫掑綊瑙f硶鐨勬椂闂村鏉傚害 = O(1) * O(2^n) = O(2^n)锛屽氨鏄寚鏁扮骇鍒殑锛**濡傛灉n姣旇緝澶х殑璇濓紝瓒呮椂寰堟甯哥殑浜**銆 - -浣犱粩缁嗚瀵熻繖棰楅掑綊鏍戯紝浣犱細鍙戠幇瀛樺湪**澶ч噺閲嶅璁$畻**锛屾瘮濡俧锛8锛夎璁$畻浜嗕袱娆★紝f锛7锛夎閲嶅璁$畻浜3娆...鎵浠ヨ繖涓掑綊绠楁硶浣庢晥鐨勫師鍥狅紝灏辨槸瀛樺湪澶ч噺鐨勯噸澶嶈绠楋紒 - -**閭d箞锛屾庝箞瑙e喅杩欎釜闂鍛紵** - -鏃㈢劧瀛樺湪澶ч噺閲嶅璁$畻锛岄偅涔堟垜浠彲浠ュ厛鎶婅绠楀ソ鐨勭瓟妗堝瓨涓嬫潵锛屽嵆閫犱竴涓蹇樺綍锛岀瓑鍒颁笅娆¢渶瑕佺殑璇濓紝鍏堝幓**澶囧繕褰**鏌ヤ竴涓嬶紝濡傛灉鏈夛紝灏辩洿鎺ュ彇灏卞ソ浜嗭紝澶囧繕褰曟病鏈夋墠鍐嶅幓璁$畻锛岄偅灏卞彲浠ョ渷鍘婚噸鏂伴噸澶嶈绠楃殑鑰楁椂鍟︼紒杩欏氨鏄**甯﹀蹇樺綍鐨勮В娉** - -鎴戜滑鏉ョ湅涓涓**甯﹀蹇樺綍鐨勯掑綊瑙f硶**鍚 - -涓鑸娇鐢ㄤ竴涓暟缁勬垨鑰呬竴涓搱甯宮ap鍏呭綋杩欎釜**澶囧繕褰**銆 - -鍋囪f(10)姹傝В鍔犱笂**澶囧繕褰**锛屾垜浠啀鏉ョ敾涓涓嬮掑綊鏍戯細 - -**绗竴姝**锛宖锛10锛= f(9) + f(8)锛宖(9) 鍜宖锛8锛夐兘闇瑕佽绠楀嚭鏉ワ紝鐒跺悗鍐嶅姞鍒板蹇樺綍涓紝濡備笅锛 - -![](https://imgkr2.cn-bj.ufileos.com/22fe0dc0-136e-4e8d-9b54-7f1ff2a9d066.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=gJl54y4g86XMhK2K1ZbaqmVl94Y%253D&Expires=1602694255) - - -**绗簩姝ワ紝** f(9) = f锛8锛+ f锛7锛夛紝f锛8锛= f锛7锛+ f(6), 鍥犱负 f(8) 宸茬粡鍦ㄥ蹇樺綍涓暒锛屾墍浠ュ彲浠ョ渷鎺夛紝f(7),f锛6锛夐兘闇瑕佽绠楀嚭鏉ワ紝鍔犲埌澶囧繕褰曚腑~ - -![](https://imgkr2.cn-bj.ufileos.com/f9b26b22-c745-4bad-b14d-d8b2b51075f4.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=RkOd5Zj5Wwqonn63eXfoWqStvx4%253D&Expires=1602694275) - - -**绗笁姝ワ紝** f(8) = f锛7锛+ f(6),鍙戠幇f(8)锛宖(7),f锛6锛夊叏閮ㄩ兘鍦ㄥ蹇樺綍涓婁簡锛屾墍浠ラ兘鍙互鍓帀銆 -![](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ec535ab8a0d3401eae5cb041dabac221~tplv-k3u1fbpfcp-watermark.image) - -鎵浠ュ憿锛岀敤浜嗗蹇樺綍閫掑綊绠楁硶锛岄掑綊鏍戝彉鎴愬厜绉冪鐨勫挴锛屽涓嬶細 -![](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5b78faafe49b4ee0ab939194459cf386~tplv-k3u1fbpfcp-watermark.image) - -甯︺屽蹇樺綍銆嶇殑閫掑綊绠楁硶锛屽瓙闂涓暟灏变负n浜嗭紝瑙e喅涓涓瓙闂杩樻槸O(1),鎵浠**甯︺屽蹇樺綍銆嶇殑閫掑綊绠楁硶鐨勬椂闂村鏉傚害鏄疧(n)**銆傛帴涓嬫潵鍛紝鎴戜滑鐢ㄥ甫銆屽蹇樺綍銆嶇殑閫掑綊绠楁硶鍘绘捀浠g爜锛岃В鍐宠繖涓潚铔欒烦闃堕棶棰樺挴~锛屼唬鐮佸涓嬶細 - -``` -public class Solution { - //鍝堝笇map鍏呭綋澶囧繕褰曠殑浣滅敤 - Map tempMap = new HashMap(); - public int numWays(int n) { - // n = 0 涔熺畻1绉 - if (n == 0) { - return 1; - } - if (n <= 2) { - return n; - } - //鍏堝垽鏂湁娌¤绠楄繃锛屽嵆鐪嬬湅澶囧繕褰曟湁娌℃湁 - if (tempMap.containsKey(n)) { - //澶囧繕褰曟湁锛屽嵆璁$畻杩囷紝鐩存帴杩斿洖 - return tempMap.get(n); - } else { - // 澶囧繕褰曟病鏈夛紝鍗虫病鏈夎绠楄繃锛屾墽琛岄掑綊璁$畻,骞朵笖鎶婄粨鏋滀繚瀛樺埌澶囧繕褰昺ap涓紝瀵1000000007鍙栦綑锛堣繖涓槸leetcode棰樼洰瑙勫畾鐨勶級 - tempMap.put(n, (numWays(n - 1) + numWays(n - 2)) % 1000000007); - return tempMap.get(n); - } - } -} -``` - -鍘籰eetcode鎻愪氦涓涓嬶紝濡傚浘锛岀ǔ浜嗭細 - -![](https://imgkr2.cn-bj.ufileos.com/8208e494-07e6-467b-96a2-8acf77121737.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=zNVyzVvQaWVQaQmABckQvIVh1XE%253D&Expires=1602694530) - -鍟ュ彨銆岃嚜椤跺悜涓嬨嶏紵娉ㄦ剰鎴戜滑鍒氭墠鐢荤殑閫掑綊鏍戯紙鎴栬呰鍥撅級锛屾槸浠庝笂鍚戜笅寤朵几锛岄兘鏄粠涓涓妯¤緝澶х殑鍘熼棶棰樻瘮濡傝 f(20)锛屽悜涓嬮愭笎鍒嗚В瑙勬ā锛岀洿鍒 f(1) 鍜 f(2) 瑙﹀簳锛岀劧鍚庨愬眰杩斿洖绛旀锛岃繖灏卞彨銆岃嚜椤跺悜涓嬨嶃 - - -鍟ュ彨銆岃嚜搴曞悜涓娿嶏紵鍙嶈繃鏉ワ紝鎴戜滑鐩存帴浠庢渶搴曚笅锛屾渶绠鍗曪紝闂瑙勬ā鏈灏忕殑 f(1) 鍜 f(2) 寮濮嬪線涓婃帹锛岀洿鍒版帹鍒版垜浠兂瑕佺殑绛旀 f(20)锛岃繖灏辨槸鍔ㄦ佽鍒掔殑鎬濊矾锛岃繖涔熸槸涓轰粈涔堝姩鎬佽鍒掍竴鑸兘鑴辩浜嗛掑綊锛岃屾槸鐢卞惊鐜凯浠e畬鎴愯绠椼 - -鍔ㄦ佽鍒掗棶棰橈紝涓嬫湡鍒嗚В - -### 鍙傝冧笌鎰熻阿 -- [涓鏂囧浼氶掑綊瑙i](https://mp.weixin.qq.com/s/Hew44D8rdXb3pf8mZGk67w) -- [鍔ㄦ佽鍒掕瑙(https://mp.weixin.qq.com/s/1V3aHVonWBEXlNUvK3S28w) - -### 涓汉鍏紬鍙 -![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e6b23c704fc94ca09207b779f953cce6~tplv-k3u1fbpfcp-zoom-1.image) -- 鏇村骞茶揣锛屽叧娉ㄥ叕浼楀彿 - From fd830096617fed64645c9bb2d0152fe899d78eab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Sat, 23 Jul 2022 10:40:38 +0800 Subject: [PATCH 21/52] =?UTF-8?q?=E5=A4=A7=E5=8E=82=E9=9D=A2=E8=AF=95?= =?UTF-8?q?=E7=9C=9F=E6=9B=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../README.MD" | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 "\345\244\247\345\216\202\351\235\242\350\257\225\347\234\237\351\242\230/README.MD" diff --git "a/\345\244\247\345\216\202\351\235\242\350\257\225\347\234\237\351\242\230/README.MD" "b/\345\244\247\345\216\202\351\235\242\350\257\225\347\234\237\351\242\230/README.MD" new file mode 100644 index 0000000..2fa4767 --- /dev/null +++ "b/\345\244\247\345\216\202\351\235\242\350\257\225\347\234\237\351\242\230/README.MD" @@ -0,0 +1,13 @@ +## 1. 闈㈣瘯鐪熼 + +鍏虫敞鍏紬鍙凤細鎹$敯铻虹殑灏忕敺瀛 +鈥 +- [oppo鍚庣16杩為棶](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498750&idx=1&sn=19fe8b4fff28fe81db14e733053bbc74&chksm=cf2224d7f855adc1d0984980a4e3de31fe33329164a472ca8d8255a8a80b69b2e23850811323&token=2001057130&lang=zh_CN#rd) +- [灏忓巶鍚庣鍗佽繛闂紙闄勭瓟妗堬級](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498316&idx=1&sn=7749b78293b7b2af51eda99844e08a56&chksm=cf222565f855ac7324232e2af459f8b6e6eb5fd5b272c2b29bda08cc579421b6704a0de94b2e&token=2001057130&lang=zh_CN#rd) +- [鑵捐浜戝悗绔15杩為棶锛乚(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498171&idx=1&sn=f5a7ec25a569822be0f73fbcd413e8ba&chksm=cf222692f855af84fba419166fcd4235c0e78af3a2e1ec4c723a4efb1bd1ad6f8a5b9404c599&token=2001057130&lang=zh_CN#rd) +- [绀炬嫑鍚庣21杩為棶锛堜笁骞村伐浣滅粡楠屼竴闈級](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498084&idx=1&sn=96c8148cfeeeb16668ed9e03fa9131cc&chksm=cf22264df855af5b6e81b93738cca28989226a53ec702fcfaa0cc5004dded4208c5ee5ea844a&token=2001057130&lang=zh_CN#rd) +- [涓浠界儹涔庝箮鐨勫瓧鑺傞潰璇曠湡棰榏(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497742&idx=1&sn=18765e7356f446a7f2521f45b467d5d3&chksm=cf222727f855ae31dd2029e3219814211336c41d9228d271a583d3691ddadca586529aca9302&token=2001057130&lang=zh_CN#rd) +- [闈㈣瘯蹇呭锛氳櫨鐨湇鍔$15杩為棶](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497256&idx=1&sn=3b799c2d514aa25e85a6faa60d639a0b&chksm=cf222901f855a017b73356b99b830b8800a7a9172fab891c5759d8dd69a270872ea9480c0b7c&token=2001057130&lang=zh_CN#rd) +- [瀹囧畽鏉′竴闈細鍗侀亾缁忓吀闈㈣瘯棰樿В鏋怾(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247495342&idx=1&sn=54e1c0c16a6467001524c34818025331&chksm=cf223187f855b89140db5ca429e6efc19d0111abf7f36b78a0ecd73b00fded1ff1e7ba32a6f1&token=2001057130&lang=zh_CN#rd) +- [铓傝殎閲戞湇涓闈細鍗侀亾缁忓吀闈㈣瘯棰樿В鏋怾(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247493270&idx=1&sn=1c78a81d6e1bd0f0fd947fe8c3a33e32&chksm=cf2239bff855b0a9627855f20a17799e0506eb7548a409bfa0ee0450328d7519ec70f7b962cc&token=2001057130&lang=zh_CN#rd) +- [鐢拌灪绮惧搧闈㈣瘯PDF鍙戝竷锛乚(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499943&idx=1&sn=fe869c0a97a306e42830336fe74e17a6&chksm=cf221f8ef8559698781709bfbccbb85087286e48434905fb18bec3a3ec0af7329c2a1632c230&token=1990771297&lang=zh_CN#rd锛 \ No newline at end of file From 9bdca98a3d18d03575ae7bb379667410efcea7e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Sat, 23 Jul 2022 10:52:06 +0800 Subject: [PATCH 22/52] =?UTF-8?q?=E5=88=86=E5=B8=83=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "\345\210\206\345\270\203\345\274\217/README.MD" | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 "\345\210\206\345\270\203\345\274\217/README.MD" diff --git "a/\345\210\206\345\270\203\345\274\217/README.MD" "b/\345\210\206\345\270\203\345\274\217/README.MD" new file mode 100644 index 0000000..1b5f507 --- /dev/null +++ "b/\345\210\206\345\270\203\345\274\217/README.MD" @@ -0,0 +1,12 @@ +## 鍒嗗竷寮 + +鍏虫敞鍏紬鍙凤細鎹$敯铻虹殑灏忕敺瀛 + +- [闈㈣瘯蹇呭锛氳亰鑱婂垎甯冨紡閿佺殑澶氱瀹炵幇锛乚(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498595&idx=1&sn=4e5308930e151a609baa2df820e48a89&chksm=cf22244af855ad5c71822cb33e828ce652c6f34202096a9344922b86dcbc08076d7922acde5f&token=1990771297&lang=zh_CN#rd) +- [鎴戜滑涓轰粈涔堣鍒嗗簱鍒嗚〃锛焆(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498625&idx=1&sn=0d7bd9d1b46eeff4c715a6761355e9b0&chksm=cf2224a8f855adbea8931c8e011711f6c70cffeef8ddf8b87729c710eacef11b46eef80fda36&token=1990771297&lang=zh_CN#rd) +- [鑱婅亰楂樺彲鐢ㄧ殑 11 涓叧閿妧宸(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498784&idx=1&sn=aad1c00d6eafb0c1f08959612c69959a&chksm=cf222309f855aa1f71ef9cf470bfa72ac73365c401ec7c7d0c3b241a9116c3112f83760793e8&token=1990771297&lang=zh_CN#rd) +- [鐪嬩竴閬嶅氨鐞嗚В锛氬垎甯冨紡浜嬪姟璇﹁В](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498358&idx=1&sn=aa6c7ceb61b73267d68d1b4fb7ccc2ed&chksm=cf22255ff855ac495861d57df276517e89779006267fa8413fe925cc15b0c3e0b0f1b1a5675e&token=1990771297&lang=zh_CN#rd) +- [鍑犵涓绘祦鐨勫垎甯冨紡瀹氭椂浠诲姟锛屼綘鐭ラ亾鍝簺锛焆(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498121&idx=1&sn=e3d7e4f5297c7b2390b412a9bafc3385&chksm=cf2226a0f855afb669cde8d7f400fb334bd4c75a8c672d1208667387d03d2dfd24884e60b825&token=1990771297&lang=zh_CN#rd) +- [redis鍒嗗竷寮忛攣鐨8澶у潙锛岃寰楁嬁灏忔湰鏈涓嬫潵鍟(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247495390&idx=1&sn=87cc1567c709cfa67b43dd8d273bb426&chksm=cf2231f7f855b8e17919f7763469d87c47d9b4c4ad25aba7e6ff60fa33b048bc47a4afd287fc&token=1990771297&lang=zh_CN#rd) +- [妗嗘灦绡囷細鍒嗗竷寮忎竴鑷存цВ鍐虫柟妗圿(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490468&idx=2&sn=91b8e5dd2ce3db218708b5c736fce700&chksm=cf21c48df8564d9b30164e1dbf9b5ebcc1847a9450d08ee146c98eb53107af475149ad12a748&token=1990771297&lang=zh_CN#rd) +- [杩欎笁骞磋鍒嗗竷寮忓潙鎯ㄤ簡锛屾洕鍏夊崄澶у潙](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488553&idx=2&sn=fa13e9698e59f5a5485d3d3d4b8ef2b1&chksm=cf21cb00f8564216277806780c64e13c48fe32009f588349b3365afa8de97bd8ef192507bd50&token=1990771297&lang=zh_CN#rd) \ No newline at end of file From 8b1da559828aabcdc18a343cd63b1a69eadffe03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Sat, 23 Jul 2022 10:58:41 +0800 Subject: [PATCH 23/52] =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E4=BA=BA=E7=94=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../README.MD" | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 "\347\250\213\345\272\217\344\272\272\347\224\237&\351\235\242\350\257\225\345\273\272\350\256\256/README.MD" diff --git "a/\347\250\213\345\272\217\344\272\272\347\224\237&\351\235\242\350\257\225\345\273\272\350\256\256/README.MD" "b/\347\250\213\345\272\217\344\272\272\347\224\237&\351\235\242\350\257\225\345\273\272\350\256\256/README.MD" new file mode 100644 index 0000000..ae9424d --- /dev/null +++ "b/\347\250\213\345\272\217\344\272\272\347\224\237&\351\235\242\350\257\225\345\273\272\350\256\256/README.MD" @@ -0,0 +1,6 @@ +## 绋嬪簭浜虹敓 + +- [璺熷ぇ瀹惰亰鑱婂ぉ锛屾垜鍛ㄦ湯閮藉湪骞插暐](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247493222&idx=1&sn=29eb95b01b54bed2abbcf5a72285b38a&chksm=cf22394ff855b059b29ffb562e22d8ecc048caa743eb5c6257ad474676940ba8d36840f075ed&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [璺熷ぇ瀹惰亰鑱婂浣曞涔燷(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247495313&idx=1&sn=7f521db08e84b07177d847c60071d709&chksm=cf2231b8f855b8ae765f2dd584994836c0b74ce0ef761653233c3af04f38b4a1aa1833f7a55a&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [鍐欎簡涓ゅ勾鏂囩珷锛岀粓浜庣牬涓囷紒](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247489788&idx=1&sn=66efbc1b718915bfd8996b521d317a55&chksm=cf21c7d5f8564ec3928957d3c23959f5cb99d9f9bd2c1bab0dcf1750a6a017c3869189a3651a&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [澶忓ぉ鐨勯锛屾垜姘歌繙璁板緱~](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487989&idx=2&sn=9eb923d4c8c22bee1a408e4f86983f65&chksm=cf21cedcf85647cac6fe4bfa6d732856fd0335f4fcadad4d1e0dd10702e95905e06c9e38e8e8&token=162724582&lang=zh_CN&scene=21#wechat_redirect) \ No newline at end of file From a293441db11c089e849ef9d375138339957bd9b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Sat, 23 Jul 2022 11:06:27 +0800 Subject: [PATCH 24/52] Add files via upload --- .../README.MD" | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 "\347\250\213\345\272\217\345\221\230\345\277\205\345\244\207\345\267\245\345\205\267\347\257\207/README.MD" diff --git "a/\347\250\213\345\272\217\345\221\230\345\277\205\345\244\207\345\267\245\345\205\267\347\257\207/README.MD" "b/\347\250\213\345\272\217\345\221\230\345\277\205\345\244\207\345\267\245\345\205\267\347\257\207/README.MD" new file mode 100644 index 0000000..73e3dce --- /dev/null +++ "b/\347\250\213\345\272\217\345\221\230\345\277\205\345\244\207\345\267\245\345\205\267\347\257\207/README.MD" @@ -0,0 +1,8 @@ + +## 绋嬪簭鍛樺伐鍏风瘒 + +- [鐢ㄤ唬鐮佺敾鏃跺簭鍥撅紒YYDS](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247500478&idx=1&sn=ec674e3eadba9bb87849292f46f84989&chksm=cf221d97f8559481fae8f0e1871ae19499568b3e49980e92018c4a5acdcf743a37da79c2436d&token=1990771297&lang=zh_CN#rd) +- [绋嬪簭鍛樺繀澶囧熀纭锛欸it 鍛戒护鍏ㄦ柟浣嶅涔燷(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488013&idx=1&sn=7011a51a347e3da2cf8f8540b4d9a5d6&chksm=cf21cd24f8564432d74bc13551ebdeae71a71ea31e339c7a8f1f42f181078b5192475d598626&token=1569911403&lang=zh_CN&scene=21#wechat_redirect) +- [MyBatis 鎻掍欢鍘熺悊涓庡疄鎴榏(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498815&idx=1&sn=737e8f92ff526dac408af7a409f3a3d4&chksm=cf222316f855aa007fe16f7bca0636c552f238deb766bb54c34db7b633c13451fc91a4fe8a3e&token=1990771297&lang=zh_CN#rd) +- [鏇村揩鐨凪aven鏉ヤ簡锛岄熷害鎻愬崌浜8鍊嶏紒](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497470&idx=1&sn=7a3a5bb48f7d3b1a627460b698e7e9a0&chksm=cf2229d7f855a0c1e892c23f7690e6ab1a745040142672b982a3934c8307901d0be03dff3cff&token=1990771297&lang=zh_CN#rd) +- [鍥犱负鐭ラ亾浜30+娆惧湪绾垮伐鍏凤紝鎴戠殑宸ヤ綔鏁堢巼鎻愬崌500%!](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488041&idx=1&sn=26d55c23ecd439860c4d9865bec61976&chksm=cf21cd00f8564416fe991974d24a51798d925b2e79d62935accf02aa6895c7b02adf48e9e207&token=1990771297&lang=zh_CN#rd) \ No newline at end of file From ef7f333d2355d429e89ed180de4d25da56f748a5 Mon Sep 17 00:00:00 2001 From: whx123 <327658337@qq.com> Date: Sat, 23 Jul 2022 12:13:44 +0800 Subject: [PATCH 25/52] update --- README.md | 38 +++++++++++++++---- .../README.MD" | 8 ++++ .../READEME.MD" | 17 +++++++++ .../README.MD" | 8 ++++ .../README.MD" | 7 ++++ .../README.MD" | 7 ++++ 6 files changed, 78 insertions(+), 7 deletions(-) create mode 100644 "\344\270\255\351\227\264\344\273\266/README.MD" create mode 100644 "\345\267\245\344\275\234\346\200\273\347\273\223/READEME.MD" create mode 100644 "\347\224\237\344\272\247\351\227\256\351\242\230\345\210\206\346\236\220/README.MD" create mode 100644 "\347\274\223\345\255\230Redis\346\200\273\347\273\223/README.MD" create mode 100644 "\351\253\230\345\271\266\345\217\221/README.MD" diff --git a/README.md b/README.md index 7327214..68aacb1 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,40 @@ -鏁寸悊涓浠借秴绾ц缁嗙殑Java闈㈣瘯棰+鍚庣鍩虹+鏃ュ父宸ヤ綔鎬荤粨锛屽仛鏈鏆栧績鐨勭敺瀛╁瓙锛屽悗闈細鎱㈡參鎶婄瓟妗堝畬鍠勶紝甯屾湜澶у鎵惧埌鐞嗘兂offer +## 鍓嶈█ -猸 鐐瑰彸涓婅缁欎竴涓 Star锛岄紦鍔辨妧鏈汉杈撳嚭鏇村骞茶揣锛岀埍浜 锛 +鏁寸悊涓浠借秴绾ц缁嗙殑Java闈㈣瘯棰+鍚庣鍩虹+鏃ュ父宸ヤ綔鎬荤粨锛屽仛鏈鏆栧績鐨勭敺瀛╁瓙锛屽悗闈細鎱㈡參瀹屽杽锛屽笇鏈涘ぇ瀹舵壘鍒扮悊鎯硂ffer -浣滆呮崱鐢拌灪鐨勫皬鐢峰锛屾氮杩硅繃鍑犲澶у巶锛屾帢閲戜紭绉鍒涗綔鑰咃紝CSDN鍗氫富銆 +猸 鐐瑰彸涓婅缁欎竴涓 Star锛岄紦鍔辨妧鏈汉杈撳嚭鏇村骞茶揣锛屾劅璋㈡劅璋紝鐖变簡锛 锛 -- 鍘熷垱绮惧搧100绡(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497536&idx=1&sn=3ac9934f607d79e51457fd01f4c8a4ef&chksm=cf222869f855a17fc30c744e5b7ccdeca407f3b7ddcca46bae1c93b1436ffc6fe417ccb8aef4&token=1990771297&lang=zh_CN#rd) +浣滆呮崱鐢拌灪鐨勫皬鐢峰锛屾氮杩硅繃鍑犲澶у巶锛**鎺橀噾浼樼鍒涗綔鑰**锛孋SDN鍗氫富锛岀煡涔庡崥涓汇備互涓嬪唴瀹瑰叏閮ㄥ嚭鑷叕浼楀彿锛**鎹$敯铻虹殑灏忕敺瀛**锛屾杩庡叧娉ㄣ + +- [鐢拌灪鍘熷垱绮惧搧100绡嘳(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497536&idx=1&sn=3ac9934f607d79e51457fd01f4c8a4ef&chksm=cf222869f855a17fc30c744e5b7ccdeca407f3b7ddcca46bae1c93b1436ffc6fe417ccb8aef4&token=1990771297&lang=zh_CN#rd) + +## 宸ヤ綔鎬荤粨 + +- [宸ヤ綔鎬荤粨锛佹棩蹇楁墦鍗扮殑15涓缓璁甝(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247494838&idx=1&sn=cdb15fd346bddf3f8c1c99f0efbd67d8&chksm=cf22339ff855ba891616c79d4f4855e228e34a9fb45088d7acbe421ad511b8d090a90f5b019f&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [25绉嶄唬鐮佸潖鍛抽亾鎬荤粨+浼樺寲绀轰緥](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490148&idx=1&sn=00a181bf74313f751b3ea15ebc303545&chksm=cf21c54df8564c5bc5b4600fce46619f175f7ae557956f449629c470a08e20580feef4ea8d53&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [鑱婅亰鏃ュ父寮鍙戜腑锛屽浣曞噺灏慴ug鍛紵](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490662&idx=1&sn=d38a090611af7f64ee3c6a31331d5228&chksm=cf21c34ff8564a59e505e6edf3065a0fc506c6d2c96f492c8d8873cd46dedbe0704e43cb9c2e&token=1990771297&lang=zh_CN#rd) +- [宸ヤ綔鍥涘勾锛屽垎浜50涓浣犱唬鐮佹洿濂界殑灏忓缓璁甝(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488708&idx=1&sn=6e2e0a740f5d42a59641487a0bf1e3bf&chksm=cf21cbedf85642fbb485fa1c7bf9af21923d8503f2542b6f8283ce79ddc683f7d9e45da83100&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [鍐欎唬鐮佹湁杩16涓ソ涔犳儻锛屽彲浠ュ噺灏80%闈炰笟鍔$殑bug](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488097&idx=1&sn=eaca1f92ca3ccd9de00dbc4ef3e4029a&chksm=cf21cd48f856445e4cc24c1f8bcf18d1479bad0a37a87a2fb70717d8a4e65dcf7b4d5f83d24f&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java鏃ュ父寮鍙戠殑21涓潙锛屼綘韪╄繃鍑犱釜锛焆(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488115&idx=1&sn=bdd4a4ca36bc7ea902106d058e8537fb&chksm=cf21cd5af856444cb36af600705615454b0aaa2b289b97ddb52d594556ac07a1915b73ecce19&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [CAS涔愯閿佽В鍐冲苟鍙戦棶棰樼殑涓娆″疄璺礭(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487937&idx=1&sn=206a37bf6d6a7aa1d05674c479ed7a72&chksm=cf21cee8f85647fe7a082049a41c0f640f54976d2cdf4302b24c5517ca42b854eb84b13ece10&token=1990771297&lang=zh_CN#rd) +- [鍐欎唬鐮佹湁杩欎簺鎯虫硶锛屽悓浜嬫墠涓嶄細璁や负浣犳槸澶嶅埗绮樿创绋嬪簭鍛榏(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487961&idx=1&sn=e646231067968d9f58e6665914293f9a&chksm=cf21cef0f85647e6f3ff2feece004ac3bd979e37fe45103c88d0f299dfe632a5cf6dd547c1d9&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [绋嬪簭鍛樺繀澶囷細Java鏃ユ湡澶勭悊鐨勫崄涓潙](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487973&idx=1&sn=0f713413098fb579e5f200b829f71e89&chksm=cf21ceccf85647da450765d79bf5943da551c3be950447063b9f8c77c21bf2a39b99387a949b&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [鍐呭瓨娉勬紡闂鐨勫垎鏋愬拰瑙e喅鏂规](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487986&idx=1&sn=d681a585ac489703788e3baa48eb9aa3&chksm=cf21cedbf85647cd23bbab9dfec63e6877f83c34efb19bd16075d5d90fea91d3f4a20fc77921&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [绋嬪簭鍛樺繀澶囧熀纭锛氬姞绛鹃獙绛綸(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488022&idx=1&sn=70484a48173d36006c8db1dfb74ab64d&chksm=cf21cd3ff8564429a1205f6c1d78757faae543111c8461d16c71aaee092fe3e0fed870cc5e0e&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [璁颁竴娆℃帴鍙fц兘浼樺寲瀹炶返鎬荤粨锛氫紭鍖栨帴鍙fц兘鐨勫叓涓缓璁甝(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488004&idx=1&sn=00840efd9c0bd0a7f172b59eb2ca130f&chksm=cf21cd2df856443bf21d8e09cfe5c8452ecaf82e3c2210fca3b28829ded04defddcf63c0a59b&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [绋嬪簭鍛樺繀澶囧熀纭锛氬浣曞畨鍏ㄤ紶杈撳瓨鍌ㄧ敤鎴峰瘑鐮侊紵](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488117&idx=1&sn=5d3d0eda0ed45f3f576e211de31ca3a9&chksm=cf21cd5cf856444af1407a94a2abf445265ca7c5f5855cfa1c223cb209e99040c7889621f231&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [涓娆′唬鐮佷紭鍖栧疄璺碉紝鐢ㄤ簡妯℃澘鏂规硶+绛栫暐+宸ュ巶鏂规硶妯″紡](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488061&idx=1&sn=1d9ab7954b03521ab81ecf033c0e5e50&chksm=cf21cd14f8564402b213f0ef908bbdb0e12fed4b281c5803b8e539cacb1551654194becfb7d6&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [淇濊瘉鎺ュ彛鏁版嵁瀹夊叏鐨10绉嶆柟妗圿(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247500285&idx=1&sn=7d0723f25d46e858859cfd79acb6fb9d&chksm=cf221ed4f85597c2093f81baa5fdedc65817bf2d23a7951236836b0f54c2335695cbed61cd13&token=1990771297&lang=zh_CN#rd) + +## 绂忓埄 500+椤靛師鍒涢潰璇曢 + +- [鐢拌灪鍘熷垱500+椤甸潰璇曢](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499943&idx=1&sn=fe869c0a97a306e42830336fe74e17a6&chksm=cf221f8ef8559698781709bfbccbb85087286e48434905fb18bec3a3ec0af7329c2a1632c230&token=1990771297&lang=zh_CN#rd) ## 涓汉鍏紬鍙 -寰俊鎼滐細鎹$敯铻虹殑灏忕敺瀛 +寰俊鎼滃叕浼楀彿锛**鎹$敯铻虹殑灏忕敺瀛** -- 濡傛灉浣犳槸涓埍瀛︿範鐨勫ソ瀛╁瓙锛屽彲浠ュ叧娉ㄦ垜鍏紬鍙凤紙鎵弿涓嬮潰浜岀淮鐮侊紝杩樻湁寰堝寰堝骞茶揣鏂囩珷锛夛紝涓璧峰涔犺璁哄搱~~ +- 灏忎紮浼村彲浠ュ叧娉ㄦ垜鐨勫叕浼楀彿锛堟壂鎻忎笅闈簩缁寸爜锛岃繕鏈**寰堝寰堝骞茶揣鏂囩珷**锛夛紝涓璧峰涔犺璁哄搱~~ -![image](https://user-images.githubusercontent.com/20244922/179399354-8a9fd2a8-42ba-4303-9ce5-04891e899e6d.png) +![鎵竴鎵玗(https://user-images.githubusercontent.com/20244922/179399354-8a9fd2a8-42ba-4303-9ce5-04891e899e6d.png) diff --git "a/\344\270\255\351\227\264\344\273\266/README.MD" "b/\344\270\255\351\227\264\344\273\266/README.MD" new file mode 100644 index 0000000..74d80b2 --- /dev/null +++ "b/\344\270\255\351\227\264\344\273\266/README.MD" @@ -0,0 +1,8 @@ +## 涓棿浠 + +- [涓鏂囧揩閫熷叆闂ㄥ垎搴撳垎琛ㄤ腑闂翠欢 Sharding-JDBC 锛堝繀淇锛塢(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499781&idx=1&sn=74bbb25c9347408f1edf7f8c9c82d7cf&chksm=cf221f2cf855963a6549069deeabe93bb6d6e889bcd086668bf6f0e23327fa1ddb31adc6d10c&token=1990771297&lang=zh_CN#rd) +- [鍏ㄦ柟浣嶅姣擹ookeeper銆丒ureka銆丯acos銆丆onsul鍜孍tcd](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498268&idx=1&sn=7b24b8625fb4ff88d50c9bd55335f478&chksm=cf222535f855ac230dfca629127f93efec606641d7338c29a8d41e7d2016a7f0b6ec28a432a0&token=1990771297&lang=zh_CN#rd) +- [娑堟伅闃熷垪缁忓吀鍗佽繛闂甝(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497847&idx=1&sn=29a32672b712e7dfadfa36c9902b2ec7&chksm=cf22275ef855ae484fb3f51a5726e9a4bc45222e8fbbd33631d177dc4b5619c36889ea178463&token=1990771297&lang=zh_CN#rd) +- [Kafka鎬ц兘绡囷細涓轰綍Kafka杩欎箞"蹇"锛焆(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488717&idx=1&sn=006c65f9a9a5796961c42f3cafc37cb4&chksm=cf21cbe4f85642f2e8ff948f8de8a69508783cee6dafd22512d6a06cd03f7065001bd1d8d87b&token=1990771297&lang=zh_CN#rd) +- [鍚庣绋嬪簭鍛樺繀澶囷細RocketMQ鐩稿叧娴佺▼鍥/鍘熺悊鍥綸(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487949&idx=1&sn=888e0917884b2918a94053e5cd560e00&chksm=cf21cee4f85647f24877791d574f5ef3f979fc9c4c84ca3fd1ea1aa08ab30c1041ad3aaa5650&token=1990771297&lang=zh_CN#rd) +- [ZooKeeper鐨勫崄浜岃繛闂紝浣犻《寰椾簡鍢涳紵](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488047&idx=1&sn=4913c7e1c3b8835f7512d8dc6b845727&chksm=cf21cd06f8564410cce6121230256facb1ab3b5a9ed35579896f428d84bdea7b86836109d575&token=162724582&lang=zh_CN&scene=21#wechat_redirect) \ No newline at end of file diff --git "a/\345\267\245\344\275\234\346\200\273\347\273\223/READEME.MD" "b/\345\267\245\344\275\234\346\200\273\347\273\223/READEME.MD" new file mode 100644 index 0000000..6c258b9 --- /dev/null +++ "b/\345\267\245\344\275\234\346\200\273\347\273\223/READEME.MD" @@ -0,0 +1,17 @@ +## 宸ヤ綔鎬荤粨 + +- [宸ヤ綔鎬荤粨锛佹棩蹇楁墦鍗扮殑15涓缓璁甝(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247494838&idx=1&sn=cdb15fd346bddf3f8c1c99f0efbd67d8&chksm=cf22339ff855ba891616c79d4f4855e228e34a9fb45088d7acbe421ad511b8d090a90f5b019f&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [25绉嶄唬鐮佸潖鍛抽亾鎬荤粨+浼樺寲绀轰緥](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490148&idx=1&sn=00a181bf74313f751b3ea15ebc303545&chksm=cf21c54df8564c5bc5b4600fce46619f175f7ae557956f449629c470a08e20580feef4ea8d53&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [鑱婅亰鏃ュ父寮鍙戜腑锛屽浣曞噺灏慴ug鍛紵](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490662&idx=1&sn=d38a090611af7f64ee3c6a31331d5228&chksm=cf21c34ff8564a59e505e6edf3065a0fc506c6d2c96f492c8d8873cd46dedbe0704e43cb9c2e&token=1990771297&lang=zh_CN#rd) +- [宸ヤ綔鍥涘勾锛屽垎浜50涓浣犱唬鐮佹洿濂界殑灏忓缓璁甝(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488708&idx=1&sn=6e2e0a740f5d42a59641487a0bf1e3bf&chksm=cf21cbedf85642fbb485fa1c7bf9af21923d8503f2542b6f8283ce79ddc683f7d9e45da83100&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [鍐欎唬鐮佹湁杩16涓ソ涔犳儻锛屽彲浠ュ噺灏80%闈炰笟鍔$殑bug](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488097&idx=1&sn=eaca1f92ca3ccd9de00dbc4ef3e4029a&chksm=cf21cd48f856445e4cc24c1f8bcf18d1479bad0a37a87a2fb70717d8a4e65dcf7b4d5f83d24f&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java鏃ュ父寮鍙戠殑21涓潙锛屼綘韪╄繃鍑犱釜锛焆(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488115&idx=1&sn=bdd4a4ca36bc7ea902106d058e8537fb&chksm=cf21cd5af856444cb36af600705615454b0aaa2b289b97ddb52d594556ac07a1915b73ecce19&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [CAS涔愯閿佽В鍐冲苟鍙戦棶棰樼殑涓娆″疄璺礭(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487937&idx=1&sn=206a37bf6d6a7aa1d05674c479ed7a72&chksm=cf21cee8f85647fe7a082049a41c0f640f54976d2cdf4302b24c5517ca42b854eb84b13ece10&token=1990771297&lang=zh_CN#rd) +- [鍐欎唬鐮佹湁杩欎簺鎯虫硶锛屽悓浜嬫墠涓嶄細璁や负浣犳槸澶嶅埗绮樿创绋嬪簭鍛榏(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487961&idx=1&sn=e646231067968d9f58e6665914293f9a&chksm=cf21cef0f85647e6f3ff2feece004ac3bd979e37fe45103c88d0f299dfe632a5cf6dd547c1d9&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [绋嬪簭鍛樺繀澶囷細Java鏃ユ湡澶勭悊鐨勫崄涓潙](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487973&idx=1&sn=0f713413098fb579e5f200b829f71e89&chksm=cf21ceccf85647da450765d79bf5943da551c3be950447063b9f8c77c21bf2a39b99387a949b&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [鍐呭瓨娉勬紡闂鐨勫垎鏋愬拰瑙e喅鏂规](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487986&idx=1&sn=d681a585ac489703788e3baa48eb9aa3&chksm=cf21cedbf85647cd23bbab9dfec63e6877f83c34efb19bd16075d5d90fea91d3f4a20fc77921&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [绋嬪簭鍛樺繀澶囧熀纭锛氬姞绛鹃獙绛綸(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488022&idx=1&sn=70484a48173d36006c8db1dfb74ab64d&chksm=cf21cd3ff8564429a1205f6c1d78757faae543111c8461d16c71aaee092fe3e0fed870cc5e0e&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [璁颁竴娆℃帴鍙fц兘浼樺寲瀹炶返鎬荤粨锛氫紭鍖栨帴鍙fц兘鐨勫叓涓缓璁甝(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488004&idx=1&sn=00840efd9c0bd0a7f172b59eb2ca130f&chksm=cf21cd2df856443bf21d8e09cfe5c8452ecaf82e3c2210fca3b28829ded04defddcf63c0a59b&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [绋嬪簭鍛樺繀澶囧熀纭锛氬浣曞畨鍏ㄤ紶杈撳瓨鍌ㄧ敤鎴峰瘑鐮侊紵](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488117&idx=1&sn=5d3d0eda0ed45f3f576e211de31ca3a9&chksm=cf21cd5cf856444af1407a94a2abf445265ca7c5f5855cfa1c223cb209e99040c7889621f231&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [涓娆′唬鐮佷紭鍖栧疄璺碉紝鐢ㄤ簡妯℃澘鏂规硶+绛栫暐+宸ュ巶鏂规硶妯″紡](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488061&idx=1&sn=1d9ab7954b03521ab81ecf033c0e5e50&chksm=cf21cd14f8564402b213f0ef908bbdb0e12fed4b281c5803b8e539cacb1551654194becfb7d6&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [淇濊瘉鎺ュ彛鏁版嵁瀹夊叏鐨10绉嶆柟妗圿(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247500285&idx=1&sn=7d0723f25d46e858859cfd79acb6fb9d&chksm=cf221ed4f85597c2093f81baa5fdedc65817bf2d23a7951236836b0f54c2335695cbed61cd13&token=1990771297&lang=zh_CN#rd) \ No newline at end of file diff --git "a/\347\224\237\344\272\247\351\227\256\351\242\230\345\210\206\346\236\220/README.MD" "b/\347\224\237\344\272\247\351\227\256\351\242\230\345\210\206\346\236\220/README.MD" new file mode 100644 index 0000000..15772be --- /dev/null +++ "b/\347\224\237\344\272\247\351\227\256\351\242\230\345\210\206\346\236\220/README.MD" @@ -0,0 +1,8 @@ +## 鐢熶骇闂鍒嗘瀽 + +- [鍐呭瓨娉勬紡闂鐨勫垎鏋愬拰瑙e喅鏂规](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487986&idx=1&sn=d681a585ac489703788e3baa48eb9aa3&chksm=cf21cedbf85647cd23bbab9dfec63e6877f83c34efb19bd16075d5d90fea91d3f4a20fc77921&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [鐢熶骇闂鍒嗘瀽锛乨elete in瀛愭煡璇笉璧扮储寮曪紵锛乚(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247495170&idx=1&sn=ce914de3abdb0d887e286b680b25111f&chksm=cf22312bf855b83d31a00da110626747df8e69fca1bc310642c56e39d663b006a8105f9fb1e1&token=1495321435&lang=zh_CN&scene=21#wechat_redirect) +- [鎵嬫妸鎵嬫暀浣犲垎鏋怣ysql姝婚攣闂](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487979&idx=1&sn=588c83d77a8851f3b3c18cd68ed9c454&chksm=cf21cec2f85647d4a77cc239ae9a4cfd31bb8832be3d98540a08ea8b4a1f46b38cf736210a02&token=1495321435&lang=zh_CN&scene=21#wechat_redirect) +- [绾跨▼姹犺繍鐢ㄤ笉褰撶殑涓娆$嚎涓婁簨鏁匽(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487992&idx=1&sn=733335f2f69d743712915abc99f83b1d&chksm=cf21ced1f85647c7ab8c5d8bc4e8206b04acb5fd4feb94b8d088a782ed458b82aab69dba82aa&token=1990771297&lang=zh_CN#rd) +- [鐩樼偣MySQL鎱㈡煡璇㈢殑12涓師鍥燷(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499624&idx=1&sn=561b9cb7fe831ca7cb2d9fd65691e85e&chksm=cf222041f855a957ac50c0a53baaec6d26be32427259b2974450620f33a8c834419fe535e83d&token=1990771297&lang=zh_CN#rd) +- [绾跨▼姹犲浣曠洃鎺э紝鎵嶈兘甯姪寮鍙戣呭揩閫熷畾浣嶇嚎涓婇敊璇紵](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497444&idx=1&sn=1b2cc8b4685413149e46c814e468c6e6&chksm=cf2229cdf855a0db5f2da881d27c69f11c69480552985baa2a08cbe4d5a48bad7fb31a78dd5a&token=1990771297&lang=zh_CN#rd) \ No newline at end of file diff --git "a/\347\274\223\345\255\230Redis\346\200\273\347\273\223/README.MD" "b/\347\274\223\345\255\230Redis\346\200\273\347\273\223/README.MD" new file mode 100644 index 0000000..996dc81 --- /dev/null +++ "b/\347\274\223\345\255\230Redis\346\200\273\347\273\223/README.MD" @@ -0,0 +1,7 @@ +## 缂撳瓨 + +- [澶у巶缁忓吀闈㈣瘯棰橈細Redis涓轰粈涔堣繖涔堝揩锛焆(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490736&idx=1&sn=95377e729b27f0afefbaa5f20239fc9d&chksm=cf21c399f8564a8ff5239fbaa86d616a48086b47b3bb03c8ccc1d3cc066e41c75e16638c3fc8&token=1495321435&lang=zh_CN&scene=21#wechat_redirect) +- [缇庡洟浜岄潰锛歊edis涓嶮ySQL鍙屽啓涓鑷存у浣曚繚璇侊紵](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490243&idx=1&sn=ff11c3aab9ada3b16d7f2b57c846d567&chksm=cf21c5eaf8564cfc59e3d0d56fd02b0f5513015005f498381be4d12db462442a49aabe4159ef&token=1495321435&lang=zh_CN&scene=21#wechat_redirect) +- [浣跨敤Redis锛屼綘蹇呴』鐭ラ亾鐨21涓敞鎰忚鐐筣(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488325&idx=1&sn=6d9bbe5bf2f2f2904755de5c786fb21b&chksm=cf21cc6cf856457a9d23b3e25ec48107a582e709f05964dfdb5ba77e9a239d8307334c485fdf&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [涓冪鏂规锛佹帰璁≧edis鍒嗗竷寮忛攣鐨勬纭娇鐢ㄥЭ鍔縘(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488142&idx=1&sn=79a304efae7a814b6f71bbbc53810c0c&chksm=cf21cda7f85644b11ff80323defb90193bc1780b45c1c6081f00da85d665fd9eb32cc934b5cf&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [2W瀛楋紒璇﹁В20閬揜edis缁忓吀闈㈣瘯棰橈紒锛堢弽钘忕増锛塢(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247494124&idx=1&sn=c185f7d999d5f006608d05707a8a7eea&chksm=cf2236c5f855bfd329c6e2ee27f23f8131ebcd312960190a10f1a819d67f07a21a08ad17f263&token=162724582&lang=zh_CN&scene=21#wechat_redirect) \ No newline at end of file diff --git "a/\351\253\230\345\271\266\345\217\221/README.MD" "b/\351\253\230\345\271\266\345\217\221/README.MD" new file mode 100644 index 0000000..0ce39a5 --- /dev/null +++ "b/\351\253\230\345\271\266\345\217\221/README.MD" @@ -0,0 +1,7 @@ +## 楂樺苟鍙 +- [缇庡洟浜岄潰锛歊edis涓嶮ySQL鍙屽啓涓鑷存у浣曚繚璇侊紵](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490243&idx=1&sn=ff11c3aab9ada3b16d7f2b57c846d567&chksm=cf21c5eaf8564cfc59e3d0d56fd02b0f5513015005f498381be4d12db462442a49aabe4159ef&token=1495321435&lang=zh_CN&scene=21#wechat_redirect) +- [Redis涓讳粠銆佸摠鍏点 Cluster闆嗙兢涓閿呯锛乚(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498254&idx=1&sn=6489360c3b226df9811e66cb40ec7656&chksm=cf222527f855ac3112628bcec7730064fee3fdbe869fbd0a7410c22766a0c036a7e5c1a69fa0&token=1990771297&lang=zh_CN#rd) +- [闈㈣瘯蹇呭锛氳亰鑱奙ySQL鐨勪富浠嶿(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497982&idx=1&sn=bb589329cceb5462fc41f66ec63dbf56&chksm=cf2227d7f855aec16dd4d3b3425c0401850eeaf2c9cdc82e82722d38a00c24ee9ccfa3353774&token=1990771297&lang=zh_CN#rd) +- [鑱婅亰骞傜瓑璁捐](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497427&idx=1&sn=2ed160c9917ad989eee1ac60d6122855&chksm=cf2229faf855a0ecf5eb34c7335acdf6420426490ee99fc2b602d54ff4ffcecfdab24eeab0a3&token=1990771297&lang=zh_CN#rd) +- [鑱婅亰鎺ュ彛鎬ц兘浼樺寲鐨11涓皬鎶宸(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497361&idx=1&sn=a0a2b0f92804921ba3d31b6236f275c2&chksm=cf2229b8f855a0aec650f4e0c3f105aa08e52fabbc54807dd37fefc4873749698b2b1445b59f&token=1990771297&lang=zh_CN#rd) +- [闈㈣瘯蹇呭锛氱鏉鍦烘櫙涔濅釜缁嗚妭](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247493227&idx=1&sn=10e5064d7d224c69dce400e90cd44de6&chksm=cf223942f855b0541ada22a312e0d4ffbc99df463678247a0dede3ef16eb81e3344a4a54ceaf&token=1990771297&lang=zh_CN#rd) \ No newline at end of file From 6622f7fc024bda2bdc0f14fca6bb0e8cabba3561 Mon Sep 17 00:00:00 2001 From: whx123 <327658337@qq.com> Date: Sat, 23 Jul 2022 12:21:47 +0800 Subject: [PATCH 26/52] update --- .../README.MD" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/\345\244\247\345\216\202\351\235\242\350\257\225\347\234\237\351\242\230/README.MD" "b/\345\244\247\345\216\202\351\235\242\350\257\225\347\234\237\351\242\230/README.MD" index 2fa4767..32264de 100644 --- "a/\345\244\247\345\216\202\351\235\242\350\257\225\347\234\237\351\242\230/README.MD" +++ "b/\345\244\247\345\216\202\351\235\242\350\257\225\347\234\237\351\242\230/README.MD" @@ -10,4 +10,4 @@ - [闈㈣瘯蹇呭锛氳櫨鐨湇鍔$15杩為棶](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497256&idx=1&sn=3b799c2d514aa25e85a6faa60d639a0b&chksm=cf222901f855a017b73356b99b830b8800a7a9172fab891c5759d8dd69a270872ea9480c0b7c&token=2001057130&lang=zh_CN#rd) - [瀹囧畽鏉′竴闈細鍗侀亾缁忓吀闈㈣瘯棰樿В鏋怾(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247495342&idx=1&sn=54e1c0c16a6467001524c34818025331&chksm=cf223187f855b89140db5ca429e6efc19d0111abf7f36b78a0ecd73b00fded1ff1e7ba32a6f1&token=2001057130&lang=zh_CN#rd) - [铓傝殎閲戞湇涓闈細鍗侀亾缁忓吀闈㈣瘯棰樿В鏋怾(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247493270&idx=1&sn=1c78a81d6e1bd0f0fd947fe8c3a33e32&chksm=cf2239bff855b0a9627855f20a17799e0506eb7548a409bfa0ee0450328d7519ec70f7b962cc&token=2001057130&lang=zh_CN#rd) -- [鐢拌灪绮惧搧闈㈣瘯PDF鍙戝竷锛乚(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499943&idx=1&sn=fe869c0a97a306e42830336fe74e17a6&chksm=cf221f8ef8559698781709bfbccbb85087286e48434905fb18bec3a3ec0af7329c2a1632c230&token=1990771297&lang=zh_CN#rd锛 \ No newline at end of file +- [鐢拌灪绮惧搧闈㈣瘯PDF鍙戝竷](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499943&idx=1&sn=fe869c0a97a306e42830336fe74e17a6&chksm=cf221f8ef8559698781709bfbccbb85087286e48434905fb18bec3a3ec0af7329c2a1632c230&token=1990771297&lang=zh_CN#rd锛 \ No newline at end of file From 990ab54b5f96691580ee9f6efd832f830d9fb10d Mon Sep 17 00:00:00 2001 From: whx123 <327658337@qq.com> Date: Sat, 23 Jul 2022 12:23:57 +0800 Subject: [PATCH 27/52] update --- .../README.MD" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/\345\244\247\345\216\202\351\235\242\350\257\225\347\234\237\351\242\230/README.MD" "b/\345\244\247\345\216\202\351\235\242\350\257\225\347\234\237\351\242\230/README.MD" index 32264de..04f4506 100644 --- "a/\345\244\247\345\216\202\351\235\242\350\257\225\347\234\237\351\242\230/README.MD" +++ "b/\345\244\247\345\216\202\351\235\242\350\257\225\347\234\237\351\242\230/README.MD" @@ -10,4 +10,4 @@ - [闈㈣瘯蹇呭锛氳櫨鐨湇鍔$15杩為棶](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497256&idx=1&sn=3b799c2d514aa25e85a6faa60d639a0b&chksm=cf222901f855a017b73356b99b830b8800a7a9172fab891c5759d8dd69a270872ea9480c0b7c&token=2001057130&lang=zh_CN#rd) - [瀹囧畽鏉′竴闈細鍗侀亾缁忓吀闈㈣瘯棰樿В鏋怾(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247495342&idx=1&sn=54e1c0c16a6467001524c34818025331&chksm=cf223187f855b89140db5ca429e6efc19d0111abf7f36b78a0ecd73b00fded1ff1e7ba32a6f1&token=2001057130&lang=zh_CN#rd) - [铓傝殎閲戞湇涓闈細鍗侀亾缁忓吀闈㈣瘯棰樿В鏋怾(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247493270&idx=1&sn=1c78a81d6e1bd0f0fd947fe8c3a33e32&chksm=cf2239bff855b0a9627855f20a17799e0506eb7548a409bfa0ee0450328d7519ec70f7b962cc&token=2001057130&lang=zh_CN#rd) -- [鐢拌灪绮惧搧闈㈣瘯PDF鍙戝竷](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499943&idx=1&sn=fe869c0a97a306e42830336fe74e17a6&chksm=cf221f8ef8559698781709bfbccbb85087286e48434905fb18bec3a3ec0af7329c2a1632c230&token=1990771297&lang=zh_CN#rd锛 \ No newline at end of file +- [鐢拌灪绮惧搧闈㈣瘯PDF鍙戝竷](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499943&idx=1&sn=fe869c0a97a306e42830336fe74e17a6&chksm=cf221f8ef8559698781709bfbccbb85087286e48434905fb18bec3a3ec0af7329c2a1632c230&token=1990771297&lang=zh_CN#rd) \ No newline at end of file From 25b5939239822ba0dd3f0a306e0aaa10d190884e Mon Sep 17 00:00:00 2001 From: whx123 <327658337@qq.com> Date: Mon, 1 Aug 2022 09:14:34 +0800 Subject: [PATCH 28/52] ThreadLocal --- .../README.MD" | 3 ++- .../README.MD.bak" | 21 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 "Java\345\237\272\347\241\200\345\255\246\344\271\240/README.MD.bak" diff --git "a/Java\345\237\272\347\241\200\345\255\246\344\271\240/README.MD" "b/Java\345\237\272\347\241\200\345\255\246\344\271\240/README.MD" index 0a1609f..a038f88 100644 --- "a/Java\345\237\272\347\241\200\345\255\246\344\271\240/README.MD" +++ "b/Java\345\237\272\347\241\200\345\255\246\344\271\240/README.MD" @@ -18,4 +18,5 @@ - [鑰佹槸閬囧埌涔辩爜闂锛氬畠鏄浣曚骇鐢熺殑锛屽張濡備綍瑙e喅鍛紵](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487962&idx=1&sn=7424e843c80b228283fc08d4d24cc4bb&chksm=cf21cef3f85647e5a9c92d280624ad2564e885561a8b64cbf6722459f7c13da7421765321aa9&token=162724582&lang=zh_CN&scene=21#wechat_redirect) - [璋堣皥Java鍙嶅皠锛氫粠鍏ラ棬鍒板疄璺碉紝鍐嶅埌鍘熺悊](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487959&idx=1&sn=778114d611f18b0f307a3f3ab6cd9117&chksm=cf21cefef85647e84b77c0e46620e91cf5ff079785b58a7dc66e5ed7419e21e0da9180699617&token=162724582&lang=zh_CN&scene=21#wechat_redirect) - [Java绋嬪簭鍛樺繀澶囩殑涓浜涙祦绋嬪浘](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487946&idx=1&sn=57a86e1d2fe1a9ecf00594a0bb6baf5f&chksm=cf21cee3f85647f5cf2ba728cc0838923140130a18ad117e248cf9843460614fc855d556968a&token=162724582&lang=zh_CN&scene=21#wechat_redirect) -- [Java绋嬪簭鍛樺繀澶囷細鏌ョ湅鏃ュ織甯哥敤鐨刲inux鍛戒护](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487954&idx=1&sn=6c04ff4edfcfea52a82795bcb9ed8efd&chksm=cf21cefbf85647ed8df72a23307315be5d1b3d4974c128f111bfdaa84da37cf7b49ff65c1112&token=162724582&lang=zh_CN&scene=21#wechat_redirect) \ No newline at end of file +- [Java绋嬪簭鍛樺繀澶囷細鏌ョ湅鏃ュ織甯哥敤鐨刲inux鍛戒护](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487954&idx=1&sn=6c04ff4edfcfea52a82795bcb9ed8efd&chksm=cf21cefbf85647ed8df72a23307315be5d1b3d4974c128f111bfdaa84da37cf7b49ff65c1112&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [ThreadLocal鐨勫叓涓叧閿煡璇嗙偣](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247500784&idx=1&sn=6519d0e092be4ed9d6f4da8d90deef2c&chksm=cf221cd9f85595cf9123043241e92a19ca9c212aa8527cfb2aeb9a2472c6bdab9045cf40f22f&token=349136600&lang=zh_CN#rd) \ No newline at end of file diff --git "a/Java\345\237\272\347\241\200\345\255\246\344\271\240/README.MD.bak" "b/Java\345\237\272\347\241\200\345\255\246\344\271\240/README.MD.bak" new file mode 100644 index 0000000..4ba4024 --- /dev/null +++ "b/Java\345\237\272\347\241\200\345\255\246\344\271\240/README.MD.bak" @@ -0,0 +1,21 @@ +## Java鍩虹绡囷紙鎸佺画鏇存柊涓級 +鈥 +鍏紬鍙凤細鎹$敯铻虹殑灏忕敺瀛 +鈥 +- [涓鏂囪鎳傜嚎绋嬫睜鐨勫伐浣滃師鐞嗭紙鏁呬簨鐧借瘽鏂囷級](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488078&idx=1&sn=0a7cef472002f6582fd2354fba83706a&chksm=cf21cd67f85644716263c3a80cead9b7bb36d9677f6f8b06d0602077ece70fcafa9d20c1cffb&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Synchronized瑙f瀽鈥斺斿鏋滀綘鎰挎剰涓灞備竴灞傚墺寮鎴戠殑蹇僝(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487942&idx=1&sn=bbc68d1b9da23bf6474378e310b1ef1b&chksm=cf21ceeff85647f9ad7a08226849fcba3f9481387d13b17a5787fb94027647de81c349f9e390&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [寮傛缂栫▼鍒╁櫒锛欳ompletableFuture璇﹁В](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490456&idx=1&sn=95836324db57673a4d7aea4fb233c0d2&chksm=cf21c4b1f8564da72dc7b39279362bcf965b1374540f3b339413d138599f7de59a5f977e3b0e&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java鏃ュ父寮鍙戠殑21涓潙锛屼綘韪╄繃鍑犱釜锛焆(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488115&idx=1&sn=bdd4a4ca36bc7ea902106d058e8537fb&chksm=cf21cd5af856444cb36af600705615454b0aaa2b289b97ddb52d594556ac07a1915b73ecce19&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [涓浠絁ava绋嬪簭鍛樼殑鐝嶈棌涔﹀崟锛岃鎮ㄦ敞鎰忔煡鏀禲(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488066&idx=1&sn=44b5a90be1b69d7938dbcf516d85f041&chksm=cf21cd6bf856447d869278386250f59a926881375df848e54f86a21682bdab50f9e09ca56fbd&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java绋嬪簭鍛樺繀澶囧熀纭锛欽DK 5-15閮芥湁鍝簺缁忓吀鏂扮壒鎬(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488058&idx=1&sn=aab4d0dc9020cb62710086474ca90baf&chksm=cf21cd13f8564405040593daa45c62aec218e13f5ff42d679c59f768dd4fcc53ddcf34e0a454&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [绋嬪簭鍛樺繀澶囧熀纭锛欸it 鍛戒护鍏ㄦ柟浣嶅涔燷(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488013&idx=1&sn=7011a51a347e3da2cf8f8540b4d9a5d6&chksm=cf21cd24f8564432d74bc13551ebdeae71a71ea31e339c7a8f1f42f181078b5192475d598626&token=162724582&ang=zh_CN&scene=21#wechat_redirect) +- [缁欎綘鐨凧ava绋嬪簭鎷嶄釜鐗囧瓙鍚э細jstack鍛戒护瑙f瀽](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487990&idx=1&sn=b5b3c565392f39e5ac517696603b2ed9&chksm=cf21cedff85647c960407dce77fe04d08e51f8c7332310ccacd925be5567c187aa761dd1d1c8&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java绋嬪簭鍛樺繀澶囧熀纭缁撴瀯鍥綸(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487985&idx=1&sn=ead28c6c8d81b98e59603b848d250b30&chksm=cf21ced8f85647ce336f19016c7ff1936b21c81066815c8f28b830098716111548edb9767b21&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java绋嬪簭鍛樺繀澶囷細搴忓垪鍖栧叏鏂逛綅瑙f瀽](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487980&idx=1&sn=2a9ce519f87a1ffe1511022e6724208e&chksm=cf21cec5f85647d357c79860171fc1799ef3c44a2bdd0716e8437e31708a17d9000b4224bd36&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [浼樺寲if-else浠g爜鐨勫叓绉嶆柟妗圿(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487970&idx=1&sn=c296bb03419adf93955c6d0f27e56b29&chksm=cf21cecbf85647dd0ef5160559bc0d524a4be004a28bc5d2770a43409e3b090123c0930cf047&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java绋嬪簭鍛樺繀澶囧熀纭锛氭硾鍨嬭В鏋怾(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487964&idx=1&sn=24d7228cc10afc98c52dbf35da61a7b9&chksm=cf21cef5f85647e3d2b3f1e126cdc46d9e889d2e30c09716e0aea016beee3ca6d4c321cf60ae&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java绋嬪簭鍛樺繀澶囧熀纭锛氬唴閮ㄧ被瑙f瀽](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487963&idx=1&sn=a0b49cd49a3dd51b6736c9ffa0a5997a&chksm=cf21cef2f85647e49a4bdb43f27583f03fb9ec4719767512dc084edd05675599c3bec44251fb&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [鑰佹槸閬囧埌涔辩爜闂锛氬畠鏄浣曚骇鐢熺殑锛屽張濡備綍瑙e喅鍛紵](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487962&idx=1&sn=7424e843c80b228283fc08d4d24cc4bb&chksm=cf21cef3f85647e5a9c92d280624ad2564e885561a8b64cbf6722459f7c13da7421765321aa9&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [璋堣皥Java鍙嶅皠锛氫粠鍏ラ棬鍒板疄璺碉紝鍐嶅埌鍘熺悊](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487959&idx=1&sn=778114d611f18b0f307a3f3ab6cd9117&chksm=cf21cefef85647e84b77c0e46620e91cf5ff079785b58a7dc66e5ed7419e21e0da9180699617&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java绋嬪簭鍛樺繀澶囩殑涓浜涙祦绋嬪浘](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487946&idx=1&sn=57a86e1d2fe1a9ecf00594a0bb6baf5f&chksm=cf21cee3f85647f5cf2ba728cc0838923140130a18ad117e248cf9843460614fc855d556968a&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java绋嬪簭鍛樺繀澶囷細鏌ョ湅鏃ュ織甯哥敤鐨刲inux鍛戒护](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487954&idx=1&sn=6c04ff4edfcfea52a82795bcb9ed8efd&chksm=cf21cefbf85647ed8df72a23307315be5d1b3d4974c128f111bfdaa84da37cf7b49ff65c1112&token=162724582&lang=zh_CN&scene=21#wechat_redirect) \ No newline at end of file From c4ee666f89f31d45051ecd95b96a907fc4d4d840 Mon Sep 17 00:00:00 2001 From: whx123 <327658337@qq.com> Date: Mon, 22 Aug 2022 08:07:36 +0800 Subject: [PATCH 29/52] =?UTF-8?q?=E5=A4=9A=E7=BA=BF=E7=A8=8B=E9=9D=A2?= =?UTF-8?q?=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../README.MD" | 3 +- .../README.MD.bak" | 31 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 "Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/README.MD.bak" diff --git "a/Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/README.MD" "b/Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/README.MD" index 78fbb48..7397d39 100644 --- "a/Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/README.MD" +++ "b/Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/README.MD" @@ -28,4 +28,5 @@ - [ZooKeeper鐨勫崄浜岃繛闂紝浣犻《寰椾簡鍢涳紵](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488047&idx=1&sn=4913c7e1c3b8835f7512d8dc6b845727&chksm=cf21cd06f8564410cce6121230256facb1ab3b5a9ed35579896f428d84bdea7b86836109d575&token=162724582&lang=zh_CN&scene=21#wechat_redirect) - [50閬揓ava闆嗗悎缁忓吀闈㈣瘯棰橈紙鏀惰棌鐗堬級](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488007&idx=1&sn=c5c16c8ec916c791e776216f3177c7e2&chksm=cf21cd2ef85644382a985e9fed1956d6ee60c86ce69e65f31f775318435fdb86bf368e26edf2&token=162724582&lang=zh_CN&scene=21#wechat_redirect) - [100閬揗ySQL鏁版嵁搴撶粡鍏搁潰璇曢瑙f瀽锛堟敹钘忕増锛塢(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488000&idx=1&sn=1c38db7fd110bbcc1ffb2d72a56aaf25&chksm=cf21cd29f856443f25a3fe98ae8e888faceef9bee45df045969b2cffb105363dcc2a4480bb74&token=1495321435&lang=zh_CN&scene=21#wechat_redirect) -- [Spring 闈㈣瘯63闂甝(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497672&idx=1&sn=6ff0350e23d014b29a47bdec79af9ef5&chksm=cf2228e1f855a1f70fa78d9bd85c53dfbe154c1325aa1e203e4c918132c430d51bb68e961eda&token=2001057130&lang=zh_CN#rd) \ No newline at end of file +- [Spring 闈㈣瘯63闂甝(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497672&idx=1&sn=6ff0350e23d014b29a47bdec79af9ef5&chksm=cf2228e1f855a1f70fa78d9bd85c53dfbe154c1325aa1e203e4c918132c430d51bb68e961eda&token=2001057130&lang=zh_CN#rd) +- [澶氱嚎绋50杩為棶](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247501446&idx=1&sn=3d83f3c1035c963c1fda3f77ab750e71&chksm=cf2219aff85590b9ba054dc33956a5cafe1beaa77b231dc4dc0cf891be3e16ef367f6b2ac4ed&token=245109219&lang=zh_CN#rd) \ No newline at end of file diff --git "a/Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/README.MD.bak" "b/Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/README.MD.bak" new file mode 100644 index 0000000..cfb8d9d --- /dev/null +++ "b/Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/README.MD.bak" @@ -0,0 +1,31 @@ +## 1. 闈㈣瘯鐪熼 + +鍏虫敞鍏紬鍙凤細鎹$敯铻虹殑灏忕敺瀛 +鈥 +- [oppo鍚庣16杩為棶](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498750&idx=1&sn=19fe8b4fff28fe81db14e733053bbc74&chksm=cf2224d7f855adc1d0984980a4e3de31fe33329164a472ca8d8255a8a80b69b2e23850811323&token=2001057130&lang=zh_CN#rd) +- [灏忓巶鍚庣鍗佽繛闂紙闄勭瓟妗堬級](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498316&idx=1&sn=7749b78293b7b2af51eda99844e08a56&chksm=cf222565f855ac7324232e2af459f8b6e6eb5fd5b272c2b29bda08cc579421b6704a0de94b2e&token=2001057130&lang=zh_CN#rd) +- [鑵捐浜戝悗绔15杩為棶锛乚(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498171&idx=1&sn=f5a7ec25a569822be0f73fbcd413e8ba&chksm=cf222692f855af84fba419166fcd4235c0e78af3a2e1ec4c723a4efb1bd1ad6f8a5b9404c599&token=2001057130&lang=zh_CN#rd) +- [绀炬嫑鍚庣21杩為棶锛堜笁骞村伐浣滅粡楠屼竴闈級](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498084&idx=1&sn=96c8148cfeeeb16668ed9e03fa9131cc&chksm=cf22264df855af5b6e81b93738cca28989226a53ec702fcfaa0cc5004dded4208c5ee5ea844a&token=2001057130&lang=zh_CN#rd) +- [涓浠界儹涔庝箮鐨勫瓧鑺傞潰璇曠湡棰榏(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497742&idx=1&sn=18765e7356f446a7f2521f45b467d5d3&chksm=cf222727f855ae31dd2029e3219814211336c41d9228d271a583d3691ddadca586529aca9302&token=2001057130&lang=zh_CN#rd) +- [闈㈣瘯蹇呭锛氳櫨鐨湇鍔$15杩為棶](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497256&idx=1&sn=3b799c2d514aa25e85a6faa60d639a0b&chksm=cf222901f855a017b73356b99b830b8800a7a9172fab891c5759d8dd69a270872ea9480c0b7c&token=2001057130&lang=zh_CN#rd) +- [瀹囧畽鏉′竴闈細鍗侀亾缁忓吀闈㈣瘯棰樿В鏋怾(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247495342&idx=1&sn=54e1c0c16a6467001524c34818025331&chksm=cf223187f855b89140db5ca429e6efc19d0111abf7f36b78a0ecd73b00fded1ff1e7ba32a6f1&token=2001057130&lang=zh_CN#rd) +- [铓傝殎閲戞湇涓闈細鍗侀亾缁忓吀闈㈣瘯棰樿В鏋怾(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247493270&idx=1&sn=1c78a81d6e1bd0f0fd947fe8c3a33e32&chksm=cf2239bff855b0a9627855f20a17799e0506eb7548a409bfa0ee0450328d7519ec70f7b962cc&token=2001057130&lang=zh_CN#rd) +鈥 +## 2. 蹇呰冪粡鍏搁潰璇曢 +鈥 +- [Redis涓讳粠銆佸摠鍏点 Cluster闆嗙兢涓閿呯锛乚(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498254&idx=1&sn=6489360c3b226df9811e66cb40ec7656&chksm=cf222527f855ac3112628bcec7730064fee3fdbe869fbd0a7410c22766a0c036a7e5c1a69fa0&token=2001057130&lang=zh_CN#rd) +- [鎴戜滑涓轰粈涔堣鍒嗗簱鍒嗚〃锛焆(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498625&idx=1&sn=0d7bd9d1b46eeff4c715a6761355e9b0&chksm=cf2224a8f855adbea8931c8e011711f6c70cffeef8ddf8b87729c710eacef11b46eef80fda36&token=2001057130&lang=zh_CN#rd) +- [闈㈣瘯蹇呭锛氳亰鑱奙ySQL鐨勪富浠嶿(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497982&idx=1&sn=bb589329cceb5462fc41f66ec63dbf56&chksm=cf2227d7f855aec16dd4d3b3425c0401850eeaf2c9cdc82e82722d38a00c24ee9ccfa3353774&token=2001057130&lang=zh_CN#rd) +- [娑堟伅闃熷垪缁忓吀鍗佽繛闂甝(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497847&idx=1&sn=29a32672b712e7dfadfa36c9902b2ec7&chksm=cf22275ef855ae484fb3f51a5726e9a4bc45222e8fbbd33631d177dc4b5619c36889ea178463&token=2001057130&lang=zh_CN#rd) +- [鍏骞傜瓑璁捐](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497427&idx=1&sn=2ed160c9917ad989eee1ac60d6122855&chksm=cf2229faf855a0ecf5eb34c7335acdf6420426490ee99fc2b602d54ff4ffcecfdab24eeab0a3&token=2001057130&lang=zh_CN#rd) +- [鐪嬩竴閬嶅氨鐞嗚В锛氶浂鎷疯礉璇﹁В](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247496788&idx=1&sn=f65ddd10d16d8376efa0037762153932&chksm=cf222b7df855a26bad76249e7b77e28da3097b226f9165d79f5031516d9c345827fca901559c&token=2001057130&lang=zh_CN#rd) +- [鐪嬩竴閬嶅氨鐞嗚В锛欼O妯″瀷璇﹁В](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247496448&idx=1&sn=cd502f850290a25949dd4a11ac55a039&chksm=cf222c29f855a53f094bde2868900fa252b07385e73564e9ee9f0510cb4e74387d9d23ab67e6&token=2001057130&lang=zh_CN#rd) +- [鐪嬩竴閬嶅氨鐞嗚В锛歁VCC鍘熺悊璇﹁В](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247495277&idx=1&sn=a1812febb4246f824ce54d778f672025&chksm=cf223144f855b8528ad6cce707dc3a1b4d387817bd751dfab4f79dda90c6640f9763d25f3f33&token=2001057130&lang=zh_CN#rd) +- [2W瀛楋紒璇﹁В20閬揜edis缁忓吀闈㈣瘯棰橈紒锛堢弽钘忕増锛塢(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247494124&idx=1&sn=c185f7d999d5f006608d05707a8a7eea&chksm=cf2236c5f855bfd329c6e2ee27f23f8131ebcd312960190a10f1a819d67f07a21a08ad17f263&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [涓冪鏂规锛佹帰璁≧edis鍒嗗竷寮忛攣鐨勬纭娇鐢ㄥЭ鍔縘(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488142&idx=1&sn=79a304efae7a814b6f71bbbc53810c0c&chksm=cf21cda7f85644b11ff80323defb90193bc1780b45c1c6081f00da85d665fd9eb32cc934b5cf&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [闈㈣瘯蹇呭锛乀CP鍗忚缁忓吀鍗佷簲杩為棶锛乚(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490868&idx=1&sn=96889bfe6a97f9200fa2d682cf2f5d89&chksm=cf21c21df8564b0b0757df584560a69340b1775fe1c70b867439565969ec3aed19c442ff4eeb&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [2W瀛楋紒姊崇悊50閬撶粡鍏歌绠楁満缃戠粶闈㈣瘯棰橈紙鏀惰棌鐗堬級](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247492832&idx=1&sn=601fa1c340a313bc0f74bb75cdb6a95a&chksm=cf223bc9f855b2dfb8d0e74f3360e2edfe25c3a728fe17e9e80b6022340994fd9d9e1ca83ca8&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [ZooKeeper鐨勫崄浜岃繛闂紝浣犻《寰椾簡鍢涳紵](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488047&idx=1&sn=4913c7e1c3b8835f7512d8dc6b845727&chksm=cf21cd06f8564410cce6121230256facb1ab3b5a9ed35579896f428d84bdea7b86836109d575&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [50閬揓ava闆嗗悎缁忓吀闈㈣瘯棰橈紙鏀惰棌鐗堬級](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488007&idx=1&sn=c5c16c8ec916c791e776216f3177c7e2&chksm=cf21cd2ef85644382a985e9fed1956d6ee60c86ce69e65f31f775318435fdb86bf368e26edf2&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [100閬揗ySQL鏁版嵁搴撶粡鍏搁潰璇曢瑙f瀽锛堟敹钘忕増锛塢(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488000&idx=1&sn=1c38db7fd110bbcc1ffb2d72a56aaf25&chksm=cf21cd29f856443f25a3fe98ae8e888faceef9bee45df045969b2cffb105363dcc2a4480bb74&token=1495321435&lang=zh_CN&scene=21#wechat_redirect) +- [Spring 闈㈣瘯63闂甝(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497672&idx=1&sn=6ff0350e23d014b29a47bdec79af9ef5&chksm=cf2228e1f855a1f70fa78d9bd85c53dfbe154c1325aa1e203e4c918132c430d51bb68e961eda&token=2001057130&lang=zh_CN#rd) \ No newline at end of file From 5f8568677c29c4e9eed376abc99d1aebbc0c5e0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Tue, 28 May 2024 00:09:01 +0800 Subject: [PATCH 30/52] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 鍘婚噸妯℃澘 --- .../README.md" | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git "a/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207/README.md" "b/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207/README.md" index c23117d..afd9e7d 100644 --- "a/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207/README.md" +++ "b/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207/README.md" @@ -1,9 +1,10 @@ -## 后端思维篇(持续更新中) - -公众号:捡田螺的小男孩 - -- [后端思想篇:设计好接口的36个锦囊!](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499388&idx=1&sn=49a22120a3238e13ad7c3d3b73d9e453&chksm=cf222155f855a8434026b2c460d963c406186578c2527ca8f2bb829bbe849d87a2392a525a9b&scene=178&cur_album_id=2396778860463161350#rd) -- [后端思维篇:手把手教你写一个并行调用模板](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499504&idx=1&sn=bb62226e6cffeb1859efb0100c796050&chksm=cf2221d9f855a8cf23f75cb51c1a407578fb0f279e96ddae74b5b8c84f2f5dc71762425b17cb&scene=178&cur_album_id=2396778860463161350#rd) -- [后端思维篇:如何应用设计模式优化代码](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499524&idx=1&sn=cb4cc48a3e8d9a54b0ebc4c7ad517f14&chksm=cf22202df855a93b37327856ee88b0bf5f6ed7da67964438fc2cf747666260d5026dd62d4a17&scene=178&cur_album_id=2396778860463161350#rd) -- [后端思维篇:统一参数校验、异常处理、结果返回](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499708&idx=1&sn=808979c495acd9344732d147c0ad40d3&chksm=cf222095f855a983f31d5f6abf401fa3b5967f8839c6775d35cefc5cc6244fb4135563ff1090&scene=178&cur_album_id=2396778860463161350#rd) -- [后端思维篇:如何抽一个观察者模板](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247500159&idx=1&sn=a5328372e580b22c939a5b3084aef164&chksm=cf221e56f85597401e8c99b8dd1bc1af97fcf69207ceaa04c5c26e028ac47d1658b79ae32291&scene=178&cur_album_id=2396778860463161350#rd) +## 鍚庣鎬濈淮绡囷紙鎸佺画鏇存柊涓級 + +鍏紬鍙凤細鎹$敯铻虹殑灏忕敺瀛 + +- [鍚庣鎬濇兂绡囷細璁捐濂芥帴鍙g殑36涓敠鍥婏紒](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499388&idx=1&sn=49a22120a3238e13ad7c3d3b73d9e453&chksm=cf222155f855a8434026b2c460d963c406186578c2527ca8f2bb829bbe849d87a2392a525a9b&scene=178&cur_album_id=2396778860463161350#rd) +- [鍚庣鎬濈淮绡囷細鎵嬫妸鎵嬫暀浣犲啓涓涓苟琛岃皟鐢ㄦā鏉縘(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499504&idx=1&sn=bb62226e6cffeb1859efb0100c796050&chksm=cf2221d9f855a8cf23f75cb51c1a407578fb0f279e96ddae74b5b8c84f2f5dc71762425b17cb&scene=178&cur_album_id=2396778860463161350#rd) +- [鍚庣鎬濈淮绡囷細濡備綍搴旂敤璁捐妯″紡浼樺寲浠g爜](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499524&idx=1&sn=cb4cc48a3e8d9a54b0ebc4c7ad517f14&chksm=cf22202df855a93b37327856ee88b0bf5f6ed7da67964438fc2cf747666260d5026dd62d4a17&scene=178&cur_album_id=2396778860463161350#rd) +- [鍚庣鎬濈淮绡:缁熶竴鍙傛暟鏍¢獙銆佸紓甯稿鐞嗐佺粨鏋滆繑鍥瀅(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499708&idx=1&sn=808979c495acd9344732d147c0ad40d3&chksm=cf222095f855a983f31d5f6abf401fa3b5967f8839c6775d35cefc5cc6244fb4135563ff1090&scene=178&cur_album_id=2396778860463161350#rd) +- [鍚庣鎬濈淮绡:濡備綍鎶戒竴涓瀵熻呮ā鏉縘(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247500159&idx=1&sn=a5328372e580b22c939a5b3084aef164&chksm=cf221e56f85597401e8c99b8dd1bc1af97fcf69207ceaa04c5c26e028ac47d1658b79ae32291&scene=178&cur_album_id=2396778860463161350#rd) +- - [鍚庣鎬濈淮绡:鍚庣鎬濈淮涓撴爮锛氶氳繃灞傚眰浠g爜鍘婚噸锛屾垜鍙堟悶浜嗕竴涓氱敤妯℃澘](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247506942&idx=1&sn=ae14ed5cc179f73ea0b2f37c73ad8da4&chksm=c1e02672f697af645943ea8ee53b7cef6257ebbc21d2b77058994e98bdb1e107ad313e29e8c3&token=134957671&lang=zh_CN#rd) From 69157df1112e21f5c4ad39512d5caacd3fb40f36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Tue, 28 May 2024 00:09:20 +0800 Subject: [PATCH 31/52] Update README.md --- .../README.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207/README.md" "b/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207/README.md" index afd9e7d..7f6092a 100644 --- "a/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207/README.md" +++ "b/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207/README.md" @@ -7,4 +7,4 @@ - [鍚庣鎬濈淮绡囷細濡備綍搴旂敤璁捐妯″紡浼樺寲浠g爜](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499524&idx=1&sn=cb4cc48a3e8d9a54b0ebc4c7ad517f14&chksm=cf22202df855a93b37327856ee88b0bf5f6ed7da67964438fc2cf747666260d5026dd62d4a17&scene=178&cur_album_id=2396778860463161350#rd) - [鍚庣鎬濈淮绡:缁熶竴鍙傛暟鏍¢獙銆佸紓甯稿鐞嗐佺粨鏋滆繑鍥瀅(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499708&idx=1&sn=808979c495acd9344732d147c0ad40d3&chksm=cf222095f855a983f31d5f6abf401fa3b5967f8839c6775d35cefc5cc6244fb4135563ff1090&scene=178&cur_album_id=2396778860463161350#rd) - [鍚庣鎬濈淮绡:濡備綍鎶戒竴涓瀵熻呮ā鏉縘(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247500159&idx=1&sn=a5328372e580b22c939a5b3084aef164&chksm=cf221e56f85597401e8c99b8dd1bc1af97fcf69207ceaa04c5c26e028ac47d1658b79ae32291&scene=178&cur_album_id=2396778860463161350#rd) -- - [鍚庣鎬濈淮绡:鍚庣鎬濈淮涓撴爮锛氶氳繃灞傚眰浠g爜鍘婚噸锛屾垜鍙堟悶浜嗕竴涓氱敤妯℃澘](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247506942&idx=1&sn=ae14ed5cc179f73ea0b2f37c73ad8da4&chksm=c1e02672f697af645943ea8ee53b7cef6257ebbc21d2b77058994e98bdb1e107ad313e29e8c3&token=134957671&lang=zh_CN#rd) +- [鍚庣鎬濈淮绡:鍚庣鎬濈淮涓撴爮锛氶氳繃灞傚眰浠g爜鍘婚噸锛屾垜鍙堟悶浜嗕竴涓氱敤妯℃澘](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247506942&idx=1&sn=ae14ed5cc179f73ea0b2f37c73ad8da4&chksm=c1e02672f697af645943ea8ee53b7cef6257ebbc21d2b77058994e98bdb1e107ad313e29e8c3&token=134957671&lang=zh_CN#rd) From cc34588ff185f81499ed16886ba12ab2f45a4200 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Wed, 29 May 2024 08:10:08 +0800 Subject: [PATCH 32/52] =?UTF-8?q?=E8=AE=BE=E8=AE=A1=E6=96=B9=E6=A1=88?= =?UTF-8?q?=E6=80=9D=E8=80=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\350\256\241\346\226\271\346\241\210\346\200\235\350\200\203" | 1 + 1 file changed, 1 insertion(+) create mode 100644 "\350\256\276\350\256\241\346\226\271\346\241\210\346\200\235\350\200\203" diff --git "a/\350\256\276\350\256\241\346\226\271\346\241\210\346\200\235\350\200\203" "b/\350\256\276\350\256\241\346\226\271\346\241\210\346\200\235\350\200\203" new file mode 100644 index 0000000..8b13789 --- /dev/null +++ "b/\350\256\276\350\256\241\346\226\271\346\241\210\346\200\235\350\200\203" @@ -0,0 +1 @@ + From b7dc04bece928bfc858d1d27b729192f804dbb47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Wed, 29 May 2024 08:15:46 +0800 Subject: [PATCH 33/52] =?UTF-8?q?Delete=20=E8=AE=BE=E8=AE=A1=E6=96=B9?= =?UTF-8?q?=E6=A1=88=E6=80=9D=E8=80=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\350\256\241\346\226\271\346\241\210\346\200\235\350\200\203" | 1 - 1 file changed, 1 deletion(-) delete mode 100644 "\350\256\276\350\256\241\346\226\271\346\241\210\346\200\235\350\200\203" diff --git "a/\350\256\276\350\256\241\346\226\271\346\241\210\346\200\235\350\200\203" "b/\350\256\276\350\256\241\346\226\271\346\241\210\346\200\235\350\200\203" deleted file mode 100644 index 8b13789..0000000 --- "a/\350\256\276\350\256\241\346\226\271\346\241\210\346\200\235\350\200\203" +++ /dev/null @@ -1 +0,0 @@ - From 80ca854a4f4d0abd607a20707ba37cba1568129c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Wed, 29 May 2024 08:16:54 +0800 Subject: [PATCH 34/52] =?UTF-8?q?Create=20=E5=B8=B8=E8=A7=81=E6=96=B9?= =?UTF-8?q?=E6=A1=88=E8=AE=BE=E8=AE=A1.txt=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\226\271\346\241\210\350\256\276\350\256\241.txt\343\200\202" | 1 + 1 file changed, 1 insertion(+) create mode 100644 "\346\226\271\346\241\210\350\256\276\350\256\241/\345\270\270\350\247\201\346\226\271\346\241\210\350\256\276\350\256\241.txt\343\200\202" diff --git "a/\346\226\271\346\241\210\350\256\276\350\256\241/\345\270\270\350\247\201\346\226\271\346\241\210\350\256\276\350\256\241.txt\343\200\202" "b/\346\226\271\346\241\210\350\256\276\350\256\241/\345\270\270\350\247\201\346\226\271\346\241\210\350\256\276\350\256\241.txt\343\200\202" new file mode 100644 index 0000000..8b13789 --- /dev/null +++ "b/\346\226\271\346\241\210\350\256\276\350\256\241/\345\270\270\350\247\201\346\226\271\346\241\210\350\256\276\350\256\241.txt\343\200\202" @@ -0,0 +1 @@ + From 2c5c0061a37d5c49c5f9a8e87be81c2923f4b90a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Wed, 29 May 2024 08:19:40 +0800 Subject: [PATCH 35/52] =?UTF-8?q?Update=20=E5=B8=B8=E8=A7=81=E6=96=B9?= =?UTF-8?q?=E6=A1=88=E8=AE=BE=E8=AE=A1.txt=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...26\271\346\241\210\350\256\276\350\256\241.txt\343\200\202" | 3 +++ 1 file changed, 3 insertions(+) diff --git "a/\346\226\271\346\241\210\350\256\276\350\256\241/\345\270\270\350\247\201\346\226\271\346\241\210\350\256\276\350\256\241.txt\343\200\202" "b/\346\226\271\346\241\210\350\256\276\350\256\241/\345\270\270\350\247\201\346\226\271\346\241\210\350\256\276\350\256\241.txt\343\200\202" index 8b13789..4d183d2 100644 --- "a/\346\226\271\346\241\210\350\256\276\350\256\241/\345\270\270\350\247\201\346\226\271\346\241\210\350\256\276\350\256\241.txt\343\200\202" +++ "b/\346\226\271\346\241\210\350\256\276\350\256\241/\345\270\270\350\247\201\346\226\271\346\241\210\350\256\276\350\256\241.txt\343\200\202" @@ -1 +1,4 @@ + + +- [瀹炵幇涓涓埛鏁颁换鍔★紝闇瑕佹濊冨摢浜涚淮搴︼紵](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247508890&idx=1&sn=919b8a794eb4902d958ae13d1f424737&chksm=c1e05e16f697d700ee9f79e087279de6312222b8e45887d976a572b01599f1177b358ade265b&token=337310304&lang=zh_CN#rd) From 7f2a4de82c2cd78b3d6150ff7c8c59f6c5b108c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Wed, 29 May 2024 08:21:54 +0800 Subject: [PATCH 36/52] =?UTF-8?q?Delete=20=E6=96=B9=E6=A1=88=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=20directory?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...6\271\346\241\210\350\256\276\350\256\241.txt\343\200\202" | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 "\346\226\271\346\241\210\350\256\276\350\256\241/\345\270\270\350\247\201\346\226\271\346\241\210\350\256\276\350\256\241.txt\343\200\202" diff --git "a/\346\226\271\346\241\210\350\256\276\350\256\241/\345\270\270\350\247\201\346\226\271\346\241\210\350\256\276\350\256\241.txt\343\200\202" "b/\346\226\271\346\241\210\350\256\276\350\256\241/\345\270\270\350\247\201\346\226\271\346\241\210\350\256\276\350\256\241.txt\343\200\202" deleted file mode 100644 index 4d183d2..0000000 --- "a/\346\226\271\346\241\210\350\256\276\350\256\241/\345\270\270\350\247\201\346\226\271\346\241\210\350\256\276\350\256\241.txt\343\200\202" +++ /dev/null @@ -1,4 +0,0 @@ - - - -- [瀹炵幇涓涓埛鏁颁换鍔★紝闇瑕佹濊冨摢浜涚淮搴︼紵](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247508890&idx=1&sn=919b8a794eb4902d958ae13d1f424737&chksm=c1e05e16f697d700ee9f79e087279de6312222b8e45887d976a572b01599f1177b358ade265b&token=337310304&lang=zh_CN#rd) From f1c359865a5e9480b397af07f38f62d8fa17de0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Wed, 29 May 2024 08:22:13 +0800 Subject: [PATCH 37/52] Create README.MD --- "\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" | 1 + 1 file changed, 1 insertion(+) create mode 100644 "\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" diff --git "a/\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" "b/\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" new file mode 100644 index 0000000..8b13789 --- /dev/null +++ "b/\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" @@ -0,0 +1 @@ + From 5a53f80abc864e3527562970649d82c7c902f509 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Wed, 29 May 2024 08:23:23 +0800 Subject: [PATCH 38/52] Update README.MD --- "\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" "b/\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" index 8b13789..e38139f 100644 --- "a/\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" +++ "b/\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" @@ -1 +1 @@ - +- [瀹炵幇涓涓埛鏁颁换鍔★紝闇瑕佹濊冨摢浜涚淮搴︼紵](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247508890&idx=1&sn=919b8a794eb4902d958ae13d1f424737&chksm=c1e05e16f697d700ee9f79e087279de6312222b8e45887d976a572b01599f1177b358ade265b&token=337310304&lang=zh_CN#rd) From 9670d5b8da9c69aa753a034245e1c065240e4791 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Wed, 29 May 2024 08:25:51 +0800 Subject: [PATCH 39/52] Update README.MD --- "\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" | 1 + 1 file changed, 1 insertion(+) diff --git "a/\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" "b/\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" index e38139f..10dc3ab 100644 --- "a/\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" +++ "b/\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" @@ -1 +1,2 @@ - [瀹炵幇涓涓埛鏁颁换鍔★紝闇瑕佹濊冨摢浜涚淮搴︼紵](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247508890&idx=1&sn=919b8a794eb4902d958ae13d1f424737&chksm=c1e05e16f697d700ee9f79e087279de6312222b8e45887d976a572b01599f1177b358ade265b&token=337310304&lang=zh_CN#rd) +- [鎵嬫妸鎵嬫暀浣犲啓璁捐鏂规](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247507937&idx=1&sn=33fd37f28675ce756e5d048b99254fcb&chksm=c1e0226df697ab7b4907fb2815c8dd2d195ea04c03a2f8fd0697c9a15a81fc639e5c5f7dab1b&token=337310304&lang=zh_CN#rd) From 04837de5a8a5e35fd32b0679bbb9e4d2d3e07d63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Wed, 29 May 2024 08:32:30 +0800 Subject: [PATCH 40/52] Update README.MD --- "\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" | 2 ++ 1 file changed, 2 insertions(+) diff --git "a/\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" "b/\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" index 10dc3ab..27d53c0 100644 --- "a/\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" +++ "b/\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" @@ -1,2 +1,4 @@ - [瀹炵幇涓涓埛鏁颁换鍔★紝闇瑕佹濊冨摢浜涚淮搴︼紵](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247508890&idx=1&sn=919b8a794eb4902d958ae13d1f424737&chksm=c1e05e16f697d700ee9f79e087279de6312222b8e45887d976a572b01599f1177b358ade265b&token=337310304&lang=zh_CN#rd) - [鎵嬫妸鎵嬫暀浣犲啓璁捐鏂规](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247507937&idx=1&sn=33fd37f28675ce756e5d048b99254fcb&chksm=c1e0226df697ab7b4907fb2815c8dd2d195ea04c03a2f8fd0697c9a15a81fc639e5c5f7dab1b&token=337310304&lang=zh_CN#rd) +- [绠鏄撶増锛屽熀浜嶫WT 瀹炵幇鐧诲綍璁よ瘉](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247508057&idx=1&sn=06b6fee69c63afbe7ebd2f81a3627341&chksm=c1e05dd5f697d4c32e38bcb58c2ecba8115ea7f94a17bc197bcb7b042a18ef07fef0f0e03878&token=337310304&lang=zh_CN#rd) + From 8b3d7e11446fb5ed0dd82dbca8205e460b231fb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Wed, 29 May 2024 08:33:23 +0800 Subject: [PATCH 41/52] Update README.MD --- "\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" | 1 + 1 file changed, 1 insertion(+) diff --git "a/\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" "b/\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" index 27d53c0..8965fd6 100644 --- "a/\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" +++ "b/\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" @@ -1,4 +1,5 @@ - [瀹炵幇涓涓埛鏁颁换鍔★紝闇瑕佹濊冨摢浜涚淮搴︼紵](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247508890&idx=1&sn=919b8a794eb4902d958ae13d1f424737&chksm=c1e05e16f697d700ee9f79e087279de6312222b8e45887d976a572b01599f1177b358ade265b&token=337310304&lang=zh_CN#rd) - [鎵嬫妸鎵嬫暀浣犲啓璁捐鏂规](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247507937&idx=1&sn=33fd37f28675ce756e5d048b99254fcb&chksm=c1e0226df697ab7b4907fb2815c8dd2d195ea04c03a2f8fd0697c9a15a81fc639e5c5f7dab1b&token=337310304&lang=zh_CN#rd) - [绠鏄撶増锛屽熀浜嶫WT 瀹炵幇鐧诲綍璁よ瘉](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247508057&idx=1&sn=06b6fee69c63afbe7ebd2f81a3627341&chksm=c1e05dd5f697d4c32e38bcb58c2ecba8115ea7f94a17bc197bcb7b042a18ef07fef0f0e03878&token=337310304&lang=zh_CN#rd) +- [楂樺苟鍙戠郴缁熻璁$殑15涓缓璁甝(https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247508062&idx=1&sn=71e9647479ea71e8660d6ba48616c122&chksm=c1e05dd2f697d4c45ffd09e07fd40770e3d11591fa2b53161cd38da908cd55e41a38d5192605&token=337310304&lang=zh_CN#rd) From 76d9cdf4ce60e66d89a210cd9c2a12dd56dd5792 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Wed, 29 May 2024 08:35:36 +0800 Subject: [PATCH 42/52] Update README.MD --- "\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" | 2 ++ 1 file changed, 2 insertions(+) diff --git "a/\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" "b/\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" index 8965fd6..70a1b3a 100644 --- "a/\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" +++ "b/\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" @@ -2,4 +2,6 @@ - [鎵嬫妸鎵嬫暀浣犲啓璁捐鏂规](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247507937&idx=1&sn=33fd37f28675ce756e5d048b99254fcb&chksm=c1e0226df697ab7b4907fb2815c8dd2d195ea04c03a2f8fd0697c9a15a81fc639e5c5f7dab1b&token=337310304&lang=zh_CN#rd) - [绠鏄撶増锛屽熀浜嶫WT 瀹炵幇鐧诲綍璁よ瘉](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247508057&idx=1&sn=06b6fee69c63afbe7ebd2f81a3627341&chksm=c1e05dd5f697d4c32e38bcb58c2ecba8115ea7f94a17bc197bcb7b042a18ef07fef0f0e03878&token=337310304&lang=zh_CN#rd) - [楂樺苟鍙戠郴缁熻璁$殑15涓缓璁甝(https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247508062&idx=1&sn=71e9647479ea71e8660d6ba48616c122&chksm=c1e05dd2f697d4c45ffd09e07fd40770e3d11591fa2b53161cd38da908cd55e41a38d5192605&token=337310304&lang=zh_CN#rd) +- [闈㈣瘯蹇呭锛氳亰鑱婂垎甯冨紡閿佺殑澶氱瀹炵幇锛乚(https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247506434&idx=1&sn=c6ae1ec19558626897295bbe41304b62&chksm=c1e0278ef697ae989b14f4746d1049be976d1d5744e4f9c7ec6e17d006f206edcc1c47a3e862&token=337310304&lang=zh_CN#rd) + From 8987b8a933e624d12601b03ef7ea4ed0dd033d67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Thu, 30 May 2024 08:21:54 +0800 Subject: [PATCH 43/52] Update README.MD --- "\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" | 2 ++ 1 file changed, 2 insertions(+) diff --git "a/\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" "b/\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" index 70a1b3a..e986b15 100644 --- "a/\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" +++ "b/\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" @@ -3,5 +3,7 @@ - [绠鏄撶増锛屽熀浜嶫WT 瀹炵幇鐧诲綍璁よ瘉](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247508057&idx=1&sn=06b6fee69c63afbe7ebd2f81a3627341&chksm=c1e05dd5f697d4c32e38bcb58c2ecba8115ea7f94a17bc197bcb7b042a18ef07fef0f0e03878&token=337310304&lang=zh_CN#rd) - [楂樺苟鍙戠郴缁熻璁$殑15涓缓璁甝(https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247508062&idx=1&sn=71e9647479ea71e8660d6ba48616c122&chksm=c1e05dd2f697d4c45ffd09e07fd40770e3d11591fa2b53161cd38da908cd55e41a38d5192605&token=337310304&lang=zh_CN#rd) - [闈㈣瘯蹇呭锛氳亰鑱婂垎甯冨紡閿佺殑澶氱瀹炵幇锛乚(https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247506434&idx=1&sn=c6ae1ec19558626897295bbe41304b62&chksm=c1e0278ef697ae989b14f4746d1049be976d1d5744e4f9c7ec6e17d006f206edcc1c47a3e862&token=337310304&lang=zh_CN#rd) +- [骞跺彂鐜涓嬶紝鍏堟搷浣滄暟鎹簱杩樻槸鍏堟搷浣滅紦瀛橈紵](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247508208&idx=1&sn=ac92523e33b478ad83560471338742f4&chksm=c1e05d7cf697d46aba95dc6661a8acbea0c894e44a793d054648b552a73b404aa3344d8a4826&token=337310304&lang=zh_CN#rd) + From 5ef506199d2e514207aad873870e5832f1798730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Thu, 30 May 2024 08:25:21 +0800 Subject: [PATCH 44/52] Update README.MD --- .../README.MD" | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git "a/\347\224\237\344\272\247\351\227\256\351\242\230\345\210\206\346\236\220/README.MD" "b/\347\224\237\344\272\247\351\227\256\351\242\230\345\210\206\346\236\220/README.MD" index 15772be..9d21f55 100644 --- "a/\347\224\237\344\272\247\351\227\256\351\242\230\345\210\206\346\236\220/README.MD" +++ "b/\347\224\237\344\272\247\351\227\256\351\242\230\345\210\206\346\236\220/README.MD" @@ -5,4 +5,5 @@ - [鎵嬫妸鎵嬫暀浣犲垎鏋怣ysql姝婚攣闂](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487979&idx=1&sn=588c83d77a8851f3b3c18cd68ed9c454&chksm=cf21cec2f85647d4a77cc239ae9a4cfd31bb8832be3d98540a08ea8b4a1f46b38cf736210a02&token=1495321435&lang=zh_CN&scene=21#wechat_redirect) - [绾跨▼姹犺繍鐢ㄤ笉褰撶殑涓娆$嚎涓婁簨鏁匽(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487992&idx=1&sn=733335f2f69d743712915abc99f83b1d&chksm=cf21ced1f85647c7ab8c5d8bc4e8206b04acb5fd4feb94b8d088a782ed458b82aab69dba82aa&token=1990771297&lang=zh_CN#rd) - [鐩樼偣MySQL鎱㈡煡璇㈢殑12涓師鍥燷(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499624&idx=1&sn=561b9cb7fe831ca7cb2d9fd65691e85e&chksm=cf222041f855a957ac50c0a53baaec6d26be32427259b2974450620f33a8c834419fe535e83d&token=1990771297&lang=zh_CN#rd) -- [绾跨▼姹犲浣曠洃鎺э紝鎵嶈兘甯姪寮鍙戣呭揩閫熷畾浣嶇嚎涓婇敊璇紵](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497444&idx=1&sn=1b2cc8b4685413149e46c814e468c6e6&chksm=cf2229cdf855a0db5f2da881d27c69f11c69480552985baa2a08cbe4d5a48bad7fb31a78dd5a&token=1990771297&lang=zh_CN#rd) \ No newline at end of file +- [绾跨▼姹犲浣曠洃鎺э紝鎵嶈兘甯姪寮鍙戣呭揩閫熷畾浣嶇嚎涓婇敊璇紵](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497444&idx=1&sn=1b2cc8b4685413149e46c814e468c6e6&chksm=cf2229cdf855a0db5f2da881d27c69f11c69480552985baa2a08cbe4d5a48bad7fb31a78dd5a&token=1990771297&lang=zh_CN#rd) +- [鏁版嵁搴撴閿佹帓鏌ユ濊矾鍒嗕韩](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247507770&idx=1&sn=b84b20aca057b34d511a501ff91941b5&chksm=c1e022b6f697aba05248128cb82f93aed341b1cc80e6d568c7150a4ffa6775692c7c9fa423a3&token=337310304&lang=zh_CN#rd) From 69abd3c8599a75e1feabbf349355c813ae4f9d6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Thu, 30 May 2024 08:27:39 +0800 Subject: [PATCH 45/52] Create README.md --- .../README.md" | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 "Mysql\345\237\272\347\241\200\345\255\246\344\271\240/README.md" diff --git "a/Mysql\345\237\272\347\241\200\345\255\246\344\271\240/README.md" "b/Mysql\345\237\272\347\241\200\345\255\246\344\271\240/README.md" new file mode 100644 index 0000000..d3eee8f --- /dev/null +++ "b/Mysql\345\237\272\347\241\200\345\255\246\344\271\240/README.md" @@ -0,0 +1,2 @@ +- [闈㈣瘯蹇呭锛氳亰鑱婂垎甯冨紡閿佺殑澶氱瀹炵幇锛乚(https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247506434&idx=1&sn=c6ae1ec19558626897295bbe41304b62&chksm=c1e0278ef697ae989b14f4746d1049be976d1d5744e4f9c7ec6e17d006f206edcc1c47a3e862&token=337310304&lang=zh_CN#rd) +- [骞跺彂鐜涓嬶紝鍏堟搷浣滄暟鎹簱杩樻槸鍏堟搷浣滅紦瀛橈紵](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247508208&idx=1&sn=ac92523e33b478ad83560471338742f4&chksm=c1e05d7cf697d46aba95dc6661a8acbea0c894e44a793d054648b552a73b404aa3344d8a4826&token=337310304&lang=zh_CN#rd) From ee23c93ece67df1feff7094c8c9a93c123fae1ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Thu, 30 May 2024 08:28:13 +0800 Subject: [PATCH 46/52] Update README.md --- .../README.md" | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git "a/Mysql\345\237\272\347\241\200\345\255\246\344\271\240/README.md" "b/Mysql\345\237\272\347\241\200\345\255\246\344\271\240/README.md" index d3eee8f..0ae9a4e 100644 --- "a/Mysql\345\237\272\347\241\200\345\255\246\344\271\240/README.md" +++ "b/Mysql\345\237\272\347\241\200\345\255\246\344\271\240/README.md" @@ -1,2 +1 @@ -- [闈㈣瘯蹇呭锛氳亰鑱婂垎甯冨紡閿佺殑澶氱瀹炵幇锛乚(https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247506434&idx=1&sn=c6ae1ec19558626897295bbe41304b62&chksm=c1e0278ef697ae989b14f4746d1049be976d1d5744e4f9c7ec6e17d006f206edcc1c47a3e862&token=337310304&lang=zh_CN#rd) -- [骞跺彂鐜涓嬶紝鍏堟搷浣滄暟鎹簱杩樻槸鍏堟搷浣滅紦瀛橈紵](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247508208&idx=1&sn=ac92523e33b478ad83560471338742f4&chksm=c1e05d7cf697d46aba95dc6661a8acbea0c894e44a793d054648b552a73b404aa3344d8a4826&token=337310304&lang=zh_CN#rd) +- [鑱婅亰select for update鍒板簳鍔犱簡浠涔堥攣](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247506728&idx=1&sn=5526ee3984e971d4c3b251c2ad76d658&chksm=c1e026a4f697afb28224d5ce0ecca7432879b357cd6433834c66d94c72a1935ba13e2e3e274e&token=337310304&lang=zh_CN#rd) From 20cc761fb304d23de53a5931a8cb341eed35a337 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Thu, 30 May 2024 08:29:45 +0800 Subject: [PATCH 47/52] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 68aacb1..54d00a0 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ - [绋嬪簭鍛樺繀澶囧熀纭锛氬浣曞畨鍏ㄤ紶杈撳瓨鍌ㄧ敤鎴峰瘑鐮侊紵](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488117&idx=1&sn=5d3d0eda0ed45f3f576e211de31ca3a9&chksm=cf21cd5cf856444af1407a94a2abf445265ca7c5f5855cfa1c223cb209e99040c7889621f231&token=162724582&lang=zh_CN&scene=21#wechat_redirect) - [涓娆′唬鐮佷紭鍖栧疄璺碉紝鐢ㄤ簡妯℃澘鏂规硶+绛栫暐+宸ュ巶鏂规硶妯″紡](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488061&idx=1&sn=1d9ab7954b03521ab81ecf033c0e5e50&chksm=cf21cd14f8564402b213f0ef908bbdb0e12fed4b281c5803b8e539cacb1551654194becfb7d6&token=162724582&lang=zh_CN&scene=21#wechat_redirect) - [淇濊瘉鎺ュ彛鏁版嵁瀹夊叏鐨10绉嶆柟妗圿(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247500285&idx=1&sn=7d0723f25d46e858859cfd79acb6fb9d&chksm=cf221ed4f85597c2093f81baa5fdedc65817bf2d23a7951236836b0f54c2335695cbed61cd13&token=1990771297&lang=zh_CN#rd) +- [瀹炴垬鎬荤粨锛18绉嶆帴鍙d紭鍖栨柟妗堢殑鎬荤粨](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247506674&idx=1&sn=8b2914d9aafa334029495b029b69d0b6&chksm=c1e0277ef697ae68e8c2bffe4bd7d9849be3165ef1a20286538f6a7569a6ba0879d517d55b87&token=337310304&lang=zh_CN#rd) ## 绂忓埄 500+椤靛師鍒涢潰璇曢 From 4a6a3f14c718ae0a49b5b1806ec05c745461aa31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Thu, 30 May 2024 08:30:42 +0800 Subject: [PATCH 48/52] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 54d00a0..33db52b 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ - [涓娆′唬鐮佷紭鍖栧疄璺碉紝鐢ㄤ簡妯℃澘鏂规硶+绛栫暐+宸ュ巶鏂规硶妯″紡](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488061&idx=1&sn=1d9ab7954b03521ab81ecf033c0e5e50&chksm=cf21cd14f8564402b213f0ef908bbdb0e12fed4b281c5803b8e539cacb1551654194becfb7d6&token=162724582&lang=zh_CN&scene=21#wechat_redirect) - [淇濊瘉鎺ュ彛鏁版嵁瀹夊叏鐨10绉嶆柟妗圿(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247500285&idx=1&sn=7d0723f25d46e858859cfd79acb6fb9d&chksm=cf221ed4f85597c2093f81baa5fdedc65817bf2d23a7951236836b0f54c2335695cbed61cd13&token=1990771297&lang=zh_CN#rd) - [瀹炴垬鎬荤粨锛18绉嶆帴鍙d紭鍖栨柟妗堢殑鎬荤粨](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247506674&idx=1&sn=8b2914d9aafa334029495b029b69d0b6&chksm=c1e0277ef697ae68e8c2bffe4bd7d9849be3165ef1a20286538f6a7569a6ba0879d517d55b87&token=337310304&lang=zh_CN#rd) +- [鑱婅亰宸ヤ綔涓父鐢ㄧ殑Lambda琛ㄨ揪寮廬(https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247506654&idx=1&sn=4835e9f486e643765d4ad3b3fc93e079&chksm=c1e02752f697ae442f62fc122d7604f4b01979f6d1665df414bb499fd8ba211335ebc503c368&token=337310304&lang=zh_CN#rd) ## 绂忓埄 500+椤靛師鍒涢潰璇曢 From 041003dfa55172cb7adadf7731dd130f7419792c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Thu, 30 May 2024 08:31:49 +0800 Subject: [PATCH 49/52] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 33db52b..42d5e5d 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ - [淇濊瘉鎺ュ彛鏁版嵁瀹夊叏鐨10绉嶆柟妗圿(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247500285&idx=1&sn=7d0723f25d46e858859cfd79acb6fb9d&chksm=cf221ed4f85597c2093f81baa5fdedc65817bf2d23a7951236836b0f54c2335695cbed61cd13&token=1990771297&lang=zh_CN#rd) - [瀹炴垬鎬荤粨锛18绉嶆帴鍙d紭鍖栨柟妗堢殑鎬荤粨](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247506674&idx=1&sn=8b2914d9aafa334029495b029b69d0b6&chksm=c1e0277ef697ae68e8c2bffe4bd7d9849be3165ef1a20286538f6a7569a6ba0879d517d55b87&token=337310304&lang=zh_CN#rd) - [鑱婅亰宸ヤ綔涓父鐢ㄧ殑Lambda琛ㄨ揪寮廬(https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247506654&idx=1&sn=4835e9f486e643765d4ad3b3fc93e079&chksm=c1e02752f697ae442f62fc122d7604f4b01979f6d1665df414bb499fd8ba211335ebc503c368&token=337310304&lang=zh_CN#rd) +- [21涓狹ySQL琛ㄨ璁$殑缁忛獙鍑嗗垯](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247506621&idx=1&sn=afca898cb461827054d706a92f9b9250&chksm=c1e02731f697ae27a83e5637ee2184d1e26e5090caeaa58121d3cf5afab7d4d5832cac6d171a&token=337310304&lang=zh_CN#rd) ## 绂忓埄 500+椤靛師鍒涢潰璇曢 From a0a2cfb1858dce4bd4869829efd29a6c58fa9cc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Thu, 30 May 2024 08:34:19 +0800 Subject: [PATCH 50/52] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 42d5e5d..abf80d6 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ - [瀹炴垬鎬荤粨锛18绉嶆帴鍙d紭鍖栨柟妗堢殑鎬荤粨](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247506674&idx=1&sn=8b2914d9aafa334029495b029b69d0b6&chksm=c1e0277ef697ae68e8c2bffe4bd7d9849be3165ef1a20286538f6a7569a6ba0879d517d55b87&token=337310304&lang=zh_CN#rd) - [鑱婅亰宸ヤ綔涓父鐢ㄧ殑Lambda琛ㄨ揪寮廬(https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247506654&idx=1&sn=4835e9f486e643765d4ad3b3fc93e079&chksm=c1e02752f697ae442f62fc122d7604f4b01979f6d1665df414bb499fd8ba211335ebc503c368&token=337310304&lang=zh_CN#rd) - [21涓狹ySQL琛ㄨ璁$殑缁忛獙鍑嗗垯](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247506621&idx=1&sn=afca898cb461827054d706a92f9b9250&chksm=c1e02731f697ae27a83e5637ee2184d1e26e5090caeaa58121d3cf5afab7d4d5832cac6d171a&token=337310304&lang=zh_CN#rd) +- [绋嬪簭鍛樺繀澶囧熀纭锛氬浣曞畨鍏ㄤ紶杈撳瓨鍌ㄧ敤鎴峰瘑鐮侊紵](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247506023&idx=1&sn=b96dde436c1c9fe4bda745ca5ca1b170&source=41#wechat_redirect) ## 绂忓埄 500+椤靛師鍒涢潰璇曢 From bff37f7eb2f9c5ba90eddcf14f524d2f2a280a56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Sat, 1 Jun 2024 17:23:09 +0800 Subject: [PATCH 51/52] =?UTF-8?q?=E6=AD=BB=E9=94=81=E6=80=9D=E8=B7=AF?= =?UTF-8?q?=E5=88=86=E4=BA=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../README.md" | 1 + 1 file changed, 1 insertion(+) diff --git "a/Mysql\345\237\272\347\241\200\345\255\246\344\271\240/README.md" "b/Mysql\345\237\272\347\241\200\345\255\246\344\271\240/README.md" index 0ae9a4e..f335927 100644 --- "a/Mysql\345\237\272\347\241\200\345\255\246\344\271\240/README.md" +++ "b/Mysql\345\237\272\347\241\200\345\255\246\344\271\240/README.md" @@ -1 +1,2 @@ - [鑱婅亰select for update鍒板簳鍔犱簡浠涔堥攣](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247506728&idx=1&sn=5526ee3984e971d4c3b251c2ad76d658&chksm=c1e026a4f697afb28224d5ce0ecca7432879b357cd6433834c66d94c72a1935ba13e2e3e274e&token=337310304&lang=zh_CN#rd) +- [鏁版嵁搴撴閿佹帓鏌ユ濊矾鍒嗕韩](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247507770&idx=1&sn=b84b20aca057b34d511a501ff91941b5&chksm=c1e022b6f697aba05248128cb82f93aed341b1cc80e6d568c7150a4ffa6775692c7c9fa423a3&token=1822874069&lang=zh_CN#rd) From c46280c44013c05ee50a6c04cfcbdabaef943c39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8D=A1=E7=94=B0=E8=9E=BA=E7=9A=84=E5=B0=8F=E7=94=B7?= =?UTF-8?q?=E5=AD=A9?= <327658337@qq.com> Date: Sun, 15 Dec 2024 10:59:31 +0800 Subject: [PATCH 52/52] =?UTF-8?q?=E6=96=B0=E6=96=87=E7=AB=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index abf80d6..7018310 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,8 @@ ## 宸ヤ綔鎬荤粨 +- [鐩樼偣鏁版嵁搴撲富浠庡欢杩熺殑9涓師鍥犱互鍙婅В鍐虫柟妗圿(https://mp.weixin.qq.com/s/aT7YjsTrM_dhDbddr8TSjg?token=528541177&lang=zh_CN) +- [瀹炴垬椤圭洰锛屾槸濡備綍淇濊瘉缂撳瓨璺熸暟鎹簱鏁版嵁涓鑷存х殑锛焆(https://mp.weixin.qq.com/s/UVHMeFDO4NYTnSwHZc9f1A?token=528541177&lang=zh_CN) - [宸ヤ綔鎬荤粨锛佹棩蹇楁墦鍗扮殑15涓缓璁甝(https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247494838&idx=1&sn=cdb15fd346bddf3f8c1c99f0efbd67d8&chksm=cf22339ff855ba891616c79d4f4855e228e34a9fb45088d7acbe421ad511b8d090a90f5b019f&token=162724582&lang=zh_CN&scene=21#wechat_redirect) - [25绉嶄唬鐮佸潖鍛抽亾鎬荤粨+浼樺寲绀轰緥](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490148&idx=1&sn=00a181bf74313f751b3ea15ebc303545&chksm=cf21c54df8564c5bc5b4600fce46619f175f7ae557956f449629c470a08e20580feef4ea8d53&token=162724582&lang=zh_CN&scene=21#wechat_redirect) - [鑱婅亰鏃ュ父寮鍙戜腑锛屽浣曞噺灏慴ug鍛紵](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490662&idx=1&sn=d38a090611af7f64ee3c6a31331d5228&chksm=cf21c34ff8564a59e505e6edf3065a0fc506c6d2c96f492c8d8873cd46dedbe0704e43cb9c2e&token=1990771297&lang=zh_CN#rd)