文章列表

JVM自定义类加载器在代码扩展性的实践

作者:微信小助手

<section style="font-size: 15px;line-height: 1.9;letter-spacing: 0.75px;box-sizing: border-box;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <blockquote class="js_blockquote_wrap" data-type="2" data-url="" data-author-name="" data-content-utf8-length="26" data-source-title=""> <section class="js_blockquote_digest"> <section> 作者:vivo互联网服务器团队-Wang Fei </section> </section> </blockquote> <p><br></p> </section> <section style="margin-top: 10px;margin-bottom: 10px;text-align: center;box-sizing: border-box;" powered-by="xiumi.us"> <section style="padding: 3px;display: inline-block;border-bottom: 1px solid rgb(65, 94, 255);font-size: 17px;color: rgb(65, 94, 255);box-sizing: border-box;"> <p style="box-sizing: border-box;">一、背景</p> </section> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">名单管理系统是手机上各个模块将需要管控的应用配置到文件中,然后下发到手机上进行应用管控的系统,比如各个应用的耗电量管控;各个模块的管控应用文件考虑到安全问题,有自己的不同的加密方式,按照以往的经验,我们可以利用模板方法+工厂模式来根据模块的类型来获取到不同的加密方法。代码类层次结构示意如下:</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-backh="248" data-backw="578" data-ratio="0.4288107202680067" data-s="300,640" src="/upload/d0d2f8d98bdedbd1799806347fb0e2b1.png" data-type="png" data-w="597" style="width: 100%;height: auto;"></p> <p style="white-space: normal;box-sizing: border-box;"><br></p> <p style="white-space: normal;box-sizing: border-box;text-align: center;"><span style="font-size: 14px;color: rgb(136, 136, 136);">获取不同加密方法的类结构图</span></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">利用工厂模式和模板方法模式,在有新的加密方法时,我们可以通过添加新的handler来满足"对修改关闭,对扩展开放"的原则,但是这种方式不可避免的需要修改代码和需要重新发版本和上线。那么有没有更好的方式能够去解决这个问题,这里就是我们今天要重点讲的主题。</p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="margin-top: 10px;margin-bottom: 10px;text-align: center;box-sizing: border-box;" powered-by="xiumi.us"> <section style="padding: 3px;display: inline-block;border-bottom: 1px solid rgb(65, 94, 255);font-size: 17px;color: rgb(65, 94, 255);box-sizing: border-box;"> <p style="box-sizing: border-box;">二、类加载的时机</p> </section> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">&nbsp;一个类型从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期将会经历<strong>加载</strong> (Loading)、<strong>验证</strong>(Verification)、<strong>准备</strong>(Preparation)、<strong>解析</strong>(Resolution)、<strong>初始化</strong> (Initialization)、<strong>使用</strong>(Using)和<strong>卸载</strong>(Unloading)七个阶段,其中验证、准备、解析三个部分统称为连接(Linking)。这七个阶段的发生顺序如图1所示。</p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-backh="124" data-backw="578" data-ratio="0.21498054474708173" data-s="300,640" src="/upload/e834e422c6e75a4ed823023001b32f8c.png" data-type="png" data-w="1028" style="width: 100%;height: auto;"></p> <p style="white-space: normal;box-sizing: border-box;"><br></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">虽然classloader的加载过程有复杂的7步,但事实上除了加载之外的四步,其它都是由JVM虚拟机控制的,我们除了适应它的规范进行开发外,能够干预的空间并不多。而加载则是我们控制classloader实现特殊目的最重要的手段了。也是接下来我们介绍的重点了。</p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="margin-top: 10px;margin-bottom: 10px;text-align: center;box-sizing: border-box;" powered-by="xiumi.us"> <section style="padding: 3px;display: inline-block;border-bottom: 1px solid rgb(65, 94, 255);font-size: 17px;color: rgb(65, 94, 255);box-sizing: border-box;"> <p style="box-sizing: border-box;">三、加载</p> </section> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">“加载”(Loading)阶段是整个“类加载”(Class Loading)过程中的一个阶段。在加载阶段,Java虚拟机需要完成以下三件事情:</p> <p style="white-space: normal;box-sizing: border-box;"><br></p> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li><p style="white-space: normal;box-sizing: border-box;">通过一个类的全限定名来获取定义此类的二进制字节流。</p></li> <li><p style="white-space: normal;box-sizing: border-box;">将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。</p></li> <li><p style="white-space: normal;box-sizing: border-box;">在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。</p></li> </ul> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;">《Java虚拟机规范》对这三点没有进行特别具体的要求,从而留给虚拟机实现与Java应用的灵活度都是相当大的。例如“通过一个类的全限定名来获取定义此类的二进制字节流”这条规则,它并没有指明二 进制字节流必须得从某个Class文件中获取,确切地说是根本没有指明要从哪里获取、如何获取。比如我们可以从ZIP压缩包中读取、从网络中获取、运行时计算生成、由其他文件生成、从数据库中读取。也可以可以从加密文件中获取。</p> <p style="white-space: normal;box-sizing: border

记一次OOM问题排查!

作者:微信小助手

<p data-tool="mdnice编辑器" style="margin-bottom: 16px;padding-top: 8px;padding-bottom: 8px;color: rgb(0, 0, 0);text-align: left;white-space: normal;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif;font-size: 15px;text-size-adjust: auto;line-height: 1.75em;">今天给大家分享最近出现的OOM问题。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 16px;padding-top: 8px;padding-bottom: 8px;color: rgb(0, 0, 0);text-align: left;white-space: normal;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif;font-size: 15px;text-size-adjust: auto;line-height: 1.75em;">某一天早上,测试同学反馈测试环境的子系统服务一直超时,请求没有响应。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 16px;padding-top: 8px;padding-bottom: 8px;color: rgb(0, 0, 0);text-align: left;white-space: normal;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif;font-size: 15px;text-size-adjust: auto;line-height: 1.75em;">收到这个问题之后,我有点纳闷,最近这个系统也没有改动代码逻辑,怎么会突然报服务超时的问题。为避免影响测试进度,我赶紧登陆堡垒机查看日志,看看到底啥情况。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 16px;padding-top: 8px;padding-bottom: 8px;color: rgb(0, 0, 0);text-align: left;white-space: normal;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif;font-size: 15px;text-size-adjust: auto;line-height: 1.75em;">首先先看系统负载情况,使用<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">top</code>命令查看。发现其中某个Java进程cpu一直持续停留在100%左右。此系统不涉及大量运算的逻辑,猜测是死循环或者频繁gc引起的问题。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 16px;text-align: left;white-space: normal;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.30039525691699603" src="/upload/5877ad09dc174b89344133e13c3c23b4.png" data-type="png" data-w="759" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <p data-tool="mdnice编辑器" style="margin-bottom: 16px;padding-top: 8px;padding-bottom: 8px;color: rgb(0, 0, 0);text-align: left;white-space: normal;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif;font-size: 15px;text-size-adjust: auto;line-height: 1.75em;">查看系统日志发现,出现<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">java.lang.OutOfMemoryError: Metaspace</code>,很明显,元空间内存溢出了。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 16px;padding-top: 8px;padding-bottom: 8px;color: rgb(0, 0, 0);text-align: left;white-space: normal;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif;font-size: 15px;text-size-adjust: auto;line-height: 1.75em;">接着查看系统gc情况,使用以下命令查看。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-size: 16px;text-align: left;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="margin-bottom: -7px;display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/B2EfAOZfS1ju4Wr3E1RibhtR4LD3ZmGhIRepj8Az4PdYEjtSpQDX1UCYiaFMLD1SFj61ibRCWBS9Z3uKPyqj94CKbnsvz0juC4v/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 558px;border-radius: 5px;"></span><code style="padding: 15px 16px 16px;overflow-x: auto;color: rgb(171, 178, 191);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(40, 44, 52);border-radius: 5px;">jstat&nbsp;-gc&nbsp;<span style="color: rgb(209, 154, 102);line-height: 26px;">217</span>&nbsp;<span style="color: rgb(209, 154, 102);line-height: 26px;">1000</span><br></code></pre> <p data-tool="mdnice编辑器" style="margin-bottom: 16px;padding-top: 8px;padding-bottom: 8px;color: rgb(0, 0, 0);text-align: left;white-space: normal;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif;font-size: 15px;text-size-adjust: auto;line-height: 1.75em;">217为对应的Java进程号。参数<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">1000</code>表示每隔1000ms打印一次记录。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 16px;padding-top: 8px;padding-bottom: 8px;color: rgb(0, 0, 0);text-align: left;white-space: normal;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif;font-size: 15px;text-size-adjust: auto;line-height: 1.75em;">执行结果如下:</p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;"> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.4463917525773196" src="/upload/9a5aa51ba65b7b3e54d9a56092b635b0.png" data-type="png" data-w="970" style="display: block;margin-right: auto;margin-left: auto;" title=""> </figure> </section> <p data-tool="mdnice编辑器" style="margin: 0px 0px 16px;padding: 8px 0px;clear: both;min-height: 1em;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(0, 0, 0);font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif;font-size: 15px;text-size-adjust: auto;line-height: 1.75em;">果不其然,<code style="margin: 0px 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">full gc</code>从应用程序启动到采样时已经触发了几百次!这也是cpu一直100%的原因。<br></p> <p data-tool="mdnice编辑器" style="margin: 0px 0px 16px;padding: 8px 0px;clear: both;min-height: 1em;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(0, 0, 0);font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif;font-size: 15px;text-size-adjust: auto;line-height: 1.75em;">其中还有另一个参数 MC(元空间分配内存大小),已经接近设置的最大元空间大小(配置的<code style="margin: 0px 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">--XX:MaxMetaspaceSize=128m</code>)。</p> <blockquote data-tool="mdnice编辑器" style="margin: 1.2em 0px;padding: 10px 1em;border-left: 4px solid rgb(221, 221, 221);color: rgb(119, 119, 119);line-height: 1.6;font-size: 0.9em;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;border-top: none;border-right: none;border-bottom: none;overflow: auto;background: rgba(0, 0, 0, 0.05);quotes: none;"> <p style="margin: 0px;padding: 8px 0px;clear: both;min-height: 1em;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;white-space: normal;text-size-adjust: auto;font-size: 15px;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;line-height: 1.75em;">这里也简单介绍下元空间。</p> <p style="margin: 0px;padding: 8px 0px;clear: both;min-height: 1em;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;white-space: normal;text-size-adjust: auto;font-size: 15px;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;line-height: 1.75em;">元数据是jdk8里特有的数据结构,jdk7是叫永久代,到了jdk8永久代就废弃了,使用元空间替代。元空间被分配在本地内存中(非堆上),默认不限制内存使用,可以使用&nbsp;<code style="margin: 0px 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">MaxMetaspaceSize</code>&nbsp;指定最大值。</p> <p style="margin: 0px;padding: 8px 0px;clear: both;min-height: 1em;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;white-space: normal;text-size-adjust: auto;font-size: 15px;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;line-height: 1.75em;">元空间由两大部分组成</p> <ul class="list-paddingleft-1" style="margin: 8px 0px;padding: 0px 0px 0px 25px;box-sizing: border-box !important;width: 524.688px;max-width: 100%;overflow-wrap: break-word !important;color: black;"> <li style="margin: 0px;padding: 0px;clear: both;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;"> <section style="margin: 5px 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif;"> <code style="margin: 0px 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">Klass Metaspace</code>,用来存klass的,klass是class文件在jvm里的运行时数据结构。 </section></li> <li style="margin: 0px;padding: 0px;clear: both;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;"> <section style="margin: 5px 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif;"> <code style="margin: 0px 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">NoKlass Metaspac</code>e,专门来存klass相关的其他的内容,比如method,常量池等,这块内存是由多块内存组合起来的。 </section></li> </ul> <p style="margin: 0px;padding: 8px 0px;clear: both;min-height: 1em;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;white-space: normal;text-size-adjust: auto;font-size: 15px;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;line-height: 1.75em;">MC 就是<code style="margin: 0px 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">Klass Metaspace</code>以及<code style="margin: 0px 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">NoKlass Metaspace</code>两者总共分配的内存大小,单位是KB。上图中,MC已经接近元空间设置的上限值,也就是此时元空间内存已经不够用了,导致一直触发full gc。</p> </blockquote> <p data-tool="mdnice编辑器" style="margin: 0px 0px 16px;padding: 8px 0px;clear: both;min-height: 1em;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(0, 0, 0);font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif;font-size: 15px;text-size-adjust: auto;line-height: 1.75em;">然后就是dump内存进行分析,看看是什么原因导致的元空间内存溢出。使用命令<code style="margin: 0px 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">./jmap -dump:live,format=b,file=/xxx</code>&nbsp;导出内存heap到xxx位置(hprof格式),然后使用MAT工具进行分析。</p> <p data-tool="mdnice编辑器" style="margin: 0px 0px 16px;padding: 8px 0px;clear: both;min-height: 1em;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(0, 0, 0);font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif;font-size: 15px;text-size-adjust: auto;line-height: 1.75em;">将hprof文件导入MAT工具,打开内存泄漏分析(涉及公司内部源码,所以打了马赛克):</p> <figure data-tool="mdnice编辑器" style="margin: 10px 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.7048997772828508" src="/upload/12fa87c5a064d325f5a16be2b338ee63.png" data-type="png" data-w="898" style="margin: 0px auto;padding: 0px;max-width: 100%;height: auto !important;overflow-wrap: break-word !important;vertical-align: bottom;display: block;"> </figure> <p data-tool="mdnice编辑器" style="margin: 0px 0px 16px;padding: 8px 0px;clear: both;min-height: 1em;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(0, 0, 0);font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif;font-size: 15px;text-size-adjust: auto;line-height: 1.75em;">看到这个之后,就大概知道是什么问题了。因为最近公司内部在推广一个漏洞监控工具,需要在服务端部署agent程序,这个工具会收集、监控应用程序运行时函数执行、数据传输,可以识别常见的安全缺陷和漏洞。而打码的部分正是这个漏洞监控工具的应用包名,很可能是引入这个工具引起的问题!</p> <p data-tool="mdnice编辑器" style="margin: 0px 0px 16px;padding: 8px 0px;clear: both;min-height: 1em;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(0, 0, 0);font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif;font-size: 15px;text-size-adjust: auto;line-height: 1.75em;">进一步确认问题。打开Histogram:</p> <figure data-tool="mdnice编辑器" style="margin: 10px 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.41361256544502617" src="/upload/b2f3be76eee11230972091f43be289e3.png" data-type="png" data-w="764" style="margin: 0px auto;padding: 0px;max-width: 100%;height: auto !important;overflow-wrap: break-word !important;vertical-align: bottom;display: block;"> </figure> <blockquote data-tool="mdnice编辑器" style="margin: 1.2em 0px;padding: 10px 1em;border-left: 4px solid rgb(221, 221, 221);color: rgb(119, 119, 119);line-height: 1.6;font-size: 0.9em;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;border-top: none;border-right: none;border-bottom: none;overflow: auto;background: rgba(0, 0, 0, 0.05);quotes: none;"> <p style="margin: 0px;padding: 8px 0px;clear: both;min-height: 1em;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;white-space: normal;text-size-adjust: auto;font-size: 15px;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;line-height: 1.75em;">Shallow Heap 代表一个<strong style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: black;">对象结构自身</strong>所占用的内存大小,不包括其属性引用对象所占的内存。</p> <p style="margin: 0px;padding: 8px 0px;clear: both;min-height: 1em;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;white-space: normal;text-size-adjust: auto;font-size: 15px;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;line-height: 1.75em;">Retained Heap 是一个对象被 GC 回收后,可释放的内存大小,等于释放对象的 Retained Heap 中所有对象的 Shallow Heap 的和。</p> </blockquote> <p data-tool="mdnice编辑器" style="margin: 0px 0px 16px;padding: 8px 0px;clear: both;min-height: 1em;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(0, 0, 0);font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif;font-size: 15px;text-size-adjust: auto;line-height: 1.75em;">在Histogram视图中,选中其中一个类点击鼠标右键会弹出一个菜单,选择Merge shortest paths to GC Roots,查看当前对象到GC Root的路径,可以过滤一些类型的引用。</p> <figure data-tool="mdnice编辑器" style="margin: 10px 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.42780026990553305" src="/upload/c963f2a2288295e88a652431124889ef.png" data-type="png" data-w="741" style="margin: 0px auto;padding: 0px;max-width: 100%;height: auto !important;overflow-wrap: break-word !important;display: block;" title=""> </figure> <p data-tool="mdnice编辑器" style="margin: 0px 0px 16px;padding: 8px 0px;clear: both;min-height: 1em;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(0, 0, 0);font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif;font-size: 15px;text-size-adjust: auto;line-height: 1.75em;">结果如下:</p> <figure data-tool="mdnice编辑器" style="margin: 10px 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.1694736842105263" src="/upload/72211272765601d41d515cd0b34439e0.png" data-type="png" data-w="950" style="margin: 0px auto;padding: 0px;max-width: 100%;height: auto !important;overflow-wrap: break-word !important;vertical-align: bottom;display: block;"> </figure> <p data-tool="mdnice编辑器" style="margin: 0px 0px 16px;padding: 8px 0px;clear: both;min-height: 1em;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(0, 0, 0);font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif;font-size: 15px;text-size-adjust: auto;line-height: 1.75em;">占用内存空间最多的就是漏洞监控工具的类(包名打码了),也基本可以确定问题所在了。</p> <p data-tool="mdnice编辑器" style="margin: 0px 0px 16px;padding: 8px 0px;clear: both;min-height: 1em;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(0, 0, 0);font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif;font-size: 15px;text-size-adjust: auto;line-height: 1.75em;">最后把这个漏洞监控工具去掉之后,重新部署之后,就不会出现服务超时的问题了。</p> <p data-tool="mdnice编辑器" style="margin: 0px 0px 16px;padding: 8px 0px;clear: both;min-height: 1em;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(0, 0, 0);font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif;font-size: 15px;text-size-adjust: auto;line-height: 1.75em;">以上就是本期OOM问题分析的整个过程~</p>

七个 yyds 的高频 MySQL 面试题

作者:微信小助手

<h3 style="margin-top: 1.2em;margin-bottom: 1em;outline: 0px;font-weight: bold;font-size: 20px;white-space: normal;color: rgb(53, 179, 120);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);visibility: visible;">MySQL 索引使用什么数据结构?理由?</h3> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);visibility: visible;">答:使用B+树。</p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);visibility: visible;">这个问题,可以在脑子里面先思考一下,如果让你来设计数据库的索引,你会怎么设计?</p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);visibility: visible;">我们还是用Why?What?How?三步法来看这个问题。</p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);visibility: visible;">为什么会需要索引?索引是什么?索引怎么用的?</p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);visibility: visible;">再思考为什么需要B+树?B+树是什么?B+树怎么用?</p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);visibility: visible;">答:大部分程序主要的功能都是对数据的处理,写入、查询、转化、输出。最形象的比喻就是树和内容和目录的关系,目录就是索引,我们根据目录能快速拿到想要内容的页码。</p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><img class="rich_pages wxw-img" data-backh="413" data-backw="570" data-ratio="0.725" src="/upload/6dc554c0e2436a7f40ac4c7248d462f0.png" data-type="png" data-w="1080" style="outline: 0px;width: 669px;box-sizing: border-box !important;visibility: visible !important;"></p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">为什么是B+树,有这个几个理由:</p> <ul class="list-paddingleft-1" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;outline: 0px;white-space: normal;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"> <li style="outline: 0px;"> <section style="margin-top: 10px;margin-bottom: 10px;outline: 0px;line-height: 26px;color: rgb(1, 1, 1);"> 如果是用AVL平衡二叉树,树高度太高,索引查询需要访问磁盘,每次访问以节点为单位进行磁盘I/O ,需要尽量减少数据读取的I/O操作,所以树高度一定不能太高,存储千万级别的数据,实践中 B+ 树的高度也就 4或者5。 </section></li> <li style="outline: 0px;color: rgb(0, 0, 0);"> <section style="margin-top: 10px;margin-bottom: 10px;outline: 0px;line-height: 26px;color: rgb(1, 1, 1);"> <a target="_blank" href="https://mp.weixin.qq.com/s?__biz=Mzg2MDYzODI5Nw==&amp;mid=2247502768&amp;idx=3&amp;sn=13e931f2c13ab493d004456dc836625d&amp;scene=21#wechat_redirect" textvalue="B+树经常用来比较的是B树,B+树相比B树有个很大的特点是B+树所有关键字都出现在叶子结点的链表中(稠密索引),且链表中的关键字恰好是有序的,对于范围查找,比如15~50,B树需要中序遍历二叉树,但是B+树直接在叶子节点顺序访问就可以了。最近整理一份MySQL面试学习资料,里面收录了高频面试题目及答案,打算跳槽的小伙伴不要错过,点击领取吧!" linktype="text" imgurl="" imgdata="null" tab="innerlink" style="color: rgb(0, 0, 0);" data-linktype="2"><span style="color: rgb(0, 0, 0);">B+树经常用来比较的是B树,B+树相比B树有个很大的特点是B+树所有关键字都出现在叶子结点的链表中(稠密索引),且链表中的关键字恰好是有序的,对于范围查找,比如15~50,B树需要中序遍历二叉树,但是B+树直接在叶子节点顺序访问就可以了。最近整理一份MySQL面试学习资料,里面收录了高频面试题目及答案,打算跳槽的小伙伴不要错过,点击领取吧!</span></a> </section></li> </ul> <h3 style="margin-top: 1.2em;margin-bottom: 1em;outline: 0px;font-weight: bold;font-size: 20px;white-space: normal;color: rgb(53, 179, 120);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">什么是最左匹配原则?</h3> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">首先说明一点:</p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">最左前缀匹配原则:在MySQL建立联合索引时会遵守最左前缀匹配原则,即最左优先,在检索数据时从联合索引的最左边开始匹配。</p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">打个比方,我们有张student 表,我们根据学院编号+班级建立了一个联合索引 index_magor_class(magor,class), 这个索引由二个字段组成。</p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">索引的底层是一颗B+树,那么联合索引的底层也就是一颗B+树,只不过联合索引的B+树节点中存储的是逗号分隔的多个值。</p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">举例:创建一个 index_magor_class(magor,class) 的联合索引,那么它的索引树就是下图的样子。</p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">它是先根据magor排序,再根据class排序,如果索引后面还有字段,继续以此类推。</p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><img class="rich_pages wxw-img" data-backh="266" data-backw="570" data-ratio="0.46710526315789475" src="/upload/fa3e17171892e72444b6203089520196.png" data-type="png" data-w="912" style="outline: 0px;width: 669px;box-sizing: border-box !important;visibility: visible !important;"></p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">我们查询的where 条件如果只传入了班级,是走不到联合索引的,但是如果只传了学院编号,是可能会走到联合索引的。(为什么说可能,MYSQL的执行计划和查询的实际执行过程并不完全吻合,比如你数据库数据量很少,可能直接全量遍历速度更快,就不走索引了)</p> <h3 style="margin-top: 1.2em;margin-bottom: 1em;outline: 0px;font-weight: bold;font-size: 20px;white-space: normal;color: rgb(53, 179, 120);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">在建表的时候如何设计索引的?有没有做过索引优化 ?</h3> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">1、利用覆盖索引来进行查询操作,来避免回表操作。</p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">说明:如果一本书需要知道第11章是什么标题,会翻开第11章对应的那一页吗?目录浏览一下就好,这个目录就是起到覆盖索引的作用。</p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">什么意思,比如你主键索引是学号,你写select 语句的时候,直接select 学号 from table 就可以了,不用select 其他字段,一般除非非常有必要,尽量按需select 字段,少用或不用 select, 不然还需要回表。</p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">这里我解释一下回表,比如我们表主键索引是学号,另外我们还根据手机号也建了索引,如果我们where 条件是手机号,分二种情况:</p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">正例:IDB能够建立索引的种类分为【主键索引、唯一索引、普通索引】,而覆盖索引是一种查询的一种效果,用explain的结果,extra列会出现:using index.</p> <ul class="list-paddingleft-1" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;outline: 0px;white-space: normal;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"> <li style="outline: 0px;"> <section style="margin-top: 10px;margin-bottom: 10px;outline: 0px;line-height: 26px;color: rgb(1, 1, 1);"> 如果我们select 获取的字段是学号,直接在手机号的索引表就能获取到数据,不需要回表; </section></li> <li style="outline: 0px;"> <section style="margin-top: 10px;margin-bottom: 10px;outline: 0px;line-height: 26px;color: rgb(1, 1, 1);"> 如果我们select 的时候还有其他字段,我们查询的时候流程是这样的,先根据手机号查到学号,再根据学号去主键索引表查询数据,这个过程叫回表。 </section></li> </ul> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">2、业务上具有唯一特性的字段,即使是组合字段,也建议建成唯一索引。说明:不要以为唯一索引影响了insert速度,这个速度损耗可以忽略,但提高查找速度是明显的;另外,即使在应用层做了非常完善的校验和控制,只要没有唯一索引,根据墨菲定律,必然有脏数据产生。</p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">3、超过三个表禁止join。需要join的字段,数据类型保持绝对一致;多表关联查询时,保证被关联的字段需要有索引。说明:即使双表join也要注意表索引、SQL性能。</p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">4、在varchar字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据实际文本区分度决定索引长度。说明:索引的长度与区分度是一对矛盾体,一般对字符串类型数据,长度为20的索引,区分度会高达90%以上,可以使用count(distinct left(列名, 索引长度))/count(*)的区分度来确定。</p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">5、页面搜索严禁左模糊或者全模糊,如果需要请走搜索引擎来解决。说明:索引文件具有B-Tree的最左前缀匹配特性,如果左边的值未确定,那么无法使用此索引。</p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">6、SQL性能优化的目标:至少要达到 range 级别,要求是ref级别,如果可以是const最好。说明:</p> <ul class="list-paddingleft-1" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;outline: 0px;white-space: normal;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"> <li style="outline: 0px;color: rgb(0, 0, 0);"> <section style="margin-top: 10px;margin-bottom: 10px;outline: 0px;line-height: 26px;color: rgb(1, 1, 1);"> <a target="_blank" href="https://mp.weixin.qq.com/s?__biz=Mzg2MDYzODI5Nw==&amp;mid=2247502768&amp;idx=3&amp;sn=13e931f2c13ab493d004456dc836625d&amp;scene=21#wechat_redirect" textvalue="1)const 单表中最多只有一个匹配行(主键或者唯一索引),在优化阶段即可读取到数据。最近整理一份MySQL面试学习资料,里面收录了高频面试题目及答案,打算跳槽的小伙伴不要错过,点击领取吧!" linktype="text" imgurl="" imgdata="null" tab="innerlink" style="color: rgb(0, 0, 0);" data-linktype="2"><span style="color: rgb(0, 0, 0);">1)const 单表中最多只有一个匹配行(主键或者唯一索引),在优化阶段即可读取到数据。最近整理一份MySQL面试学习资料,里面收录了高频面试题目及答案,打算跳槽的小伙伴不要错过,点击领取吧!</span></a> </section></li> <li style="outline: 0px;"> <section style="margin-top: 10px;margin-bottom: 10px;outline: 0px;line-height: 26px;color: rgb(1, 1, 1);"> 2)ref 指的是使用普通的索引。(normal index) </section></li> <li style="outline: 0px;"> <section style="margin-top: 10px;margin-bottom: 10px;outline: 0px;line-height: 26px;color: rgb(1, 1, 1);"> 3)range 对索引进行范围检索。反例:explain表的结果,type=index,索引物理文件全扫描,速度非常慢,这个index级别比较range还低,与全表扫描是小巫见大巫。 </section></li> </ul> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">7、建组合索引的时候,区分度最高的在最左边。正例:如果where a=? and b=? ,a列的几乎接近于唯一值,那么只需要单建idx_a索引即可。说明:存在非等号和等号混合判断条件时,在建索引时,请把等号条件的列前置。如:where c&gt;? and d=? 那么即使c的区分度更高,也必须把d放在索引的最前列,即建立组合索引idx_d_c。</p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">8、防止因字段类型不同造成的隐式转换,导致索引失效。</p> <h3 style="margin-top: 1.2em;margin-bottom: 1em;outline: 0px;font-weight: bold;font-size: 20px;white-space: normal;color: rgb(53, 179, 120);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">MyBatis用过吗? 一二级缓存清楚吗?</h3> <ul class="list-paddingleft-1" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;outline: 0px;white-space: normal;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"> <li style="outline: 0px;"> <section style="margin-top: 10px;margin-bottom: 10px;outline: 0px;line-height: 26px;color: rgb(1, 1, 1);"> 一级缓存 Mybatis的一级缓存是指SQLSession,一级缓存的作用域是SQlSession, Mabits默认开启一级缓存。在同一个SqlSession中,执行相同的SQL查询时;第一次会去查询数据库,并写在缓存中,第二次会直接从缓存中取。当执行SQL时候两次查询中间发生了增删改的操作,则SQLSession的缓存会被清空。每次查询会先去缓存中找,如果找不到,再去数据库查询,然后把结果写到缓存中。Mybatis的内部缓存使用一个HashMap,key为hashcode+statementId+sql语句。Value为查询出来的结果集映射成的java对象。SqlSession执行insert、update、delete等操作commit后会清空该SQLSession缓存。 </section></li> <li style="outline: 0px;"> <section style="margin-top: 10px;margin-bottom: 10px;outline: 0px;line-height: 26px;color: rgb(1, 1, 1);"> 二级缓存 二级缓存是 mapper级别的,Mybatis默认是没有开启二级缓存的。第一次调用mapper下的SQL去查询用户的信息,查询到的信息会存放在该mapper对应的二级缓存区域。第二次调用namespace下的mapper映射文件中,相同的sql去查询用户信息,会去对应的二级缓存内取结果。 </section></li> </ul> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><img class="rich_pages wxw-img" data-backh="431" data-backw="570" data-ratio="0.7564814814814815" src="/upload/f711c1f5128788380735d95103e2d00b.png" data-type="png" data-w="1080" style="outline: 0px;width: 669px;box-sizing: border-box !important;visibility: visible !important;"> <mpcpc js_editor_cpcad="" class="js_cpc_area cpc_iframe" src="/cgi-bin/readtemplate?t=tmpl/cpc_tmpl#1647488094784" data-category_id_list="1|16|17|2|21|24|28|29|31|35|36|37|39|41|42|43|46|47|48|5|50|51|55|56|57|58|59|6|60|61|62|63|64|65|66|7|8" data-id="1647488094784"></mpcpc></p> <h3 style="margin-top: 1.2em;margin-bottom: 1em;outline: 0px;font-weight: bold;font-size: 20px;white-space: normal;color: rgb(53, 179, 120);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">MySQL 主从同步怎么做的?binlog清楚吗?</h3> <ul class="list-paddingleft-1" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;outline: 0px;white-space: normal;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"> <li style="outline: 0px;"> <section style="margin-top: 10px;margin-bottom: 10px;outline: 0px;line-height: 26px;color: rgb(1, 1, 1);"> Master 数据库只要发生变化,立马记录到Binary log 日志文件中 </section></li> <li style="outline: 0px;"> <section style="margin-top: 10px;margin-bottom: 10px;outline: 0px;line-height: 26px;color: rgb(1, 1, 1);"> Slave数据库启动一个I/O thread连接Master数据库,请求Master变化的二进制日志 </section></li> <li style="outline: 0px;"> <section style="margin-top: 10px;margin-bottom: 10px;outline: 0px;line-height: 26px;color: rgb(1, 1, 1);"> Slave I/O获取到的二进制日志,保存到自己的Relay log 日志文件中。 </section></li> <li style="outline: 0px;"> <section style="margin-top: 10px;margin-bottom: 10px;outline: 0px;line-height: 26px;color: rgb(1, 1, 1);"> Slave 有一个 SQL thread定时检查Realy log是否变化,变化那么就更新数据 </section></li> </ul> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><img class="rich_pages wxw-img" data-backh="370" data-backw="570" data-ratio="0.6481835564053537" src="/upload/9f33183e0d34751bd5e6f9788cfd7080.png" data-type="png" data-w="1046" style="outline: 0px;width: 669px;box-sizing: border-box !important;visibility: visible !important;"></p> <h3 style="margin-top: 1.2em;margin-bottom: 1em;outline: 0px;font-weight: bold;font-size: 20px;white-space: normal;color: rgb(53, 179, 120);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">MySQL 有没有做分库分表?怎么设计的?</h3> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">Why?:</p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><a target="_blank" href="https://mp.weixin.qq.com/s?__biz=Mzg2MDYzODI5Nw==&amp;mid=2247502768&amp;idx=3&amp;sn=13e931f2c13ab493d004456dc836625d&amp;scene=21#wechat_redirect" textvalue="当一张表的数据达到几千万时,你查询一次所花的时间会变多,如果有联合查询的话,我想有可能会死在那儿了。分表的目的就在于此,减小数据库的负担,缩短查询时间。最近整理一份MySQL面试学习资料,里面收录了高频面试题目及答案,打算跳槽的小伙伴不要错过,点击领取吧!" linktype="text" imgurl="" imgdata="null" tab="innerlink" style="color: rgb(0, 0, 0);" data-linktype="2"><span style="color: rgb(0, 0, 0);">当一张表的数据达到几千万时,你查询一次所花的时间会变多,如果有联合查询的话,我想有可能会死在那儿了。分表的目的就在于此,减小数据库的负担,缩短查询时间。最近整理一份MySQL面试学习资料,里面收录了高频面试题目及答案,打算跳槽的小伙伴不要错过,点击领取吧!</span></a></p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">mysql中有一种机制是表锁定和行锁定,是为了保证数据的完整性。表锁定表示你们都不能对这张表进行操作,必须等我对表操作完才行。行锁定也一样,别的sql必须等我对这条数据操作完了,才能对这条数据进行操作。</p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">When?(什么时候需要分表?):</p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">单表行数超过500万行或者单表容量超过2GB,才推荐进行分库分表。说明:如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表。</p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">反例:某业务三年总数据量才2万行,却分成1024张表,问:你为什么这么设计?答:分1024张表,不是标配吗?</p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">How?(分库分表有几种策略):</p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">垂直拆分 or 水平拆分</p> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">拆分中间件,详细可以参考:</p> <ul class="list-paddingleft-1" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;outline: 0px;white-space: normal;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"> <li style="outline: 0px;"> <section style="margin-top: 10px;margin-bottom: 10px;outline: 0px;line-height: 26px;color: rgb(1, 1, 1);"> Sharding-sphere,前身是sharding-jdbc;当当的分库分表中间件 </section></li> <li style="outline: 0px;color: rgb(0, 0, 0);"> <section style="margin-top: 10px;margin-bottom: 10px;outline: 0px;line-height: 26px;color: rgb(1, 1, 1);"> <a target="_blank" href="https://mp.weixin.qq.com/s?__biz=Mzg2MDYzODI5Nw==&amp;mid=2247502768&amp;idx=3&amp;sn=13e931f2c13ab493d004456dc836625d&amp;scene=21#wechat_redirect" textvalue="TDDL:jar,Taobao Distribute Data Layer;最近整理一份MySQL面试学习资料,里面收录了高频面试题目及答案,打算跳槽的小伙伴不要错过,点击领取吧!" linktype="text" imgurl="" imgdata="null" tab="innerlink" style="color: rgb(0, 0, 0);" data-linktype="2"><span style="color: rgb(0, 0, 0);">TDDL:jar,Taobao Distribute Data Layer;最近整理一份MySQL面试学习资料,里面收录了高频面试题目及答案,打算跳槽的小伙伴不要错过,点击领取吧!</span></a> </section></li> <li style="outline: 0px;"> <section style="margin-top: 10px;margin-bottom: 10px;outline: 0px;line-height: 26px;color: rgb(1, 1, 1);"> Mycat:中间件。 </section></li> </ul> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">注:工具的利弊,请自行调研,官网和社区优先。</p> <ul class="list-paddingleft-1" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;outline: 0px;white-space: normal;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"> <li style="outline: 0px;"> <section style="margin-top: 10px;margin-bottom: 10px;outline: 0px;line-height: 26px;color: rgb(1, 1, 1);"> 按照userId纬度拆分,安琪拉见过的常见的有,根据 userId % 64 取模拆0~63编号的64张表, </section></li> <li style="outline: 0px;"> <section style="margin-top: 10px;margin-bottom: 10px;outline: 0px;line-height: 26px;color: rgb(1, 1, 1);"> 固定位拆,取userId 指定二位,例如倒数2,3位组成00~99 一共100张表的,百库表表。 </section></li> <li style="outline: 0px;"> <section style="margin-top: 10px;margin-bottom: 10px;outline: 0px;line-height: 26px;color: rgb(1, 1, 1);"> hash: userId hash一下,然后 % 表数; </section></li> <li style="outline: 0px;"> <section style="margin-top: 10px;margin-bottom: 10px;outline: 0px;line-height: 26px;color: rgb(1, 1, 1);"> Range: 另外还有按照userId 指定范围拆的,0-1千万一张表,这种用的比较少,容易产生热点。 </section></li> <li style="outline: 0px;"> <section style="margin-top: 10px;margin-bottom: 10px;outline: 0px;line-height: 26px;color: rgb(1, 1, 1);"> 把不同业务域的表拆成不同库,例如订单相关表、用户信息相关表、营销相关表分开在不同库; </section></li> <li style="outline: 0px;"> <section style="margin-top: 10px;margin-bottom: 10px;outline: 0px;line-height: 26px;color: rgb(1, 1, 1);"> 把大字段独立存储到一张表中 </section></li> <li style="outline: 0px;"> <section style="margin-top: 10px;margin-bottom: 10px;outline: 0px;line-height: 26px;color: rgb(1, 1, 1);"> 把不常用的字段单独拿出来存储到一张表 </section></li> </ul> <h3 style="margin-top: 1.2em;margin-bottom: 1em;outline: 0px;font-weight: bold;font-size: 20px;white-space: normal;color: rgb(53, 179, 120);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">用userId做的分库分表,现在需要用电话号码查询怎么办?</h3> <p style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;outline: 0px;white-space: normal;font-size: 16px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);">和回表逻辑一样,单独建一个电话号码索引表,存放电话号码和userId,查询时先根据电话号码查询userId,然后再根据userId查询数据。</p> <section data-mpa-template="t" mpa-from-tpl="t"> <section mpa-from-tpl="t" style="margin-top: 10px;margin-bottom: 10px;"> <p style="margin-right: auto;margin-left: auto;width: 231.188px;"><img class="rich_pages wxw-img" data-ratio="0.16666666666666666" src="/upload/89aa6c9fe16e0dfcf56dad1a9f9078ff.png" data-type="gif" data-w="300" style="width: auto;"></p> <p style="margin-right: auto;margin-left: auto;width: 231.188px;"><br></p> </section> </section> <section style="box-sizing: border-box;font-size: 16px;"> <section style="height: auto;box-sizing: border-box;" powered-by="xiumi.us"> <section style="text-align: left;justify-content: flex-start;margin-top: 10px;margin-right: 0%;margin-left: 0%;display: flex;flex-flow: row nowrap;transform: translate3d(32px, 0px, 0px);box-sizing: border-box;"> <section style="display: inline-block;vertical-align: middle;width: auto;min-width: 10%;max-width: 100%;flex: 0 0 auto;height: auto;align-self: center;box-sizing: border-box;"> <section style="font-size: 19px;margin-right: 0%;margin-left: 0%;justify-content: flex-start;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;text-align: center;width: 1.8em;height: 1.8em;line-height: 1.8em;border-radius: 100%;margin-left: auto;margin-right: auto;font-size: 16px;color: rgb(255, 255, 255);border-width: 1px;border-style: solid;border-color: rgb(95, 156, 239);background-color: rgb(95, 156, 239);box-sizing: border-box;"> <p style="box-sizing: border-box;">往</p> </section> </section> </section> <section style="display: inline-block;vertical-align: middle;width: auto;min-width: 10%;max-width: 100%;flex: 0 0 auto;height: auto;align-self: center;box-sizing: border-box;"> <section style="font-size: 19px;margin-right: 0%;margin-left: 0%;justify-content: flex-start;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;text-align: center;width: 1.8em;height: 1.8em;line-height: 1.8em;border-radius: 100%;margin-left: auto;margin-right: auto;font-size: 16px;color: rgb(255, 255, 255);border-width: 1px;border-style: solid;border-color: rgb(95, 156, 239);background-color: rgb(95, 156, 239);box-sizing: border-box;"> <p style="box-sizing: border-box;">期</p> </section> </section> </section> <section style="display: inline-block;vertical-align: middle;width: auto;min-width: 10%;max-width: 100%;flex: 0 0 auto;height: auto;align-self: center;box-sizing: border-box;"> <section style="font-size: 19px;margin-right: 0%;margin-left: 0%;justify-content: flex-start;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;text-align: center;width: 1.8em;height: 1.8em;line-height: 1.8em;border-radius: 100%;margin-left: auto;margin-right: auto;font-size: 16px;color: rgb(255, 255, 255);border-width: 1px;border-style: solid;border-color: rgb(95, 156, 239);background-color: rgb(95, 156, 239);box-sizing: border-box;"> <p style="box-sizing: border-box;">推</p> </section> </section> </section> <section style="display: inline-block;vertical-align: middle;width: auto;min-width: 10%;max-width: 100%;flex: 0 0 auto;height: auto;align-self: center;box-sizing: border-box;"> <section style="font-size: 19px;margin-right: 0%;margin-left: 0%;justify-content: flex-start;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;text-align: center;width: 1.8em;height: 1.8em;line-height: 1.8em;border-radius: 100%;margin-left: auto;margin-right: auto;font-size: 16px;color: rgb(255, 255, 255);border-width: 1px;border-style: solid;border-color: rgb(95, 156, 239);background-color: rgb(95, 156, 239);box-sizing: border-box;"> <p style="box-sizing: border-box;">荐</p> </section> </section> </section> <section style="display: inline-block;vertical-align: middle;width: 25%;flex: 0 0 auto;height: auto;align-self: center;box-sizing: border-box;"> <section style="margin-top: 0.5em;margin-bottom: 0.5em;box-sizing: border-box;" powered-by="xiumi.us"> <section style="height: 1px;background-color: rgb(95, 156, 239);box-sizing: border-box;"> <section> <svg viewbox="0 0 1 1" style="float:left;line-height:0;width:0;vertical-align:top;"></svg> </section> </section> </section> </section> </section> </section> <section style="margin: 10px 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: 100%;vertical-align: top;background-color: rgba(123, 118, 118, 0.05);padding: 24px 34px 34px;box-sizing: border-box;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="box-sizing: border-box;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247502183&amp;idx=1&amp;sn=9d67afbf6e2589b15d85332998d48503&amp;chksm=97b4577fa0c3de69c1af9c90b353428e7bda34222605983afa7a79415cf3a32791d2103b4c8c&amp;scene=21#wechat_redirect" textvalue="阿里一面:ReadWriteLock 读写之间互斥吗?我竟然答不上来。。" linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" style="font-size: 15px;" data-linktype="2"><span style="font-size: 15px;">阿里一面:ReadWriteLock 读写之间互斥吗?我竟然答不上来。。</span></a><br></p> </section> <section style="margin-top: 0.5em;margin-bottom: 0.5em;box-sizing: border-box;" powered-by="xiumi.us"> <section style="height: 1px;background-color: rgb(95, 156, 239);box-sizing: border-box;"> <section> <svg viewbox="0 0 1 1" style="float:left;line-height:0;width:0;vertical-align:top;"></svg> </section> </section> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="box-sizing: border-box;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247502183&amp;idx=2&amp;sn=7ad02aad9a04574a63c2d86b3575e5f9&amp;chksm=97b4577fa0c3de6957c844818d4e33d4efbad4b44781414eafff9c1fa22241165688b54ad57f&amp;scene=21#wechat_redirect" textvalue="成都有哪些牛批的互联网公司?" linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" style="font-size: 15px;" data-linktype="2"><span style="font-size: 15px;">成都有哪些牛批的互联网公司?</span></a><br></p> </section> <section style="margin-top: 0.5em;margin-bottom: 0.5em;box-sizing: border-box;" powered-by="xiumi.us"> <section style="height: 1px;background-color: rgb(95, 156, 239);box-sizing: border-box;"> <section> <svg viewbox="0 0 1 1" style="float:left;line-height:0;width:0;vertical-align:top;"></svg> </section> </section> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="box-sizing: border-box;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247502111&amp;idx=1&amp;sn=368c2b49b9bcfb8980c27cb23b007684&amp;chksm=97b45707a0c3de1178e1cecafd80b5a2ef1316ab112d8403d1e45cd8abdd3860961721b0201c&amp;scene=21#wechat_redirect" textvalue="自定义注解妙用,一行代码搞定用户操作日志记录,你学会了吗?" linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" style="font-size: 15px;" data-linktype="2"><span style="font-size: 15px;">自定义注解妙用,一行代码搞定用户操作日志记录,你学会了吗?</span></a><br></p> </section> <section style="margin-top: 0.5em;margin-bottom: 0.5em;box-sizing: border-box;" powered-by="xiumi.us"> <section style="height: 1px;background-color: rgb(95, 156, 239);box-sizing: border-box;"> <section> <svg viewbox="0 0 1 1" style="float:left;line-height:0;width:0;vertical-align:top;"></svg> </section> </section> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="box-sizing: border-box;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247502111&amp;idx=2&amp;sn=0bcdba260cf5701bb7856125909b334b&amp;chksm=97b45707a0c3de111016a122dda9d1731090eeb31fc4ab540b26376128f66f7af033c091d9d0&amp;scene=21#wechat_redirect" textvalue="深入分析 RestController 与 Controller 的区别,你真的了解吗?" linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" style="font-size: 15px;" data-linktype="2"><span style="font-size: 15px;">深入分析 RestController 与 Controller 的区别,你真的了解吗?</span></a><br></p> </section> <section style="margin-top: 0.5em;margin-bottom: 0.5em;box-sizing: border-box;" powered-by="xiumi.us"> <section style="height: 1px;background-color: rgb(95, 156, 239);box-sizing: border-box;"> <section> <svg viewbox="0 0 1 1" style="float:left;line-height:0;width:0;vertical-align:top;"></svg> </section> </section> </section> </section> </section> </section> <section data-mpa-template="t" mpa-from-tpl="t" style="white-space: normal;"> <p style="text-align: center;"><strong><span style="color: rgb(140, 140, 140);letter-spacing: 0.008em;font-size: 14px;"><br></span></strong></p> <p style="text-align: center;"><strong><span style="color: rgb(140, 140, 140);letter-spacing: 0.008em;font-size: 14px;">一起进大厂,每日学干货</span></strong></p> </section> <section style="margin-top: 5px;white-space: normal;text-align: center;font-size: 15px;color: rgb(64, 64, 64);line-height: 1.74;letter-spacing: 0.008em;outline-style: none;overflow-wrap: break-word;"> <span style="color: rgb(0, 0, 0);"><strong><span style="font-size: 14px;">关注我回复【</span></strong></span> <span style="color: rgb(255, 76, 65);"><strong><span style="font-size: 14px;">加群</span></strong></span> <span style="color: rgb(0, 0, 0);"><strong><span style="font-size: 14px;">】,加入Java技术交流群</span></strong></span> </section> <section data-mpa-template="t" mpa-from-tpl="t"> <p style="text-align: center;"><img class="rich_pages wxw-img" data-ratio="0.5982532751091703" src="/upload/4e21037b66f60f7d73d060863de4b4b5.png" data-type="gif" data-w="458" data-width="100%" style="color: rgb(62, 62, 62);font-size: 16px;vertical-align: middle;width: 62.0938px;"></p> <section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzIxMzQzNzMwMw==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/HmHDU48icAtYvlypOY9VaGVXQ639L63Iq6zHiclgibG0CAhgrJ2JLRibKbeCgVIx7WXcicbMW6AJL1Hos9AoJTqtVfA/0?wx_fmt=png" data-nickname="后端面试那些事" data-alias="" data-signature="专注分享后端干货!面向大厂,一起进步!" data-from="0"></mpprofile> </section> </section> <section data-mpa-template="t" mpa-from-tpl="t"> <section data-role="paragraph" mpa-from-tpl="t" style="white-space: normal;border-width: 0px;border-style: none;border-color: initial;"> <p style="outline: 0px;max-width: 100%;color: rgb(0, 0, 0);font-family: PingFangSC-Light;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;color: rgb(64, 84, 115);text-align: justify;box-sizing: border-box !important;overflow-wrap: break-word !important;">点击“阅读原文”,领取 2022&nbsp;年<strong style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">最新免费学习资料</strong></span><strong style="outline: 0px;max-width: 100%;color: rgb(64, 84, 115);text-align: justify;box-sizing: border-box !important;overflow-wrap: break-word !important;"></strong></p> <section data-mpa-template="t" mpa-from-tpl="t" style="outline: 0px;max-width: 100%;color: rgb(0, 0, 0);font-family: PingFangSC-Light;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section data-role="paragraph" mpa-from-tpl="t" style="outline: 0px;max-width: 100%;border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section powered-by="xiumi.us" style="outline: 0px;max-width: 100%;font-size: 32px;color: rgb(249, 110, 87);box-sizing: border-box !important;overflow-wrap: break-word !important;"> ↓↓↓ <span style="color: rgb(51, 51, 51);font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 17px;text-align: justify;"></span> </section> </section> </section> </section> </section> </section>

7种方式,教你提升 SpringBoot 项目的吞吐量

作者:微信小助手

<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="padding-right: 10px;padding-left: 10px;text-align: left;line-height: 1.6;letter-spacing: 0.034em;color: rgb(63, 63, 63);font-size: 16px;font-family: Roboto, Oxygen, Ubuntu, Cantarell, PingFangSC-light, PingFangTC-light, &quot;Open Sans&quot;, &quot;Helvetica Neue&quot;, sans-serif;"> <h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;">一、异步执行<span style="display: none;"></span></h5> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 23px;color: rgb(74, 74, 74);line-height: 1.75em;">实现方式二种:</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 使用异步注解 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(60, 112, 198);">@aysnc</code>、启动类:添加 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(60, 112, 198);">@EnableAsync</code>注解 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> JDK 8本身有一个非常好用的Future类—— <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(60, 112, 198);">CompletableFuture</code> </section></li> </ol> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background: #272822;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #75715e;line-height: 26px;">@AllArgsConstructor</span><br><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">class</span>&nbsp;<span style="font-weight: bold;color: white;line-height: 26px;">AskThread</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">implements</span>&nbsp;<span style="font-weight: bold;color: white;line-height: 26px;">Runnable</span></span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">private</span>&nbsp;CompletableFuture&lt;Integer&gt;&nbsp;re&nbsp;=&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">null</span>;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">void</span>&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">run</span><span style="line-height: 26px;">()</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">int</span>&nbsp;myRe&nbsp;=&nbsp;<span style="line-height: 26px;">0</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">try</span>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myRe&nbsp;=&nbsp;re.get()&nbsp;*&nbsp;re.get();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">catch</span>&nbsp;(Exception&nbsp;e)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(myRe);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">static</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">void</span>&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">main</span><span style="line-height: 26px;">(String[]&nbsp;args)</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">throws</span>&nbsp;InterruptedException&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">final</span>&nbsp;CompletableFuture&lt;Integer&gt;&nbsp;future&nbsp;=&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">new</span>&nbsp;CompletableFuture&lt;&gt;();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">new</span>&nbsp;Thread(<span style="color: #f92672;font-weight: bold;line-height: 26px;">new</span>&nbsp;AskThread(future)).start();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">//模拟长时间的计算过程</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(<span style="line-height: 26px;">1000</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">//告知完成结果</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;future.complete(<span style="line-height: 26px;">60</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 23px;color: rgb(74, 74, 74);line-height: 1.75em;">在该示例中,启动一个线程,此时<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(60, 112, 198);">AskThread</code>对象还没有拿到它需要的数据,执行到 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(60, 112, 198);">myRe = re.get() * re.get()</code>会阻塞。我们用休眠1秒来模拟一个长时间的计算过程,并将计算结果告诉<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(60, 112, 198);">future</code>执行结果,<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(60, 112, 198);">AskThread</code>线程将会继续执行。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background: #272822;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">class</span>&nbsp;<span style="font-weight: bold;color: white;line-height: 26px;">Calc</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">static</span>&nbsp;Integer&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">calc</span><span style="line-height: 26px;">(Integer&nbsp;para)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">try</span>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">//模拟一个长时间的执行</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(<span style="line-height: 26px;">1000</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">catch</span>&nbsp;(InterruptedException&nbsp;e)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">return</span>&nbsp;para&nbsp;*&nbsp;para;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">static</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">void</span>&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">main</span><span style="line-height: 26px;">(String[]&nbsp;args)</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">throws</span>&nbsp;ExecutionException,&nbsp;InterruptedException&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">final</span>&nbsp;CompletableFuture&lt;Void&gt;&nbsp;future&nbsp;=&nbsp;CompletableFuture.supplyAsync(()&nbsp;-&gt;&nbsp;calc(<span style="line-height: 26px;">50</span>))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.thenApply((i)&nbsp;-&gt;&nbsp;Integer.toString(i))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.thenApply((str)&nbsp;-&gt;&nbsp;<span style="color: #a6e22e;line-height: 26px;">"\""</span>&nbsp;+&nbsp;str&nbsp;+&nbsp;<span style="color: #a6e22e;line-height: 26px;">"\""</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.thenAccept(System.out::println);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;future.get();<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 23px;color: rgb(74, 74, 74);line-height: 1.75em;"><code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(60, 112, 198);">CompletableFuture.supplyAsync</code>方法构造一个<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(60, 112, 198);">CompletableFuture</code>实例,在<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(60, 112, 198);">supplyAsync()</code>方法中,它会在一个新线程中,执行传入的参数。在这里它会执行<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(60, 112, 198);">calc()</code>方法,这个方法可能是比较慢的,但这并不影响<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(60, 112, 198);">CompletableFuture</code>实例的构造速度,<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(60, 112, 198);">supplyAsync()</code>会立即返回。而返回的<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(60, 112, 198);">CompletableFuture</code>实例就可以作为这次调用的契约,在将来任何场合,用于获得最终的计算结果。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 23px;color: rgb(74, 74, 74);line-height: 1.75em;"><code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(60, 112, 198);">supplyAsync</code>用于提供返回值的情况,<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(60, 112, 198);">CompletableFuture</code>还有一个不需要返回值的异步调用方法<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(60, 112, 198);">runAsync(Runnable runnable)</code>,一般我们在优化<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(60, 112, 198);">Controller</code>时,使用这个方法比较多。这两个方法如果在不指定线程池的情况下,都是在<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(60, 112, 198);">ForkJoinPool.common</code>线程池中执行,而这个线程池中的所有线程都是<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(60, 112, 198);">Daemon</code>(守护)线程,所以,当主线程结束时,这些线程无论执行完毕都会退出系统。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 23px;color: rgb(74, 74, 74);line-height: 1.75em;">核心代码:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background: #272822;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">CompletableFuture.runAsync(()&nbsp;-&gt;<br>&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">this</span>.afterBetProcessor(betRequest,betDetailResult,appUser,id)<br>);<br></code></pre> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 23px;color: rgb(74, 74, 74);line-height: 1.75em;">异步调用使用Callable来实现</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background: #272822;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #75715e;line-height: 26px;">@RestController</span>&nbsp;&nbsp;<br><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">class</span>&nbsp;<span style="font-weight: bold;color: white;line-height: 26px;">HelloController</span>&nbsp;</span>{&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">private</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">static</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">final</span>&nbsp;Logger&nbsp;logger&nbsp;=&nbsp;LoggerFactory.getLogger(HelloController<span style="line-height: 26px;">.<span style="color: #f92672;font-weight: bold;line-height: 26px;">class</span>)</span>;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">@Autowired</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">private</span>&nbsp;HelloService&nbsp;hello;&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">@GetMapping</span>(<span style="color: #a6e22e;line-height: 26px;">"/helloworld"</span>)&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;String&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">helloWorldController</span><span style="line-height: 26px;">()</span>&nbsp;</span>{&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">return</span>&nbsp;hello.sayHello();&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">/**&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;异步调用restful&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;当controller返回值是Callable的时候,springmvc就会启动一个线程将Callable交给TaskExecutor去处理&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;然后DispatcherServlet还有所有的spring拦截器都退出主线程,然后把response保持打开的状态&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;当Callable执行结束之后,springmvc就会重新启动分配一个request请求,然后DispatcherServlet就重新&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;调用和处理Callable异步执行的返回结果,&nbsp;然后返回视图&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;<span style="font-weight: bold;line-height: 26px;">@return</span>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">@GetMapping</span>(<span style="color: #a6e22e;line-height: 26px;">"/hello"</span>)&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;Callable&lt;String&gt;&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">helloController</span><span style="line-height: 26px;">()</span>&nbsp;</span>{&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info(Thread.currentThread().getName()&nbsp;+&nbsp;<span style="color: #a6e22e;line-height: 26px;">"&nbsp;进入helloController方法"</span>);&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Callable&lt;String&gt;&nbsp;callable&nbsp;=&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">new</span>&nbsp;Callable&lt;String&gt;()&nbsp;{&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">@Override</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;String&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">call</span><span style="line-height: 26px;">()</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">throws</span>&nbsp;Exception&nbsp;</span>{&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info(Thread.currentThread().getName()&nbsp;+&nbsp;<span style="color: #a6e22e;line-height: 26px;">"&nbsp;进入call方法"</span>);&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;say&nbsp;=&nbsp;hello.sayHello();&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info(Thread.currentThread().getName()&nbsp;+&nbsp;<span style="color: #a6e22e;line-height: 26px;">"&nbsp;从helloService方法返回"</span>);&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">return</span>&nbsp;say;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info(Thread.currentThread().getName()&nbsp;+&nbsp;<span style="color: #a6e22e;line-height: 26px;">"&nbsp;从helloController方法返回"</span>);&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">return</span>&nbsp;callable;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br>}&nbsp;&nbsp;<br></code></pre> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 23px;color: rgb(74, 74, 74);line-height: 1.75em;">异步调用的方式 WebAsyncTask</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background: #272822;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #75715e;line-height: 26px;">@RestController</span>&nbsp;&nbsp;<br><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">class</span>&nbsp;<span style="font-weight: bold;color: white;line-height: 26px;">HelloController</span>&nbsp;</span>{&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">private</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">static</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">final</span>&nbsp;Logger&nbsp;logger&nbsp;=&nbsp;LoggerFactory.getLogger(HelloController<span style="line-height: 26px;">.<span style="color: #f92672;font-weight: bold;line-height: 26px;">class</span>)</span>;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">@Autowired</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">private</span>&nbsp;HelloService&nbsp;hello;&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">/**&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;带超时时间的异步请求&nbsp;通过WebAsyncTask自定义客户端超时间&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;<span style="font-weight: bold;line-height: 26px;">@return</span>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">@GetMapping</span>(<span style="color: #a6e22e;line-height: 26px;">"/world"</span>)&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;WebAsyncTask&lt;String&gt;&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">worldController</span><span style="line-height: 26px;">()</span>&nbsp;</span>{&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info(Thread.currentThread().getName()&nbsp;+&nbsp;<span style="color: #a6e22e;line-height: 26px;">"&nbsp;进入helloController方法"</span>);&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">//&nbsp;3s钟没返回,则认为超时&nbsp;&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WebAsyncTask&lt;String&gt;&nbsp;webAsyncTask&nbsp;=&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">new</span>&nbsp;WebAsyncTask&lt;&gt;(<span style="line-height: 26px;">3000</span>,&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">new</span>&nbsp;Callable&lt;String&gt;()&nbsp;{&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">@Override</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;String&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">call</span><span style="line-height: 26px;">()</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">throws</span>&nbsp;Exception&nbsp;</span>{&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info(Thread.currentThread().getName()&nbsp;+&nbsp;<span style="color: #a6e22e;line-height: 26px;">"&nbsp;进入call方法"</span>);&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;say&nbsp;=&nbsp;hello.sayHello();&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info(Thread.currentThread().getName()&nbsp;+&nbsp;<span style="color: #a6e22e;line-height: 26px;">"&nbsp;从helloService方法返回"</span>);&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">return</span>&nbsp;say;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info(Thread.currentThread().getName()&nbsp;+&nbsp;<span style="color: #a6e22e;line-height: 26px;">"&nbsp;从helloController方法返回"</span>);&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;webAsyncTask.onCompletion(<span style="color: #f92672;font-weight: bold;line-height: 26px;">new</span>&nbsp;Runnable()&nbsp;{&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">@Override</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">void</span>&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">run</span><span style="line-height: 26px;">()</span>&nbsp;</span>{&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info(Thread.currentThread().getName()&nbsp;+&nbsp;<span style="color: #a6e22e;line-height: 26px;">"&nbsp;执行完毕"</span>);&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;webAsyncTask.onTimeout(<span style="color: #f92672;font-weight: bold;line-height: 26px;">new</span>&nbsp;Callable&lt;String&gt;()&nbsp;{&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">@Override</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;String&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">call</span><span style="line-height: 26px;">()</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">throws</span>&nbsp;Exception&nbsp;</span>{&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info(Thread.currentThread().getName()&nbsp;+&nbsp;<span style="color: #a6e22e;line-height: 26px;">"&nbsp;onTimeout"</span>);&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">//&nbsp;超时的时候,直接抛异常,让外层统一处理超时异常&nbsp;&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">throw</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">new</span>&nbsp;TimeoutException(<span style="color: #a6e22e;line-height: 26px;">"调用超时"</span>);&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">return</span>&nbsp;webAsyncTask;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">/**&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;异步调用,异常处理,详细的处理流程见MyExceptionHandler类&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;<span style="font-weight: bold;line-height: 26px;">@return</span>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">@GetMapping</span>(<span style="color: #a6e22e;line-height: 26px;">"/exception"</span>)&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;WebAsyncTask&lt;String&gt;&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">exceptionController</span><span style="line-height: 26px;">()</span>&nbsp;</span>{&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info(Thread.currentThread().getName()&nbsp;+&nbsp;<span style="color: #a6e22e;line-height: 26px;">"&nbsp;进入helloController方法"</span>);&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Callable&lt;String&gt;&nbsp;callable&nbsp;=&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">new</span>&nbsp;Callable&lt;String&gt;()&nbsp;{&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">@Override</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;String&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">call</span><span style="line-height: 26px;">()</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">throws</span>&nbsp;Exception&nbsp;</span>{&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info(Thread.currentThread().getName()&nbsp;+&nbsp;<span style="color: #a6e22e;line-height: 26px;">"&nbsp;进入call方法"</span>);&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">throw</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">new</span>&nbsp;TimeoutException(<span style="color: #a6e22e;line-height: 26px;">"调用超时!"</span>);&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info(Thread.currentThread().getName()&nbsp;+&nbsp;<span style="color: #a6e22e;line-height: 26px;">"&nbsp;从helloController方法返回"</span>);&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">return</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">new</span>&nbsp;WebAsyncTask&lt;&gt;(<span style="line-height: 26px;">20000</span>,&nbsp;callable);&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>}&nbsp;&nbsp;<br></code></pre> <h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;"><span style="display: none;"></span>二、增加内嵌Tomcat的最大连接数<span style="display: none;"></span></h5> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background: #272822;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #75715e;line-height: 26px;">@Configuration</span><br><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">class</span>&nbsp;<span style="font-weight: bold;color: white;line-height: 26px;">TomcatConfig</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">@Bean</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;ConfigurableServletWebServerFactory&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">webServerFactory</span><span style="line-height: 26px;">()</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TomcatServletWebServerFactory&nbsp;tomcatFactory&nbsp;=&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">new</span>&nbsp;TomcatServletWebServerFactory();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tomcatFactory.addConnectorCustomizers(<span style="color: #f92672;font-weight: bold;line-height: 26px;">new</span>&nbsp;MyTomcatConnectorCustomizer());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tomcatFactory.setPort(<span style="line-height: 26px;">8005</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tomcatFactory.setContextPath(<span style="color: #a6e22e;line-height: 26px;">"/api-g"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">return</span>&nbsp;tomcatFactory;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">class</span>&nbsp;<span style="font-weight: bold;color: white;line-height: 26px;">MyTomcatConnectorCustomizer</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">implements</span>&nbsp;<span style="font-weight: bold;color: white;line-height: 26px;">TomcatConnectorCustomizer</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">void</span>&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">customize</span><span style="line-height: 26px;">(Connector&nbsp;connector)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Http11NioProtocol&nbsp;protocol&nbsp;=&nbsp;(Http11NioProtocol)&nbsp;connector.getProtocolHandler();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">//设置最大连接数&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;protocol.setMaxConnections(<span style="line-height: 26px;">20000</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">//设置最大线程数&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;protocol.setMaxThreads(<span style="line-height: 26px;">2000</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;protocol.setConnectionTimeout(<span style="line-height: 26px;">30000</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>}<br></code></pre> <h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;"><span style="display: none;"></span>三、使用@ComponentScan()定位扫包比@SpringBootApplication扫包更快<span style="display: none;"></span></h5> <h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;"><span style="display: none;"></span>四、默认tomcat容器改为Undertow(Jboss下的服务器,Tomcat吞吐量5000,Undertow吞吐量8000)<span style="display: none;"></span></h5> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background: #272822;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #f92672;line-height: 26px;">&lt;<span style="line-height: 26px;">exclusions</span>&gt;</span><br>&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="line-height: 26px;">exclusion</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="line-height: 26px;">groupId</span>&gt;</span>org.springframework.boot<span style="color: #f92672;line-height: 26px;">&lt;/<span style="line-height: 26px;">groupId</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="line-height: 26px;">artifactId</span>&gt;</span>spring-boot-starter-tomcat<span style="color: #f92672;line-height: 26px;">&lt;/<span style="line-height: 26px;">artifactId</span>&gt;</span><br>&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="line-height: 26px;">exclusion</span>&gt;</span><br><span style="color: #f92672;line-height: 26px;">&lt;/<span style="line-height: 26px;">exclusions</span>&gt;</span><br></code></pre> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 23px;color: rgb(74, 74, 74);line-height: 1.75em;">改为:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background: #272822;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #f92672;line-height: 26px;">&lt;<span style="line-height: 26px;">dependency</span>&gt;</span><br>&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="line-height: 26px;">groupId</span>&gt;</span>org.springframework.boot<span style="color: #f92672;line-height: 26px;">&lt;/<span style="line-height: 26px;">groupId</span>&gt;</span><br>&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="line-height: 26px;">artifactId</span>&gt;</span>spring-boot-starter-undertow<span style="color: #f92672;line-height: 26px;">&lt;/<span style="line-height: 26px;">artifactId</span>&gt;</span><br><span style="color: #f92672;line-height: 26px;">&lt;/<span style="line-height: 26px;">dependency</span>&gt;</span><br></code></pre> <h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;"><span style="display: none;"></span>五、使用 BufferedWriter 进行缓冲<span style="display: none;"></span></h5> <h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;"><span style="display: none;"></span>六、Deferred方式实现异步调用<span style="display: none;"></span></h5> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background: #272822;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #75715e;line-height: 26px;">@RestController</span><br><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">class</span>&nbsp;<span style="font-weight: bold;color: white;line-height: 26px;">AsyncDeferredController</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">private</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">final</span>&nbsp;Logger&nbsp;logger&nbsp;=&nbsp;LoggerFactory.getLogger(<span style="color: #f92672;font-weight: bold;line-height: 26px;">this</span>.getClass());<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">private</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">final</span>&nbsp;LongTimeTask&nbsp;taskService;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">@Autowired</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">AsyncDeferredController</span><span style="line-height: 26px;">(LongTimeTask&nbsp;taskService)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">this</span>.taskService&nbsp;=&nbsp;taskService;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">@GetMapping</span>(<span style="color: #a6e22e;line-height: 26px;">"/deferred"</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;DeferredResult&lt;String&gt;&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">executeSlowTask</span><span style="line-height: 26px;">()</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info(Thread.currentThread().getName()&nbsp;+&nbsp;<span style="color: #a6e22e;line-height: 26px;">"进入executeSlowTask方法"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DeferredResult&lt;String&gt;&nbsp;deferredResult&nbsp;=&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">new</span>&nbsp;DeferredResult&lt;&gt;();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">//&nbsp;调用长时间执行任务</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;taskService.execute(deferredResult);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">//&nbsp;当长时间任务中使用deferred.setResult("world");这个方法时,会从长时间任务中返回,继续controller里面的流程</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info(Thread.currentThread().getName()&nbsp;+&nbsp;<span style="color: #a6e22e;line-height: 26px;">"从executeSlowTask方法返回"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">//&nbsp;超时的回调方法</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;deferredResult.onTimeout(<span style="color: #f92672;font-weight: bold;line-height: 26px;">new</span>&nbsp;Runnable(){<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">@Override</span><br>&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">void</span>&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">run</span><span style="line-height: 26px;">()</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;logger.info(Thread.currentThread().getName()&nbsp;+&nbsp;<span style="color: #a6e22e;line-height: 26px;">"&nbsp;onTimeout"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">//&nbsp;返回超时信息</span><br>&nbsp;&nbsp;&nbsp;&nbsp;deferredResult.setErrorResult(<span style="color: #a6e22e;line-height: 26px;">"time&nbsp;out!"</span>);<br>&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;});<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">//&nbsp;处理完成的回调方法,无论是超时还是处理成功,都会进入这个回调方法</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;deferredResult.onCompletion(<span style="color: #f92672;font-weight: bold;line-height: 26px;">new</span>&nbsp;Runnable(){<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">@Override</span><br>&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">void</span>&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">run</span><span style="line-height: 26px;">()</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;logger.info(Thread.currentThread().getName()&nbsp;+&nbsp;<span style="color: #a6e22e;line-height: 26px;">"&nbsp;onCompletion"</span>);<br>&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;});<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">return</span>&nbsp;deferredResult;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br></code></pre> <h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;"><span style="display: none;"></span>七、异步调用可以使用AsyncHandlerInterceptor进行拦截<span style="display: none;"></span></h5> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background: #272822;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #75715e;line-height: 26px;">@Component</span><br><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">class</span>&nbsp;<span style="font-weight: bold;color: white;line-height: 26px;">MyAsyncHandlerInterceptor</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">implements</span>&nbsp;<span style="font-weight: bold;color: white;line-height: 26px;">AsyncHandlerInterceptor</span>&nbsp;</span>{<br>&nbsp;<br>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">private</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">static</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">final</span>&nbsp;Logger&nbsp;logger&nbsp;=&nbsp;LoggerFactory.getLogger(MyAsyncHandlerInterceptor<span style="line-height: 26px;">.<span style="color: #f92672;font-weight: bold;line-height: 26px;">class</span>)</span>;<br>&nbsp;<br>&nbsp;<span style="color: #75715e;line-height: 26px;">@Override</span><br>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">boolean</span>&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">preHandle</span><span style="line-height: 26px;">(HttpServletRequest&nbsp;request,&nbsp;HttpServletResponse&nbsp;response,&nbsp;Object&nbsp;handler)</span><br>&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">throws</span>&nbsp;Exception&nbsp;</span>{<br>&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">return</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">true</span>;<br>&nbsp;}<br>&nbsp;<br>&nbsp;<span style="color: #75715e;line-height: 26px;">@Override</span><br>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">void</span>&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">postHandle</span><span style="line-height: 26px;">(HttpServletRequest&nbsp;request,&nbsp;HttpServletResponse&nbsp;response,&nbsp;Object&nbsp;handler,<br>&nbsp;&nbsp;&nbsp;ModelAndView&nbsp;modelAndView)</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">throws</span>&nbsp;Exception&nbsp;</span>{<br><span style="color: #75715e;line-height: 26px;">//&nbsp;&nbsp;HandlerMethod&nbsp;handlerMethod&nbsp;=&nbsp;(HandlerMethod)&nbsp;handler;</span><br>&nbsp;&nbsp;logger.info(Thread.currentThread().getName()+&nbsp;<span style="color: #a6e22e;line-height: 26px;">"服务调用完成,返回结果给客户端"</span>);<br>&nbsp;}<br>&nbsp;<br>&nbsp;<span style="color: #75715e;line-height: 26px;">@Override</span><br>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">void</span>&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">afterCompletion</span><span style="line-height: 26px;">(HttpServletRequest&nbsp;request,&nbsp;HttpServletResponse&nbsp;response,&nbsp;Object&nbsp;handler,&nbsp;Exception&nbsp;ex)</span><br>&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">throws</span>&nbsp;Exception&nbsp;</span>{<br>&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">if</span>(<span style="color: #f92672;font-weight: bold;line-height: 26px;">null</span>&nbsp;!=&nbsp;ex){<br>&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: #a6e22e;line-height: 26px;">"发生异常:"</span>+ex.getMessage());<br>&nbsp;&nbsp;}<br>&nbsp;}<br>&nbsp;<br>&nbsp;<span style="color: #75715e;line-height: 26px;">@Override</span><br>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">void</span>&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">afterConcurrentHandlingStarted</span><span style="line-height: 26px;">(HttpServletRequest&nbsp;request,&nbsp;HttpServletResponse&nbsp;response,&nbsp;Object&nbsp;handler)</span><br>&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">throws</span>&nbsp;Exception&nbsp;</span>{<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">//&nbsp;拦截之后,重新写回数据,将原来的hello&nbsp;world换成如下字符串</span><br>&nbsp;&nbsp;String&nbsp;resp&nbsp;=&nbsp;<span style="color: #a6e22e;line-height: 26px;">"my&nbsp;name&nbsp;is&nbsp;chhliu!"</span>;<br>&nbsp;&nbsp;response.setContentLength(resp.length());<br>&nbsp;&nbsp;response.getOutputStream().write(resp.getBytes());<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;logger.info(Thread.currentThread().getName()&nbsp;+&nbsp;<span style="color: #a6e22e;line-height: 26px;">"&nbsp;进入afterConcurrentHandlingStarted方法"</span>);<br>&nbsp;}<br>&nbsp;<br>}<br></code></pre> <h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;"><span style="display: none;"></span>参考<span style="display: none;"></span></h5> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;background: rgb(239, 239, 239);color: rgb(106, 115, 125);margin-bottom: 20px;margin-top: 20px;padding: 15px 20px;line-height: 27px;"> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> https://my.oschina.net/u/3768341/blog/3001731 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> https://blog.csdn.net/liuchuanhong1/article/details/78744138 </section></li> </ul> </blockquote> </section>

Spring Boot + MDC 实现全链路调用日志跟踪

作者:微信小助手

<section class="mp_profile_iframe_wrp" data-mpa-powered-by="yiban.io"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzA5MTU0OTY0Ng==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/zc3KLDBfJlmPt0J5PXYOoiaG8wsQPZrLevbxMZSfgQ0YypNYaicnbS0P9UicluuOySLSP4CjTcRUVHCZzYeXQ9WlA/0?wx_fmt=png" data-nickname="Java派" data-alias="javapai" data-signature="专注Java相关技术栈:Spring全家筒、Docker、k8s、Mysql、集群、微服务、中间件等知识。" data-from="0"></mpprofile> </section> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;line-height: 1.6;letter-spacing: 0px;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;"> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;font-weight: bold;font-size: 22px;border-bottom: 2px solid rgb(89, 89, 89);margin-bottom: 30px;color: rgb(89, 89, 89);"><span style="display: none;"></span><span style="font-size: 19px;display: inline-block;border-bottom: 2px solid rgb(89,89,89);">写在前面</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 15px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">通过本文将了解到什么是MDC、MDC应用中存在的问题、如何解决存在的问题</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;font-weight: bold;font-size: 22px;border-bottom: 2px solid rgb(89, 89, 89);margin-bottom: 30px;color: rgb(89, 89, 89);"><span style="display: none;"></span><span style="font-size: 19px;display: inline-block;border-bottom: 2px solid rgb(89,89,89);">MDC介绍</span></h2> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>简介:<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 15px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">MDC(Mapped Diagnostic Context,映射调试上下文)是 log4j 、logback及log4j2 提供的一种方便在多线程条件下记录日志的功能。<strong style="color: rgb(71, 193, 168);">MDC</strong> 可以看成是一个<strong style="color: rgb(71, 193, 168);">与当前线程绑定的哈希表</strong>,可以往其中添加键值对。MDC 中包含的内容可以<strong style="color: rgb(71, 193, 168);">被同一线程中执行的代码所访问</strong>。当前线程的子线程会继承其父线程中的 MDC 的内容。当需要记录日志时,只需要从 MDC 中获取所需的信息即可。MDC 的内容则由程序在适当的时候保存进去。对于一个 Web 应用来说,通常是在请求被处理的最开始保存这些数据</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>API说明:<span style="display: none;"></span></h4> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;font-size: 15px;line-height: 30px;letter-spacing: 1.5px;color: rgb(51, 51, 51);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 30px;"> clear() =&gt; 移除所有MDC </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 30px;"> get (String key) =&gt; 获取当前线程MDC中指定key的值 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 30px;"> getContext() =&gt; 获取当前线程MDC的MDC </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 30px;"> put(String key, Object o) =&gt; 往当前线程的MDC中存入指定的键值对 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 30px;"> remove(String key) =&gt; 删除当前线程MDC中指定的键值对 </section></li> </ul> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>优点:<span style="display: none;"></span></h4> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;font-size: 15px;line-height: 30px;letter-spacing: 1.5px;color: rgb(51, 51, 51);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 30px;"> 代码简洁,日志风格统一,不需要在log打印中手动拼写traceId,即LOGGER.info("traceId:{} ", traceId) </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 15px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">暂时只能想到这一点</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;font-weight: bold;font-size: 22px;border-bottom: 2px solid rgb(89, 89, 89);margin-bottom: 30px;color: rgb(89, 89, 89);"><span style="display: none;"></span><span style="font-size: 19px;display: inline-block;border-bottom: 2px solid rgb(89,89,89);">MDC使用</span></h2> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;font-size: 15px;line-height: 30px;letter-spacing: 1.5px;color: rgb(51, 51, 51);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 30px;"> 添加拦截器 </section></li> </ul> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/icFTnRoibgibpicVqKDsKh7eaoR8lZJibjC9Oy43hRmaX93IHaAXf481GXCIXxy9VEfy1Y81nfB7hIJClhHbOs34wxBnnGLLJdGbp/640?wx_fmt=svg&amp;random=0.8171761397222812&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span>&nbsp;<span style="color: #e6c07b;line-height: 26px;">LogInterceptor</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">implements</span>&nbsp;<span style="color: #e6c07b;line-height: 26px;">HandlerInterceptor</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #61aeee;line-height: 26px;">@Override</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">boolean</span>&nbsp;<span style="color: #61aeee;line-height: 26px;">preHandle</span><span style="line-height: 26px;">(HttpServletRequest&nbsp;request,&nbsp;HttpServletResponse&nbsp;response,&nbsp;Object&nbsp;handler)</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">throws</span>&nbsp;Exception&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #5c6370;font-style: italic;line-height: 26px;">//如果有上层调用就用上层的ID</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;traceId&nbsp;=&nbsp;request.getHeader(Constants.TRACE_ID);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">if</span>&nbsp;(traceId&nbsp;==&nbsp;<span style="color: #c678dd;line-height: 26px;">null</span>)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;traceId&nbsp;=&nbsp;TraceIdUtil.getTraceId();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MDC.put(Constants.TRACE_ID,&nbsp;traceId);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">return</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">true</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #61aeee;line-height: 26px;">@Override</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">void</span>&nbsp;<span style="color: #61aeee;line-height: 26px;">postHandle</span><span style="line-height: 26px;">(HttpServletRequest&nbsp;request,&nbsp;HttpServletResponse&nbsp;response,&nbsp;Object&nbsp;handler,&nbsp;ModelAndView&nbsp;modelAndView)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">throws</span>&nbsp;Exception&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #61aeee;line-height: 26px;">@Override</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">void</span>&nbsp;<span style="color: #61aeee;line-height: 26px;">afterCompletion</span><span style="line-height: 26px;">(HttpServletRequest&nbsp;request,&nbsp;HttpServletResponse&nbsp;response,&nbsp;Object&nbsp;handler,&nbsp;Exception&nbsp;ex)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">throws</span>&nbsp;Exception&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #5c6370;font-style: italic;line-height: 26px;">//调用结束后删除</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MDC.remove(Constants.TRACE_ID);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br></code></pre> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;font-size: 15px;line-height: 30px;letter-spacing: 1.5px;color: rgb(51, 51, 51);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 30px;"> 修改日志格式 </section></li> </ul> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/icFTnRoibgibpicVqKDsKh7eaoR8lZJibjC9Oy43hRmaX93IHaAXf481GXCIXxy9VEfy1Y81nfB7hIJClhHbOs34wxBnnGLLJdGbp/640?wx_fmt=svg&amp;random=0.5633498240276145&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">property</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">name</span>=<span style="color: #98c379;line-height: 26px;">"pattern"</span>&gt;</span>[TRACEID:%X{traceId}]&nbsp;%d{HH:mm:ss.SSS}&nbsp;%-5level&nbsp;%class{-1}.%M()/%L&nbsp;-&nbsp;%msg%xEx%n<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">property</span>&gt;</span><br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 15px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">重点是%X{traceId},traceId和MDC中的键名称一致</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 15px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">简单使用就这么容易,但是在有些情况下traceId将获取不到</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.8222996515679443" src="/upload/fa720b0760bcab13583a2e8a3ccc4748.jpg" data-type="jpeg" data-w="574" style="display: block;margin-right: auto;margin-left: auto;box-shadow: rgb(210, 210, 210) 3px 3px 10px;height: auto !important;"> <figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"> img </figcaption> </figure> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;font-weight: bold;font-size: 22px;border-bottom: 2px solid rgb(89, 89, 89);margin-bottom: 30px;color: rgb(89, 89, 89);"><span style="display: none;"></span><span style="font-size: 19px;display: inline-block;border-bottom: 2px solid rgb(89,89,89);">MDC 存在的问题</span></h2> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;font-size: 15px;line-height: 30px;letter-spacing: 1.5px;color: rgb(51, 51, 51);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 30px;"> 子线程中打印日志丢失traceId </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 30px;"> HTTP调用丢失traceId </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 15px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">丢失traceId的情况,来一个再解决一个,绝不提前优化</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;color: rgb(89, 89, 89);"><span style="display: none;"></span>解决MDC存在的问题<span style="display: none;"></span></h3> <h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;"><span style="display: none;"></span>子线程日志打印丢失traceId<span style="display: none;"></span></h5> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 15px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">子线程在打印日志的过程中traceId将丢失,解决方式为重写线程池,对于直接new创建线程的情况不考略【实际应用中应该避免这种用法】,重写线程池无非是对任务进行一次封装</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;font-size: 15px;line-height: 30px;letter-spacing: 1.5px;color: rgb(51, 51, 51);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 30px;"> 线程池封装类:ThreadPoolExecutorMdcWrapper.java </section></li> </ul> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/icFTnRoibgibpicVqKDsKh7eaoR8lZJibjC9Oy43hRmaX93IHaAXf481GXCIXxy9VEfy1Y81nfB7hIJClhHbOs34wxBnnGLLJdGbp/640?wx_fmt=svg&amp;random=0.3993059497784317&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span>&nbsp;<span style="color: #e6c07b;line-height: 26px;">ThreadPoolExecutorMdcWrapper</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">extends</span>&nbsp;<span style="color: #e6c07b;line-height: 26px;">ThreadPoolExecutor</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="color: #61aeee;line-height: 26px;">ThreadPoolExecutorMdcWrapper</span><span style="line-height: 26px;">(<span style="color: #c678dd;line-height: 26px;">int</span>&nbsp;corePoolSize,&nbsp;<span style="color: #c678dd;line-height: 26px;">int</span>&nbsp;maximumPoolSize,&nbsp;<span style="color: #c678dd;line-height: 26px;">long</span>&nbsp;keepAliveTime,&nbsp;TimeUnit&nbsp;unit,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BlockingQueue&lt;Runnable&gt;&nbsp;workQueue)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">super</span>(corePoolSize,&nbsp;maximumPoolSize,&nbsp;keepAliveTime,&nbsp;unit,&nbsp;workQueue);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="color: #61aeee;line-height: 26px;">ThreadPoolExecutorMdcWrapper</span><span style="line-height: 26px;">(<span style="color: #c678dd;line-height: 26px;">int</span>&nbsp;corePoolSize,&nbsp;<span style="color: #c678dd;line-height: 26px;">int</span>&nbsp;maximumPoolSize,&nbsp;<span style="color: #c678dd;line-height: 26px;">long</span>&nbsp;keepAliveTime,&nbsp;TimeUnit&nbsp;unit,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BlockingQueue&lt;Runnable&gt;&nbsp;workQueue,&nbsp;ThreadFactory&nbsp;threadFactory)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">super</span>(corePoolSize,&nbsp;maximumPoolSize,&nbsp;keepAliveTime,&nbsp;unit,&nbsp;workQueue,&nbsp;threadFactory);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="color: #61aeee;line-height: 26px;">ThreadPoolExecutorMdcWrapper</span><span style="line-height: 26px;">(<span style="color: #c678dd;line-height: 26px;">int</span>&nbsp;corePoolSize,&nbsp;<span style="color: #c678dd;line-height: 26px;">int</span>&nbsp;maximumPoolSize,&nbsp;<span style="color: #c678dd;line-height: 26px;">long</span>&nbsp;keepAliveTime,&nbsp;TimeUnit&nbsp;unit,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BlockingQueue&lt;Runnable&gt;&nbsp;workQueue,&nbsp;RejectedExecutionHandler&nbsp;handler)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">super</span>(corePoolSize,&nbsp;maximumPoolSize,&nbsp;keepAliveTime,&nbsp;unit,&nbsp;workQueue,&nbsp;handler);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="color: #61aeee;line-height: 26px;">ThreadPoolExecutorMdcWrapper</span><span style="line-height: 26px;">(<span style="color: #c678dd;line-height: 26px;">int</span>&nbsp;corePoolSize,&nbsp;<span style="color: #c678dd;line-height: 26px;">int</span>&nbsp;maximumPoolSize,&nbsp;<span style="color: #c678dd;line-height: 26px;">long<

IDEA 注释模板,惊艳了!动作要快,姿势要帅!

作者:微信小助手

<section style="margin-bottom: 15px;white-space: normal;outline: 0px;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2em;visibility: visible;"> <span style="outline: 0px;font-size: 14px;visibility: visible;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">一、类注释</span> </section> <section style="padding-top: 8px;padding-bottom: 8px;white-space: normal;outline: 0px;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-align: left;line-height: 2em;visibility: visible;"> <span style="outline: 0px;font-size: 14px;visibility: visible;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">打开 IDEA 的&nbsp;</span> <code style="outline: 0px;visibility: visible;"><span style="outline: 0px;font-size: 14px;visibility: visible;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">Settings</span></code> <span style="outline: 0px;font-size: 14px;visibility: visible;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">,点击&nbsp;</span> <code style="outline: 0px;visibility: visible;"><span style="outline: 0px;font-size: 14px;visibility: visible;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">Editor--&gt;File and Code Templates</span></code> <span style="outline: 0px;font-size: 14px;visibility: visible;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">,点击右边&nbsp;</span> <code style="outline: 0px;visibility: visible;"><span style="outline: 0px;font-size: 14px;visibility: visible;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">File</span></code> <span style="outline: 0px;font-size: 14px;visibility: visible;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">&nbsp;选项卡下面的</span> <code style="outline: 0px;visibility: visible;"><span style="outline: 0px;font-size: 14px;visibility: visible;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">Class</span></code> <span style="outline: 0px;font-size: 14px;visibility: visible;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">,在其中添加图中红框内的内容:</span> </section> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" mpa-preserve="t" mpa-from-tpl="t" style="white-space: normal;outline: 0px;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);visibility: visible;"> <pre style="outline: 0px;background: none;visibility: visible;"> <section style="margin-bottom: 15px;padding: 5.20625px;outline: 0px;border-radius: 4px;font-size: 0.85em;background: rgb(248, 248, 248);overflow-x: auto;white-space: nowrap;line-height: 2em;visibility: visible;"> <span style="outline: 0px;font-size: 13px;visibility: visible;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">/**<br mpa-from-tpl="t" style="outline: 0px;visibility: visible;">&nbsp;* @author jitwxs<br mpa-from-tpl="t" style="outline: 0px;visibility: visible;">&nbsp;* @date ${YEAR}年${MONTH}月${DAY}日 ${TIME}<br mpa-from-tpl="t" style="outline: 0px;visibility: visible;">&nbsp;*<span style="outline: 0px;color: rgb(0, 153, 38);background: rgba(0, 0, 0, 0);width: 7px;visibility: visible;">/</span></span> </section></pre> </section> <section style="white-space: normal;outline: 0px;letter-spacing: 0.544px;color: rgb(74, 74, 74);font-size: 16px;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;background-color: rgb(255, 255, 255);text-align: center;visibility: visible;"> <span style="outline: 0px;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;font-size: 20px;background-color: rgb(255, 251, 0);color: rgb(0, 0, 0);visibility: visible;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"><strong style="outline: 0px;visibility: visible;"></strong></span> </section> <section style="white-space: normal;outline: 0px;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);visibility: visible;"> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;letter-spacing: 0.544px;display: flex;flex-direction: column;justify-content: center;align-items: center;visibility: visible;"> <img class="rich_pages wxw-img" data-fileid="305504136" data-ratio="0.6972386587771203" src="/upload/e635fdffcec56eb4a7256e817b62fe30.png" data-type="png" data-w="1014" style="margin-right: auto;margin-left: auto;outline: 0px;display: block;box-sizing: border-box !important;visibility: visible !important;width: 677px !important;"> </figure> </section> <section style="white-space: normal;outline: 0px;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);visibility: visible;"> <br style="outline: 0px;visibility: visible;"> </section> <section style="padding-top: 8px;padding-bottom: 8px;white-space: normal;outline: 0px;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-align: left;line-height: 2em;visibility: visible;"> <span style="outline: 0px;font-size: 14px;visibility: visible;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">在我提供的示例模板中,说明了作者和时间,IDEA 支持的所有的模板参数在下方的&nbsp;</span> <code style="outline: 0px;visibility: visible;"><span style="outline: 0px;font-size: 14px;visibility: visible;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">Description</span></code> <span style="outline: 0px;font-size: 14px;visibility: visible;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">&nbsp;中被列出来。</span> </section> <section style="padding-top: 8px;padding-bottom: 8px;white-space: normal;outline: 0px;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-align: left;line-height: 2em;visibility: visible;"> <span style="outline: 0px;font-size: 14px;visibility: visible;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">保存后,当你创建一个新的类的时候就会自动添加类注释。如果你想对接口也生效,同时配置上图中的</span> <code style="outline: 0px;visibility: visible;"><span style="outline: 0px;font-size: 14px;visibility: visible;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">Interface</span></code> <span style="outline: 0px;font-size: 14px;visibility: visible;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">&nbsp;项即可。</span> </section> <section style="margin-top: 5px;margin-bottom: 5px;white-space: normal;outline: 0px;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;font-size: 16px;text-align: left;background-color: rgb(255, 255, 255);line-height: 26px;color: rgb(1, 1, 1);visibility: visible;"> <a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzI4NTM1NDgwNw==&amp;mid=2247508609&amp;idx=1&amp;sn=4cebafadddef99fcd35ee19a0d9ae089&amp;scene=21#wechat_redirect" textvalue="内测福利,不要错过点击下面图片,深度了解" linktype="text" imgurl="" imgdata="null" tab="innerlink" data-linktype="2" wah-hotarea="click" style="color: rgb(255, 41, 65);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;outline: 0px;font-size: 24px;visibility: visible;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"><span style="outline: 0px;visibility: visible;"><p style="outline: 0px;text-align: center;visibility: visible;"><strong style="outline: 0px;visibility: visible;"><span style="outline: 0px;color: rgb(0, 82, 255);visibility: visible;">内测福利,不要错过</span></strong></p><p style="outline: 0px;text-align: center;visibility: visible;"><br style="outline: 0px;visibility: visible;"></p><p style="outline: 0px;text-align: center;visibility: visible;"><strong style="outline: 0px;visibility: visible;"><span style="outline: 0px;font-size: 15px;visibility: visible;">点击下面图片,深度了解</span></strong></p></span></a> <a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzI4NTM1NDgwNw==&amp;mid=2247508457&amp;idx=1&amp;sn=b91a38f9e48e1fd1e7b25510e20afa33&amp;scene=21#wechat_redirect" textvalue="内测福利,不要错过点击下面图片,深度了解" linktype="text" imgurl="" imgdata="null" tab="innerlink" data-linktype="2" wah-hotarea="click" style="color: rgb(255, 41, 65);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;outline: 0px;font-size: 24px;visibility: visible;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"><span style="outline: 0px;visibility: visible;"><p style="outline: 0px;text-align: center;visibility: visible;"><br style="outline: 0px;visibility: visible;"></p></span></a> </section> <section style="margin-top: 5px;margin-bottom: 5px;white-space: normal;outline: 0px;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;font-size: 16px;text-align: left;background-color: rgb(255, 255, 255);line-height: 26px;color: rgb(1, 1, 1);visibility: visible;"> <span style="outline: 0px;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;letter-spacing: 0.544px;font-size: 15px;visibility: visible;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"><p style="outline: 0px;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;letter-spacing: 0.544px;text-align: center;visibility: visible;"><a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzI4NTM1NDgwNw==&amp;mid=2247508609&amp;idx=1&amp;sn=4cebafadddef99fcd35ee19a0d9ae089&amp;scene=21#wechat_redirect" textvalue="你已选中了添加链接的内容" linktype="text" imgurl="" imgdata="null" tab="innerlink" data-linktype="1" wah-hotarea="click" style="outline: 0px;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;visibility: visible;"><span class="js_jump_icon h5_image_link" data-positionback="static" style="font-size: 15px;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;let

SpringBoot中如何实现全链路调用日志跟踪?这方法才优雅!

作者:微信小助手

<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="padding-right: 10px;padding-left: 10px;text-align: left;line-height: 1.6;letter-spacing: 0.034em;color: rgb(63, 63, 63);font-size: 16px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;"> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 23px;color: rgb(74, 74, 74);line-height: 1.75em;">通过本文将了解到什么是MDC、MDC应用中存在的问题、如何解决存在的问题</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/eQPyBffYbueAY5zdqpjc4klzhtzQfuDqhkQb8cyrklqibWTVDvicNicWU4k0gDvib7BXYsexsQD0XQNyPgd5UVOY5g/640?wx_fmt=png&quot;);background-size: 15px 15px;display: inline-block;width: 15px;height: 15px;line-height: 15px;margin-bottom: -1px;"></span><span style="display: none;"></span><span style="font-size: 16px;display: inline-block;margin-left: 8px;color: rgb(60, 112, 198);">MDC介绍</span><span style="display: none;"></span></h3> <h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;"><span style="display: none;"></span>简介:<span style="display: none;"></span></h5> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 23px;color: rgb(74, 74, 74);line-height: 1.75em;">MDC(Mapped Diagnostic Context,映射调试上下文)是 log4j 、logback及log4j2 提供的一种方便在多线程条件下记录日志的功能。<strong style="line-height: 1.75em;">MDC</strong>&nbsp;可以看成是一个<strong style="line-height: 1.75em;">与当前线程绑定的哈希表</strong>,可以往其中添加键值对。MDC 中包含的内容可以<strong style="line-height: 1.75em;">被同一线程中执行的代码所访问</strong>。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 23px;color: rgb(74, 74, 74);line-height: 1.75em;">当前线程的子线�

本机号码一键登录原理与应用

作者:微信小助手

<section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;" data-mpa-powered-by="yiban.io"> <span style="font-size: 14px;">很多APP的目前都支持“本机号码一键登录”功能。本机号码一键登录是基于运营商独有网关认证能力推出的账号认证产品。用户只需一键授权,即可实现以本机号码注册/登录,相比先前的短信验证码流程体验更优。</span> </section> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;">目前市面上有很多厂商提供三网验证的服务,只不过是对三大运营商的包装。要了解具体的原理可直接看三大运营商相关的介绍。</span> </section> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-weight: bold;text-align: center;font-size: 14px;">中国移动</span> </section> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;">中国移动号码认证服务支支持移动、联通、电信三网号码。主要产品功能:</span> </section> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin: 8px;padding-left: 25px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);list-style-type: square;"> <li style="outline: 0px;font-size: 14px;"> <section style="margin-top: 5px;outline: 0px;color: rgb(1, 1, 1);margin-bottom: 20px;line-height: 2em;"> <span style="font-size: 14px;">一键登录:依托运营商的移动通信网络,采用通信网关取号技术,准确识别用户流量卡归属的手机号码。在获得用户授权后,App端(适配iOS和Android)可使用本机号码实现一键免密登录。</span> </section></li> <li style="outline: 0px;font-size: 14px;"> <section style="margin-top: 5px;outline: 0px;color: rgb(1, 1, 1);margin-bottom: 20px;line-height: 2em;"> <span style="font-size: 14px;">本机号码校验:通过SDK/JSSDK提供的本机号码校验功能,调用网关鉴权方式,验证用户输入的手机号码或后台绑定的手机号码是否为本机流量卡归属号码,保证机卡不分离,用于快捷登入和安全风控等场景。本机号码校验现已适配iOS、Android、H5、小程序、快应用。</span> </section></li> </ul> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;">获取手机号码(一键登录):</span> </section> <section style="margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <figure data-tool="mdnice编辑器" style=""> <img class="rich_pages wxw-img" data-cropselx1="0" data-cropselx2="554" data-cropsely1="0" data-cropsely2="357" data-ratio="0.644404332129964" src="/upload/b8e88f7f9153f1c48559648b6453bb5a.png" data-type="png" data-w="554" style="outline: 0px;border-width: 0px;border-style: initial;border-color: initial;display: block;box-shadow: rgba(170, 170, 170, 0.48) 0px 0px 6px 0px;border-radius: 4px;width: 554px;height: 357px;top: 0px;left: 0px;right: 0px;bottom: 0px;margin: 0px;box-sizing: border-box !important;visibility: visible !important;"> </figure> </section> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;">本机号码校验:</span> </section> <section style="margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <figure data-tool="mdnice编辑器" style=""> <img class="rich_pages wxw-img" data-cropselx1="0" data-cropselx2="554" data-cropsely1="0" data-cropsely2="317" data-ratio="0.572202166064982" src="/upload/9f57ee082aa700340850121cc2f243c5.png" data-type="png" data-w="554" style="outline: 0px;border-width: 0px;border-style: initial;border-color: initial;display: block;box-shadow: rgba(170, 170, 170, 0.48) 0px 0px 6px 0px;border-radius: 4px;width: 554px;height: 317px;box-sizing: border-box !important;visibility: visible !important;top: 0px;left: 0px;margin: 10px 0px 0px;right: 0px;bottom: 0px;"> </figure> </section> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;"><strong style="outline: 0px;">取号方法</strong></span> </section> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;">通过调用安卓的getPhoneInfo或iOS的getPhoneNumberCompletion,在用户无感知的情况下进行网络判断、蜂窝数据网络切换和网关取号等操作(以上操作均需消耗一定时间),返回取号是否成功的结果。</span> </section> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin: 8px;padding-left: 25px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);list-style-type: square;"> <li style="outline: 0px;font-size: 14px;"> <section style="margin-top: 5px;outline: 0px;color: rgb(1, 1, 1);margin-bottom: 20px;line-height: 2em;"> <span style="font-size: 14px;">取号所需网络环境:运营商取号能力是通过数据网关实现,取号过程须在数据流量打开的情况下才能进行。因此,用户如果关闭数据流量将无法取号;若当前信号弱或者网络有干扰时,时延会高于平均值,取号成功率降低。</span> </section></li> <li style="outline: 0px;font-size: 14px;"> <section style="margin-top: 5px;outline: 0px;color: rgb(1, 1, 1);margin-bottom: 20px;line-height: 2em;"> <span style="font-size: 14px;">超时设置:SDK默认超时设置为8000ms,同时提供设置取号超的方法:安卓通过setOverTime设置,iOS通过setTimeoutInterval设置。</span> </section></li> <li style="outline: 0px;font-size: 14px;"> <section style="margin-top: 5px;outline: 0px;color: rgb(1, 1, 1);margin-bottom: 20px;line-height: 2em;"> <span style="font-size: 14px;">运营商判断:SDK提供判断用户当前网络状态和流量卡所属运营商的方法,通过调用安卓SDK的getNetworkType或iOS的networkInfo可获得以上信息,以便对不同用户选择不同的运营商的SDK进行取号或选择不同的登录方式。</span> </section></li> <li style="outline: 0px;font-size: 14px;"> <section style="margin-top: 5px;outline: 0px;color: rgb(1, 1, 1);margin-bottom: 20px;line-height: 2em;"> <span style="font-size: 14px;">关于取号缓存:应用取号或者授权成功后,SDK将取号的一个临时凭证缓存在本地,缓存能有效提高取号成功率、降低时延,并允许用户在未开启蜂窝网络时成功取号。SDK本身对缓存有处理逻辑,在某些场景下(如换卡)会让缓存提前失效,但若应用对安全性要求较高,也可以通过SDK提供的方法(安卓的delScrip和iOS的delectScrip)让缓存马上失效。</span> </section></li> </ul> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;"><strong style="outline: 0px;">本机号码校验</strong></span> </section> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;">通过调用安卓的mobileAuth或iOS的mobileAuthCompletion方法,可在不拉起授权页的情况下获得token。此时获得的token不能用于兑换用户的完整号码,只能用于校验本机号码与待校验号码的一致性。</span> </section> <section style="margin: 5px 8px 20px;outline: 0px;color: rgb(1, 1, 1);line-height: 2em;"> <span style="font-size: 14px;">预取号:安卓的getPhoneInfo或iOS的getPhoneNumberCompletion所形成取号缓存scrip同样适用于本机号码校验,可提前进行取号以提高后续获取token的效率。</span> </section> <section style="margin: 5px 8px 20px;outline: 0px;color: rgb(1, 1, 1);line-height: 2em;"> <span style="font-size: 14px;">适用场景:可在用户无感知的情况下校验本机号码与待校验号码的一致性,适用于所有基于手机号码进行风控的场景。</span> </section> <section style="margin: 5px 8px 20px;outline: 0px;color: rgb(1, 1, 1);text-align: left;line-height: 2em;"> <span style="color: rgb(0, 0, 0);font-weight: bold;text-align: center;font-size: 16px;">中国电信</span> </section> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;">中国电信天翼账号开放平台提供了:免密登录、手机号码认证、二次卡校验等服务。目前只支持中国电信用户。</span> </section> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;"><strong style="outline: 0px;">免密认证:</strong>&nbsp;天翼账号免密认证方案,依托运营商的移动数据网络,采用“通信网关预登录”及 SIM卡识别等技术,准确识别用户手机号码,实现一键登录,并可有效规避短信验证码泄露风险。</span> </section> <section style="margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <figure data-tool="mdnice编辑器" style=""> <img class="rich_pages wxw-img" data-cropselx1="0" data-cropselx2="554" data-cropsely1="0" data-cropsely2="235" data-ratio="0.42418772563176893" src="/upload/12689ce8e5873e1c038aab1e6f70b66b.png" data-type="png" data-w="554" style="outline: 0px;border-width: 0px;border-style: initial;border-color: initial;display: block;box-shadow: rgba(170, 170, 170, 0.48) 0px 0px 6px 0px;border-radius: 4px;width: 554px;height: 235px;box-sizing: border-box !important;visibility: visible !important;top: 0px;left: 0px;margin: 10px 0px 0px;right: 0px;bottom: 0px;"> </figure> <figure data-tool="mdnice编辑器" style=""> <img class="rich_pages wxw-img" data-cropselx1="0" data-cropselx2="554" data-cropsely1="0" data-cropsely2="270" data-ratio="0.48736462093862815" src="/upload/58eccadfbed79bc84a34836d1127aef5.png" data-type="png" data-w="554" style="outline: 0px;border-width: 0px;border-style: initial;border-color: initial;display: block;box-shadow: rgba(170, 170, 170, 0.48) 0px 0px 6px 0px;border-radius: 4px;width: 554px;height: 270px;box-sizing: border-box !important;visibility: visible !important;top: 0px;left: 0px;margin: 10px 0px 0px;right: 0px;bottom: 0px;"> </figure> </section> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;"><strong style="outline: 0px;">手机号码校验</strong>&nbsp;:确认本机号码信息是否为当前用户本机号码。依托运营商的移动数据网络,采用“通信网关预登录”及 SIM卡识别等技术,判断用户输入的手机号与本机号码是否一致。</span> </section> <section style="margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <figure data-tool="mdnice编辑器" style=""> <img class="rich_pages wxw-img" data-cropselx1="0" data-cropselx2="554" data-cropsely1="0" data-cropsely2="157" data-ratio="0.2833935018050541" src="/upload/64694ab313ab6a862c614d89c5ebcd75.png" data-type="png" data-w="554" style="outline: 0px;border-width: 0px;border-style: initial;border-color: initial;display: block;box-shadow: rgba(170, 170, 170, 0.48) 0px 0px 6px 0px;border-radius: 4px;width: 554px;height: 157px;box-sizing: border-box !important;visibility: visible !important;top: 0px;left: 0px;margin: 10px 0px 0px;right: 0px;bottom: 0px;"> </figure> <figure data-tool="mdnice编辑器" style=""> <img class="rich_pages wxw-img" data-cropselx1="0" data-cropselx2="554" data-cropsely1="0" data-cropsely2="171" data-ratio="0.30866425992779783" src="/upload/2db7dc5cf773291b9d74fc20b80eeafc.png" data-type="png" data-w="554" style="outline: 0px;border-width: 0px;border-style: initial;border-color: initial;display: block;box-shadow: rgba(170, 170, 170, 0.48) 0px 0px 6px 0px;border-radius: 4px;width: 554px;height: 171px;box-sizing: border-box !important;visibility: visible !important;top: 0px;left: 0px;margin: 10px 0px 0px;right: 0px;bottom: 0px;"> </figure> </section> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;"><strong style="outline: 0px;">二次卡校验</strong>&nbsp;:众所周知,三大运营商每月注销的手机号约有2000多万,为避免手机号资源浪费,运营商会先回收已注销的手机号,然后重新销售,重新销售的卡即为二次卡。如果用户更换了手机号,且未与原账号解绑,可能存在安全风险。天翼账号二次卡校验方案, 使用独有的运营商二次号数据库,可快速检测用户号码更换状态,保障号码旧用户隐私安全。</span> </section> <section> <figure data-tool="mdnice编辑器"> <img class="rich_pages wxw-img" data-cropselx1="0" data-cropselx2="554" data-cropsely1="0" data-cropsely2="151" data-ratio="0.27256317689530685" src="/upload/3396b22bc543462d3c8afd0caf958195.png" data-type="png" data-w="554" style="outline: 0px;border-width: 0px;border-style: initial;border-color: initial;display: block;box-shadow: rgba(170, 170, 170, 0.48) 0px 0px 6px 0px;border-radius: 4px;width: 554px;height: 151px;box-sizing: border-box !important;visibility: visible !important;top: 0px;left: 0px;margin: 10px 0px 0px;right: 0px;bottom: 0px;"> </figure> <figure data-tool="mdnice编辑器"> <img class="rich_pages wxw-img" data-cropselx1="0" data-cropselx2="554" data-cropsely1="0" data-cropsely2="247" data-ratio="0.44584837545126355" src="/upload/4450bb3f3db79ef6c57b1d7bc4fc6712.png" data-type="png" data-w="554" style="outline: 0px;border-width: 0px;border-style: initial;border-color: initial;display: block;box-shadow: rgba(170, 170, 170, 0.48) 0px 0px 6px 0px;border-radius: 4px;width: 554px;height: 247px;box-sizing: border-box !important;visibility: visible !important;top: 0px;left: 0px;margin: 10px 0px 0px;right: 0px;bottom: 0px;"> </figure> <p style="margin: 20px 8px;"><strong>中国联通</strong></p> </section> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;">中国联通通信创新能力平台提供了号码认证(一键登录)、匿名设备标识、匿名用户标识、空号识别、二次号验证、三要素验证等服务。</span> </section> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;"><strong style="outline: 0px;">号码认证</strong></span> </section> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;">依托运营商网关认证能力,面向互联网应用提供的本机手机号码一键注册登录及本机手机号码校验服务,支持APP、H5页面多场景应用。官方SDK,支持联通、移动、电信三网,智能化程度高,交互时间短,提升用户体验、提高拉新转化率;专利技术,性能可靠,降低空号注册登录、密码拦截盗取风险。</span> </section> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;">应用场景:</span> </section> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin: 8px;padding-left: 25px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);list-style-type: square;"> <li style="outline: 0px;font-size: 14px;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;line-height: 26px;color: rgb(1, 1, 1);"> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: black;margin-bottom: 20px;line-height: 2em;"> <span style="font-size: 14px;">一键登录</span> </section> </section></li> <ul class="list-paddingleft-1" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;outline: 0px;"> <li style="outline: 0px;list-style-type: circle;font-size: 14px;"> <section style="margin-top: 5px;outline: 0px;color: rgb(1, 1, 1);margin-bottom: 20px;line-height: 2em;"> <span style="font-size: 14px;">APP一键登录。手机在有蜂窝信号的环境中(若WIFI接入,SDK可瞬间切换至蜂窝信号再切回),可自动获取手机号码,帮助用户实现一键验证快捷登录,无需手动输入号码和短信验证,有利于提升用户体验,提高登录安全性。</span> </section></li> <li style="outline: 0px;list-style-type: circle;font-size: 14px;"> <section style="margin-top: 5px;outline: 0px;color: rgb(1, 1, 1);margin-bottom: 20px;line-height: 2em;"> <span style="font-size: 14px;">H5一键登录。适用于手机接入蜂窝信号时,H5页面登录场景,用户只需输入4位本机号码即可实现快捷登录,减少降登录等待时间。</span> </section></li> </ul> </ul> <section style="margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <figure data-tool="mdnice编辑器" style=""> <img class="rich_pages wxw-img" data-cropselx1="0" data-cropselx2="554" data-cropsely1="0" data-cropsely2="474" data-ratio="0.855595667870036" src="/upload/b2b770033bc8bcf3f253fd7771ba03b3.png" data-type="png" data-w="554" style="outline: 0px;border-width: 0px;border-style: initial;border-color: initial;display: block;box-shadow: rgba(170, 170, 170, 0.48) 0px 0px 6px 0px;border-radius: 4px;width: 554px;height: 474px;box-sizing: border-box !important;visibility: visible !important;top: 0px;left: 0px;margin: 10px 0px 0px;right: 0px;bottom: 0px;"> </figure> </section> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin: 8px;padding-left: 25px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);list-style-type: square;"> <li style="outline: 0px;font-size: 14px;"> <section style="margin-top: 5px;outline: 0px;color: rgb(1, 1, 1);margin-bottom: 20px;line-height: 2em;"> <span style="font-size: 14px;">本机校验。自动校验用户手机号与当前本机卡号的一致性,免输登录密码或短信验证码;适用于如手机号绑定、支付确认、积分兑换等需要具备安全校验能力的业务场景,提供仅限本机操作的安全风控机制。支持有蜂窝信号环境下的APP及正在使用蜂窝信号下的H5。</span> </section></li> </ul> <section style="margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <figure data-tool="mdnice编辑器" style=""> <img class="rich_pages wxw-img" data-cropselx1="0" data-cropselx2="554" data-cropsely1="0" data-cropsely2="474" data-ratio="0.855595667870036" src="/upload/a64ae9dcfd42d52f09bb37576444abbb.png" data-type="png" data-w="554" style="outline: 0px;border-width: 0px;border-style: initial;border-color: initial;display: block;box-shadow: rgba(170, 170, 170, 0.48) 0px 0px 6px 0px;border-radius: 4px;width: 554px;height: 474px;box-sizing: border-box !important;visibility: visible !important;top: 0px;left: 0px;margin: 10px 0px 0px;right: 0px;bottom: 0px;"> </figure> </section> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;"><strong style="outline: 0px;">匿名设备标识</strong></span> </section> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;">通过识别移动设备唯一ID,为客户提供基于用户和设备的标识方案,支持IOS和安卓系统,不依赖设备厂商,具备稳定性和唯一性,可关联安卓设备资产数据,帮助企业找回历史关联资产,实现基于用户画像的精准投放,有效识别设备篡改和营销作假,防止薅羊毛,避免金融风险等。</span> </section> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;">应用场景:</span> </section> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin: 8px;padding-left: 25px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);list-style-type: square;"> <li style="outline: 0px;font-size: 14px;"> <section style="margin-top: 5px;outline: 0px;color: rgb(1, 1, 1);margin-bottom: 20px;line-height: 2em;"> <span style="font-size: 14px;">风险识别:企业开展营销活动时,面对薅羊毛、黑产等,通过设备识别可有效识别判断参与用户,防止有限资源被无价值用户占用,支持APP/H5/小程序等全场景,覆盖安卓/IOS生态系统。适用于开展各类营销活动的企业,如电商、金融、游戏、生活等。</span> </section></li> <li style="outline: 0px;font-size: 14px;"> <section style="margin-top: 5px;outline: 0px;color: rgb(1, 1, 1);margin-bottom: 20px;line-height: 2em;"> <span style="font-size: 14px;">场景营销:企业可基于不同营销场景(APP/H5/小程序)下的用户标识,进行跨应用用户分析与画像生成,实现精准营销推送。适用于需分析用户偏好、阅读习惯的企业,如购物、新闻、视频、娱乐、阅读等.</span> </section></li> </ul> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;"><strong style="outline: 0px;">匿名用户标识</strong></span> </section> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;">通过手机用户的公私网IP返回唯一串码,可以在保护用户手机号不泄露的情况下,提供用户唯一标识(即伪码)方案。仅支持联通用户。</span> </section> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;">应用场景:</span> </section> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin: 8px;padding-left: 25px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);list-style-type: square;"> <li style="outline: 0px;font-size: 14px;"> <section style="margin-top: 5px;outline: 0px;color: rgb(1, 1, 1);margin-bottom: 20px;line-height: 2em;"> <span style="font-size: 14px;">会员营销:会员营销活动时,用户领取会团优惠,平台方通过联通唯一识别平台将手机号转换成伪码供商户进行维系和发放。适用于入住商户无法获取平台用户手机号的场景。</span> </section></li> </ul> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;"><strong style="outline: 0px;">空号识别</strong></span> </section> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;">识别号码是否为真实有效的开机使用号码,对于不可达号码(例如关机、养卡等情况)采取相应的运营措施。识别过程一秒以内,支持大规模并发查询,且对用户无感知。帮助企业快速、高效、精准开展营销、维系等商业活动,减少营销成本。</span> </section> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;">应用场景:</span> </section> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin: 8px;padding-left: 25px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);list-style-type: square;"> <li style="outline: 0px;font-size: 14px;"> <section style="margin-top: 5px;outline: 0px;color: rgb(1, 1, 1);margin-bottom: 20px;line-height: 2em;"> <span style="font-size: 14px;">外呼中心:用于外呼中心,回访或者推介产品之前先对用户手机状态进行有效识别,关机、离网及不在服务区用户免拨叫,节省人力物力。</span> </section></li> <li style="outline: 0px;font-size: 14px;"> <section style="margin-top: 5px;outline: 0px;color: rgb(1, 1, 1);margin-bottom: 20px;line-height: 2em;"> <span style="font-size: 14px;">存量用户维系:用于检测用户手机是否处于在网状态,便于企业精准开展后续营销活动。例如优惠券发放、权益下达等,为真实客户送权益,送利益。</span> </section></li> <li style="outline: 0px;font-size: 14px;"> <section style="margin-top: 5px;outline: 0px;color: rgb(1, 1, 1);margin-bottom: 20px;line-height: 2em;"> <span style="font-size: 14px;">注册用户清洗:对注册会员的号码进行检测,对短期内高频次的注册行为进行监控,对可疑号码进行监控,及时清理批量注册的垃圾用户和数据、被占用数据,将恶意注册用户拒之门外,防止“薅羊毛党”恶意套利现象。使用号码检测功能,可以减少企业客户的营销维护成本,保护真实用户的权益。</span> </section></li> </ul> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;"><strong style="outline: 0px;">二次号验证</strong></span> </section> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;">次号验证产品是指核验手机号码在指定时间之后是否重新开户。</span> </section> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;">应用场景:</span> </section> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin: 8px;padding-left: 25px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);list-style-type: square;"> <li style="outline: 0px;font-size: 14px;"> <section style="margin-top: 5px;outline: 0px;color: rgb(1, 1, 1);margin-bottom: 20px;line-height: 2em;"> <span style="font-size: 14px;">注册/登录/密码找回:针对注册/登录/密码找回等场景,企业可通过使用联通二次号码验证产品识别当前注册登录号码是否为二次放号,从而避免二次放号用户使用原号码账号可能带来的用户隐私泄露和经济损失。</span> </section></li> </ul> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;"><strong style="outline: 0px;">三要素验证</strong></span> </section> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;">三要素验证产品提供联通用户的姓名、身份证号、手机号三要素的一致性核验服务。</span> </section> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);margin-bottom: 20px;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <span style="font-size: 14px;">应用场景:</span> </section> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin: 8px;padding-left: 25px;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);list-style-type: square;"> <li style="outline: 0px;font-size: 14px;"> <section style="margin-top: 5px;outline: 0px;color: rgb(1, 1, 1);margin-bottom: 20px;line-height: 2em;"> <span style="font-size: 14px;">实名认证:针对金融、婚恋等应用系统中的实名注册场景,企业可通过联通三要素验证产品识别用户身份真实性和信息一致性,有助于防范用户风险。</span> </section></li> <li style="outline: 0px;font-size: 14px;"> <section style="margin-top: 5px;outline: 0px;color: rgb(1, 1, 1);margin-bottom: 20px;line-height: 2em;"> <span style="font-size: 14px;">贷前审核:针对借贷、信用卡申请等金融场景,企业可以通过使用联通三要素验证产品识别申请用户信息真实度,助力用户风险评估和贷款决策。</span> </section></li> </ul>

JavaScript 逆向爬虫中的浏览器调试常见技巧

作者:微信小助手

<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="line-height: 1.6;word-break: break-word;overflow-wrap: break-word;text-align: left;padding: 5px;font-size: 16px;color: rgb(53, 53, 53);word-spacing: 0.8px;letter-spacing: 0.8px;border-radius: 16px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;" data-mpa-powered-by="yiban.io"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">现在越来越多的网站也已经应用了这些技术对其数据接口进行了保护,在做爬虫时如果我们遇到了这种情况,我们可能就不得不硬着头皮来去想方设法找出其中隐含的关键逻辑了,这个过程我们可以称之为 JavaScript 逆向。<br></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">既然我们要做 JavaScript 逆向,那少不了要用到浏览器的开发者工具,因为网页是在浏览器中加载的,所以多数的调试过程也是在浏览器中完成的。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">工欲善其事,必先利其器。本节我们先来基于 Chrome 浏览器介绍一下浏览器开发者工具的使用。但由于开发者工具功能十分复杂,本节主要介绍对 JavaScript 逆向有一些帮助的功能,学会了这些,我们在做 JavaScript 逆向调试的过程会更加得心应手。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">本节我们以一个示例网站 <span style="color: rgb(255, 76, 65);">https://spa2.scrape.center/</span> 来做演示,用这个示例来介绍浏览器开发者工具各个面版的用法。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">1. 面板介绍</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">首先我们用 Chrome 浏览器打开示例网站,页面如图所示:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.5757109915449654" src="/upload/5ef36897c01439619b4d729f9c655f2a.png" data-type="png" data-w="2602" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;"> 示例网站页面 </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">接下来打开开发者工具,我们会看到类似图 xx 所示的结果。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.5757109915449654" src="/upload/cf2deb1c834e580c8b929970c71fab2c.png" data-type="png" data-w="2602" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;"> 打开开发者工具 </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">这里可以看到多个面板标签,如 Elements、Console、Sources 等,这就是开发者工具的一个个面板,功能丰富而又强大,先对面板作下简单的介绍:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Elements:元素面板,用于查看或修改当前网页 HTML 节点的属性、CSS 属性、监听事件等等,HTML 和 CSS 都可以即时修改和即时显示。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Console:控制台面板,用于查看调试日志或异常信息。另外我们还可以在控制台输入 JavaScript 代码,方便调试。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Sources:源代码面板,用于查看页面的 HTML 文件源代码、JavaScript 源代码、CSS 源代码,还可以在此面板对 JavaScript 代码进行调试,比如添加和修改 JavaScript 断点,观察 JavaScript 变量变化等。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Network:网络面板,用于查看页面加载过程中的各个网络请求,包括请求、响应等各个详情。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Performance:性能面板,用于记录和分析页面在运行时的所有活动,比如 CPU 占用情况,呈现页面性能分析结果, </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Memory:内存面板,用于记录和分析页面占用内存情况,如查看内存占用变化,查看 JavaScript 对象和 HTML 节点的内存分配。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Application:应用面板,用于记录网站加载的所有资源信息,如存储、缓存、字体、图片等,同时也可以对一些资源进行修改和删除。 </section></li> <li> <section style="margin-

MySQL缓冲池(buffer pool),终于懂了!!!(收藏)

作者:微信小助手

<p style="line-height: 1.75em;" data-mpa-powered-by="yiban.io"><img class="rich_pages wxw-img" data-ratio="0.3486238532110092" data-s="300,640" src="/upload/c5c11468c914eb166dbbc2ebde820672.png" data-type="png" data-w="218" style=""></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">应用系统分层架构,为了加速数据访问,会把最常访问的数据,放在<strong>缓存</strong></span><span style="letter-spacing: 1px;font-size: 12px;">(cache)</span><span style="font-size: 15px;letter-spacing: 1px;">里,避免每次都去访问数据库。<br></span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">操作系统,会有<strong>缓冲池</strong></span><span style="letter-spacing: 1px;font-size: 12px;">(buffer pool)</span><span style="font-size: 15px;letter-spacing: 1px;">机制,避免每次访问磁盘,以加速数据的访问。</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">MySQL作为一个存储系统,同样具有<strong>缓冲池</strong></span><span style="letter-spacing: 1px;font-size: 12px;">(buffer pool)</span><span style="font-size: 15px;letter-spacing: 1px;">机制,以避免每次查询数据都进行磁盘IO。</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;"><br></span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">今天,和大家聊一聊InnoDB的缓冲池。</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;">InnoDB的缓冲池缓存什么?有什么用?</span></strong></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">缓存表数据与索引数据</span><span style="font-size: 15px;letter-spacing: 1px;">,把磁盘上的数据加载到缓冲池,避免每次访问都进行磁盘IO,起到加速访问的作用。</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">速度快,那<strong>为啥不把所有数据都放到缓冲池里</strong>?</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">凡事都具备两面性,抛开数据易失性不说,访问快速的反面是存</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">储容量小</span><span style="font-size: 15px;letter-spacing: 1px;">:</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(1)缓存访问快,但容量小,数据库存储了200G数据,缓存容量可能只有64G;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(2)内存访问快,但容量小,买一台笔记本磁盘有2T,内存可能只有16G;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">因此,</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">只能把“最热”的数据放到“最近”的地方</span><span style="font-size: 15px;letter-spacing: 1px;">,以“最大限度”的降低磁盘访问。</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;">如何管理与淘汰缓冲池,使得性能最大化呢?</span></strong></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">在介绍具体细节之前,先介绍下“</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">预读</span><span style="font-size: 15px;letter-spacing: 1px;">”的概念。</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;">什么是预读?</span></strong></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">磁盘读写,并不是按需读取,而是按页读取,</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">一次至少读一页数据</span><span style="font-size: 15px;letter-spacing: 1px;">(一般是4K),如果未来要读取的数据就在页中,就能够省去后续的磁盘IO,提高效率。</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;">预读为什么有效?</span></strong></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">数据访问,通常都遵循“集中读写”的原则,使用一些数据,大概率会使用附近的数据,这就是所谓的“</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">局部性原理</span><span style="font-size: 15px;letter-spacing: 1px;">”,它表明提前加载是有效的,确实能够减少磁盘IO。</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;">按页(4K)读取,和InnoDB的缓冲池设计有啥关系?</span></strong></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(1)磁盘访问按页读取能够提高性能,所以</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">缓冲池一般也是按页缓存数据</span><span style="font-size: 15px;letter-spacing: 1px;">;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(2)预读机制启示了我们,能</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">把一些“可能要访问”的页提前加入缓冲池</span><span style="font-size: 15px;letter-spacing: 1px;">,避免未来的磁盘IO操作;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;">InnoDB是以什么算法,来管理这些缓冲页呢?</span></strong></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">最容易想到的,就是</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">LRU</span><span style="letter-spacing: 1px;color: rgb(255, 76, 0);font-size: 12px;">(Least recently used)</span><span style="font-size: 15px;letter-spacing: 1px;">。</span></p> <p style="line-height: 1.75em;"><span style="color: rgb(0, 82, 255);"><em><span style="font-size: 15px;letter-spacing: 1px;">画外音:memcache,OS都会用LRU来进行页置换管理,但MySQL的玩法并不一样。</span></em></span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;">传统的LRU是如何进行缓冲页管理?</span></strong></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">最常见的玩法是,</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">把入缓冲池的页放到LRU的头部,作为最近访问的元素</span><span style="font-size: 15px;letter-spacing: 1px;">,从而最晚被淘汰。这里又分两种情况:</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(1)<strong>页已经在缓冲池里</strong>,那就只做</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">“移至”LRU头部</span><span style="font-size: 15px;letter-spacing: 1px;">的动作,而没有页被淘汰;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(2)<strong>页不在缓冲池里</strong>,除了做</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">“放入”LRU头部</span><span style="font-size: 15px;letter-spacing: 1px;">的动作,还要做</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">“淘汰”LRU尾部</span><span style="font-size: 15px;letter-spacing: 1px;">页的动作;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><img class="rich_pages wxw-img" data-ratio="0.22691292875989447" data-s="300,640" src="/upload/acf35601d9dd11bb606e7cef7b8755c3.png" data-type="png" data-w="379" style=""></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">如上图,假如管理缓冲池的LRU长度为10,缓冲了页号为1,3,5…,40,7的页。</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">假如,接下来要访问的数据在页号为4的页中:</span></p> <p style="line-height: 1.75em;"><img class="rich_pages wxw-img" data-ratio="0.246684350132626" data-s="300,640" src="/upload/b54361aff9ed0fe47f4bc09319a6186.png" data-type="png" data-w="377" style=""></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(1)页号为4的页,本来就在缓冲池里;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(2)把页号为4的页,放到LRU的头部即可,没有页被淘汰;</span></p> <p style="line-height: 1.75em;"><span style="color: rgb(0, 82, 255);"><em><span style="font-size: 15px;letter-spacing: 1px;">画外音:为了减少数据移动,LRU一般用链表实现。</span></em></span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">假如,再接下来要访问的数据在页号为50的页中:</span></p> <p style="line-height: 1.75em;"><img class="rich_pages wxw-img" data-ratio="0.20518867924528303" data-s="300,640" src="/upload/209919f2e538e0ca916b89f85ce47113.png" data-type="png" data-w="424" style=""></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(1)页号为50的页,原来不在缓冲池里;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(2)把页号为50的页,放到LRU头部,同时淘汰尾部页号为7的页;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;">传统的LRU缓冲池算法十分直观</span></strong><span style="font-size: 15px;letter-spacing: 1px;">,OS,memcache等很多软件都在用,<strong>MySQL为啥这么矫情,不能直接用呢?</strong></span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">这里有两个问题:</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(1)</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">预读失效</span><span style="font-size: 15px;letter-spacing: 1px;">;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(2)</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">缓冲池污染</span><span style="font-size: 15px;letter-spacing: 1px;">;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;">什么是预读失效?</span></strong></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">由于预读</span><span style="letter-spacing: 1px;font-size: 12px;">(Read-Ahead)</span><span style="font-size: 15px;letter-spacing: 1px;">,提前把页放入了缓冲池,但最终MySQL并没有从页中读取数据,称为预读失效。</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;">如何对预读失效进行优化?</span></strong></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">要优化预读失效,思路是:</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(1)让预读失败的页,停留在缓冲池LRU里的时间尽可能短;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(2)让真正被读取的页,才挪到缓冲池LRU的头部;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">以保证,真正被读取的热数据留在缓冲池里的时间尽可能长。</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">具体方法是:</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(1)将LRU分为两个部分:</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">&nbsp;&nbsp;&nbsp;&nbsp;- 新生代</span><span style="letter-spacing: 1px;font-size: 12px;">(new sublist)</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">&nbsp;&nbsp;&nbsp;&nbsp;- 老生代</span><span style="letter-spacing: 1px;font-size: 12px;">(old sublist)</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(2)</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">新老生代收尾相连</span><span style="font-size: 15px;letter-spacing: 1px;">,即:新生代的尾</span><span style="letter-spacing: 1px;font-size: 12px;">(tail)</span><span style="font-size: 15px;letter-spacing: 1px;">连接着老生代的头</span><span style="letter-spacing: 1px;font-size: 12px;">(head)</span><span style="font-size: 15px;letter-spacing: 1px;">;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(3)新页(例如被预读的页)加入缓冲池时,只加入到老生代头部:</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;&nbsp;&nbsp;&nbsp;- 如果数据真正被读取(</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">预读成功</span><span style="font-size: 15px;letter-spacing: 1px;">),</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">才会加入到新生代的头部</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;&nbsp;&nbsp;&nbsp;- 如果数据</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">没有被读取</span><span style="font-size: 15px;letter-spacing: 1px;">,则会比新生代里的“热数据页”更早被淘汰出缓冲池</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><img class="rich_pages wxw-img" data-ratio="0.40102827763496146" data-s="300,640" src="/upload/329760bb0d708bc7467df6e0e047ae3f.png" data-type="png" data-w="389" style=""></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">举个例子,整个缓冲池LRU如上图:</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(1)整个LRU长度是10;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(2)前70%是新生代;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(3)后30%是老生代;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(4)新老生代</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">首尾相连</span><span style="font-size: 15px;letter-spacing: 1px;">;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><img class="rich_pages wxw-img" data-ratio="0.3586206896551724" data-s="300,640" src="/upload/d24b59cb602d9c14698dae1d38d41fac.png" data-type="png" data-w="435" style=""></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">假如有一个页号为50的新页被预读加入缓冲池:</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(1)50</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">只会从老生代头部插入</span><span style="font-size: 15px;letter-spacing: 1px;">,老生代尾部(也是整体尾部)的页会被淘汰掉;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(2)假设50这一页不会被真正读取,即预读失败,它将比新生代的数据更早淘汰出缓冲池;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><img class="rich_pages wxw-img" data-ratio="0.38961038961038963" data-s="300,640" src="/upload/61cfa589dbc7a187856a675c7ead0b77.png" data-type="png" data-w="385" style=""></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">假如50这一页立刻被读取到,例如SQL访问了页内的行row数据:</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(1)它会被立刻加入到新生代的头部;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(2)新生代的页会被挤到老生代,此时并不会有页面被真正淘汰;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">改进版缓冲池LRU能够很好的解决“预读失败”的问题</span><span style="font-size: 15px;letter-spacing: 1px;">。</span></p> <p style="line-height: 1.75em;"><span style="color: rgb(0, 82, 255);"><em><span style="font-size: 15px;letter-spacing: 1px;">画外音:但也不要因噎废食,因为害怕预读失败而取消预读策略,大部分情况下,局部性原理是成立的,预读是有效的。</span></em></span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">新老生代改进版LRU仍然解决不了缓冲池污染的问题。</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;">什么是MySQL缓冲池污染?</span></strong></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">当某一个SQL语句,要</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">批量扫描大量数据</span><span style="font-size: 15px;letter-spacing: 1px;">时,可能导致把缓冲池的所有页都替换出去,</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">导致大量热数据被换出</span><span style="font-size: 15px;letter-spacing: 1px;">,MySQL性能急剧下降,这种情况叫缓冲池污染。</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">例如,有一个数据量较大的用户表,当执行:</span></p> <p style="line-height: 1.75em;"><span style="letter-spacing: 1px;font-size: 12px;">select * from user where name like "%shenjian%";</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">虽然结果集可能只有少量数据,但这类like不能命中索引,必须</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">全表扫描</span><span style="font-size: 15px;letter-spacing: 1px;">,就需要访问大量的页:</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(1)把页加到缓冲池(插入老生代头部);</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(2)从页里读出相关的row(插入新生代头部);</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(3)row里的name字段和字符串shenjian进行比较,如果符合条件,加入到结果集中;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(4)…直到扫描完所有页中的所有row…</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">如此一来,</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">所有的数据页都会被加载到新生代的头部,但只会访问一次,真正的热数据被大量换出</span><span style="font-size: 15px;letter-spacing: 1px;">。</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;">怎么这类扫码大量数据导致的缓冲池污染问题呢?</span></strong></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">MySQL缓冲池加入了一个“</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">老生代停留时间窗口</span><span style="font-size: 15px;letter-spacing: 1px;">”的机制:</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(1)假设T=老生代停留时间窗口;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(2)插入老生代头部的页,即使立刻被访问,并不会立刻放入新生代头部;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(3)只有<strong>满足</strong>“</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">被访问</span><span style="font-size: 15px;letter-spacing: 1px;">”并且</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">“在老生代停留时间”大于T</span><span style="font-size: 15px;letter-spacing: 1px;">,才会被放入新生代头部;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><img class="rich_pages wxw-img" data-ratio="0.65625" data-s="300,640" src="/upload/9ac55133df07ea9ed16a357f31d488df.png" data-type="png" data-w="416" style=""></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">继续举例,假如批量数据扫描,有51,52,53,54,55等五个页面将要</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">依次</span><span style="font-size: 15px;letter-spacing: 1px;">被访问。</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><img class="rich_pages wxw-img" data-ratio="0.2867012089810017" data-s="300,640" src="/upload/536255bd6d4ad4e23d3fe85bd8cf789d.png" data-type="png" data-w="579" style=""></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">如果没有“老生代停留时间窗口”的策略,这些批量被访问的页面,会换出大量热数据。</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><img class="rich_pages wxw-img" data-ratio="0.3260135135135135" data-s="300,640" src="/upload/2cb009c6254f6a5a3eae51d8bc80717e.png" data-type="png" data-w="592" style=""></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">加入“老生代停留时间窗口”策略后,短时间内被大量加载的页,并不会立刻插入新生代头部,而是优先淘汰那些,短期内仅仅访问了一次的页。</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><img class="rich_pages wxw-img" data-ratio="0.29930795847750863" data-s="300,640" src="/upload/9bee0de555ac141c02ea4e262942e21d.png" data-type="png" data-w="578" style=""></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">而只有在老生代呆的时间足够久,停留时间大于T,才会被插入新生代头部。</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;">上述原理,对应InnoDB里哪些参数?</span></strong></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">有三个比较重要的参数。</span></p> <p style="line-height: 1.75em;"><img class="rich_pages wxw-img" data-ratio="0.6719858156028369" data-s="300,640" src="/upload/1fce089a8c62c7edd0deb927fba59044.png" data-type="png" data-w="564" style="width: 385px;height: 259px;"></p> <p style="line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;">参数</span></strong><span style="font-size: 15px;letter-spacing: 1px;">:</span><span style="letter-spacing: 1px;font-size: 12px;">innodb_buffer_pool_size</span></p> <p style="line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;">介绍</span></strong><span style="font-size: 15px;letter-spacing: 1px;">:配置缓冲池的大小,在内存允许的情况下,DBA往往会建议调大这个参数,越多数据和索引放到内存里,数据库的性能会越好。</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;">参数</span></strong><span style="font-size: 15px;letter-spacing: 1px;">:</span><span style="letter-spacing: 1px;font-size: 12px;">innodb_old_blocks_pct</span></p> <p style="line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;">介绍</span></strong><span style="font-size: 15px;letter-spacing: 1px;">:老生代占整个LRU链长度的比例,默认是37,即整个LRU中新生代与老生代长度比例是63:37。</span></p> <p style="line-height: 1.75em;"><span style="color: rgb(0, 82, 255);"><em><span style="font-size: 15px;letter-spacing: 1px;">画外音:如果把这个参数设为100,就退化为普通LRU了。</span></em></span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;">参数</span></strong><span style="font-size: 15px;letter-spacing: 1px;">:</span><span style="letter-spacing: 1px;font-size: 12px;">innodb_old_blocks_time</span></p> <p style="line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;">介绍</span></strong><span style="font-size: 15px;letter-spacing: 1px;">:老生代停留时间窗口,单位是毫秒,默认是1000,即同时满足“被访问”与“在老生代停留时间超过1秒”两个条件,才会被插入到新生代头部。</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;">总结</span></strong></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(1)缓冲池</span><span style="letter-spacing: 1px;font-size: 12px;">(buffer pool)</span><span style="font-size: 15px;letter-spacing: 1px;">是一种<strong>常见的降低磁盘访问的机制;</strong></span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(2)缓冲池通常</span><strong><span style="font-size: 15px;letter-spacing: 1px;">以页</span><span style="letter-spacing: 1px;font-size: 12px;">(page)</span><span style="font-size: 15px;letter-spacing: 1px;">为单位缓存数据;</span></strong></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(3)缓冲池的<strong>常见管理算法是LRU</strong>,memcache,OS,InnoDB都使用了这种算法;</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">(4)InnoDB对普通LRU进行了优化:</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;&nbsp;&nbsp;&nbsp;- 将缓冲池分为<strong>老生代和新生代</strong>,入缓冲池的页,优先进入老生代,页被访问,才进入新生代,以</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">解决预读失效</span><span style="font-size: 15px;letter-spacing: 1px;">的问题</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;&nbsp;&nbsp;&nbsp;- 页被访问,且在老生代<strong>停留时间超过配置阈值</strong>的,才进入新生代,以</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">解决批量数据访问,大量热数据淘汰</span><span style="font-size: 15px;letter-spacing: 1px;">的问题</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span></p> <p style="line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;">思路</span></strong><span style="font-size: 15px;letter-spacing: 1px;">,比结论重要。</span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">解决了什么问题,比方案重要。</span></p> <section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MjM5ODYxMDA5OQ==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/YrezxckhYOxbibeY4UQvLjjG76dIsbXYGaaKCJpqU0kzRuu3r2CXosccgtc57I15CePibfpQMd5dBibXZDNNZYtkg/0?wx_fmt=png" data-nickname="架构师之路" data-alias="road5858" data-signature="架构师之路,坚持撰写接地气的架构文章" data-from="0"></mpprofile> </section> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;line-height: normal;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 12px;letter-spacing: 1px;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box;word-wrap: break-word;"><strong style="max-width: 100%;box-sizing: border-box;word-wrap: break-word;">架构师之路</strong>-分享技术思路</strong></span></p> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;letter-spacing: 1px;box-sizing: border-box !important;word-wrap: break-word !important;">相关推荐:</span></p> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;letter-spacing: 1px;box-sizing: border-box !important;word-wrap: break-word !important;">《<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&amp;mid=2651969397&amp;idx=1&amp;sn=5a0a001776c0e848722312bb7adb53b0&amp;chksm=bd2d62a98a5aebbf80e51bd0988c9484548272e91c6e3762487d816ad836b05b4d62f9bd0fbf&amp;scene=21#wechat_redirect" textvalue="架构师之路,21年干货精选" linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" data-linktype="2">架构师之路,21年干货精选</a>》</span><span style="letter-spacing: 0.544px;"></span></p>