作者:微信小助手
<h2 data-tool="mdnice编辑器" style="margin: 80px 10px 40px;font-size: 22.4px;text-align: center;color: rgb(63, 63, 63);">温故而知新</h2> <p data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);">业务很简单:需要批量插入一些数据,数据来源可能是其他数据库的表,也可能是一个外部excel的导入</p> <p data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);">那么问题来了,是不是每次插入之前都要查一遍,看看重不重复,在代码里筛选一下数据,重复的就过滤掉呢?</p> <p data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);">向大数据数据库中插入值时,还要判断插入是否重复,然后插入。如何提高效率</p> <p data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);">看来这个问题不止我一个人苦恼过。</p> <p data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);">解决的办法有很多种,不同的场景解决方案也不一样,数据量很小的情况下,怎么搞都行,但是数据量很大的时候,这就不是一个简单的问题了。</p> <p data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);">几百万的数据,不可能查出来,做去重处理</p> <p data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);">说一下我Google到的解决方案</p> <h2 data-tool="mdnice编辑器" style="margin: 80px 10px 40px;font-size: 22.4px;text-align: center;color: rgb(63, 63, 63);">1、insert ignore into</h2> <blockquote data-tool="mdnice编辑器" style="margin-top: 20px;margin-bottom: 20px;padding-top: 1px;padding-bottom: 1px;border-left-color: rgb(158, 158, 158);color: rgb(91, 91, 91);font-size: 0.9em;border-top: none;border-right: none;border-bottom: none;overflow: auto;background: rgba(158, 158, 158, 0.1);"> <p style="margin: 10px;color: rgb(63, 63, 63);line-height: 1.5;font-size: 16px;">当插入数据时,如出现错误时,如重复数据,将不返回错误,只以警告形式返回。所以使用ignore请确保语句本身没有问题,否则也会被忽略掉。例如:</p> </blockquote> <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="margin-bottom: -7px;display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/GibvHudxmlJYMcltcicSW2K9XNmziarfC8vgLlVmvnb1whcQk3ql5SAwvO9tzZRkFC2NFA6TDwjKbtCgLOZEDkeiaib62ibMs3hTEl/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(250, 250, 250);height: 30px;width: 657px;border-radius: 5px;"></span><code style="padding: 15px 16px 16px;overflow-x: auto;color: rgb(56, 58, 66);display: -webkit-box;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(250, 250, 250);border-radius: 5px;"><span style="color: rgb(166, 38, 164);line-height: 26px;">INSERT</span> <span style="color: rgb(166, 38, 164);line-height: 26px;">IGNORE</span> <span style="color: rgb(166, 38, 164);line-height: 26px;">INTO</span> <span style="color: rgb(166, 38, 164);line-height: 26px;">user</span> (<span style="color: rgb(166, 38, 164);line-height: 26px;">name</span>) <span style="color: rgb(166, 38, 164);line-height: 26px;">VALUES</span> (<span style="color: rgb(80, 161, 79);line-height: 26px;">'telami'</span>) </code></pre> <blockquote data-tool="mdnice编辑器" style="margin-top: 20px;margin-bottom: 20px;padding-top: 1px;padding-bottom: 1px;border-left-color: rgb(158, 158, 158);color: rgb(91, 91, 91);font-size: 0.9em;border-top: none;border-right: none;border-bottom: none;overflow: auto;background: rgba(158, 158, 158, 0.1);"> <p style="margin: 10px;color: rgb(63, 63, 63);line-height: 1.5;font-size: 16px;">这种方法很简便,但是有一种可能,就是插入不是因为重复数据报错,而是因为其他原因报错的,也同样被忽略了~</p> </blockquote> <h2 data-tool="mdnice编辑器" style="margin: 80px 10px 40px;font-size: 22.4px;text-align: center;color: rgb(63, 63, 63);">2、on duplicate key update</h2> <p data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);">当primary或者unique重复时,则执行update语句,如update后为无用语句,如id=id,则同1功能相同,但错误不会被忽略掉。</p> <p data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);">例如,为了实现name重复的数据插入不报错,可使用一下语句:</p> <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="margin-bottom: -7px;display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/GibvHudxmlJYMcltcicSW2K9XNmziarfC8vgLlVmvnb1whcQk3ql5SAwvO9tzZRkFC2NFA6TDwjKbtCgLOZEDkeiaib62ibMs3hTEl/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(250, 250, 250);height: 30px;width: 657px;border-radius: 5px;"></span><code style="padding: 15px 16px 16px;overflow-x: auto;color: rgb(56, 58, 66);display: -webkit-box;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(250, 250, 250);border-radius: 5px;"><span style="color: rgb(166, 38, 164);line-height: 26px;">INSERT</span> <span style="color: rgb(166, 38, 164);line-height: 26px;">INTO</span> <span style="color: rgb(166, 38, 164);line-height: 26px;">user</span> (<span style="color: rgb(166, 38, 164);line-height: 26px;">name</span>) <span style="color: rgb(166, 38, 164);line-height: 26px;">VALUES</span> (<span style="color: rgb(80, 161, 79);line-height: 26px;">'telami'</span>) <span style="color: rgb(166, 38, 164);line-height: 26px;">ON</span> <span style="color: rgb(166, 38, 164);line-height: 26px;">duplicate</span> <span style="color: rgb(166, 38, 164);line-height: 26px;">KEY</span> <span style="color: rgb(166, 38, 164);line-height: 26px;">UPDATE</span> <span style="color: rgb(166, 38, 164);line-height: 26px;">id</span> = <span style="color: rgb(166, 38, 164);line-height: 26px;">id</span> </code></pre> <p data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);">这种方法有个前提条件,就是,需要插入的约束,需要是主键或者唯一约束(在你的业务中那个要作为唯一的判断就将那个字段设置为唯一约束也就是unique key)。</p> <h2 data-tool="mdnice编辑器" style="margin: 80px 10px 40px;font-size: 22.4px;text-align: center;color: rgb(63, 63, 63);">3、insert … select … where not exist</h2> <p data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);">根据select的条件判断是否插入,可以不光通过primary 和unique来判断,也可通过其它条件。例如:</p> <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="margin-bottom: -7px;display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/GibvHudxmlJYMcltcicSW2K9XNmziarfC8vgLlVmvnb1whcQk3ql5SAwvO9tzZRkFC2NFA6TDwjKbtCgLOZEDkeiaib62ibMs3hTEl/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(250, 250, 250);height: 30px;width: 657px;border-radius: 5px;"></span><code style="padding: 15px 16px 16px;overflow-x: auto;color: rgb(56, 58, 66);display: -webkit-box;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(250, 250, 250);border-radius: 5px;"><span style="color: rgb(166, 38, 164);line-height: 26px;">INSERT</span> <span style="color: rgb(166, 38, 164);line-height: 26px;">INTO</span> <span style="color: rgb(166, 38, 164);line-height: 26px;">user</span> (<span style="color: rgb(166, 38, 164);line-height: 26px;">name</span>) <span style="color: rgb(166, 38, 164);line-height: 26px;">SELECT</span> <span style="color: rgb(80, 161, 79);line-height: 26px;">'telami'</span> <span style="color: rgb(166, 38, 164);line-height: 26px;">FROM</span> dual <span style="color: rgb(166, 38, 164);line-height: 26px;">WHERE</span> <span style="color: rgb(166, 38, 164);line-height: 26px;">NOT</span> <span style="color: rgb(166, 38, 164);line-height: 26px;">EXISTS</span> (<span style="color: rgb(166, 38, 164);line-height: 26px;">SELECT</span> <span style="color: rgb(166, 38, 164);line-height: 26px;">id</span> <span style="color: rgb(166, 38, 164);line-height: 26px;">FROM</span> <span style="color: rgb(166, 38, 164);line-height: 26px;">user</span> <span style="color: rgb(166, 38, 164);line-height: 26px;">WHERE</span> <span style="color: rgb(166, 38, 164);line-height: 26px;">id</span> = <span style="color: rgb(152, 104, 1);line-height: 26px;">1</span>) </code></pre> <p data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);">这种方法其实就是使用了mysql的一个临时表的方式,但是里面使用到了子查询,效率也会有一点点影响,如果能使用上面的就不使用这个。</p> <h2 data-tool="mdnice编辑器" style="margin: 80px 10px 40px;font-size: 22.4px;text-align: center;color: rgb(63, 63, 63);">4、replace into</h2> <p data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);">如果存在primary or unique相同的记录,则先删除掉。再插入新记录。</p> <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="margin-bottom: -7px;display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/GibvHudxmlJYMcltcicSW2K9XNmziarfC8vgLlVmvnb1whcQk3ql5SAwvO9tzZRkFC2NFA6TDwjKbtCgLOZEDkeiaib62ibMs3hTEl/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(250, 250, 250);height: 30px;width: 657px;border-radius: 5px;"></span><code style="padding: 15px 16px 16px;overflow-x: auto;color: rgb(56, 58, 66);display: -webkit-box;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(250, 250, 250);border-radius: 5px;"><span style="color: rgb(166, 38, 164);line-height: 26px;">REPLACE</span> <span style="color: rgb(166, 38, 164);line-height: 26px;">INTO</span> <span style="color: rgb(166, 38, 164);line-height: 26px;">user</span> <span style="color: rgb(166, 38, 164);line-height: 26px;">SELECT</span> <span style="color: rgb(152, 104, 1);line-height: 26px;">1</span>, <span style="color: rgb(80, 161, 79);line-height: 26px;">'telami'</span> <span style="color: rgb(166, 38, 164);line-height: 26px;">FROM</span> books </code></pre> <p data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);">这种方法就是不管原来有没有相同的记录,都会先删除掉然后再插入。</p> <h2 data-tool="mdnice编辑器" style="margin: 80px 10px 40px;font-size: 22.4px;text-align: center;color: rgb(63, 63, 63);">实践</h2> <p data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);">选择的是第二种方式</p> <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="margin-bottom: -7px;display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/GibvHudxmlJYMcltcicSW2K9XNmziarfC8vgLlVmvnb1whcQk3ql5SAwvO9tzZRkFC2NFA6TDwjKbtCgLOZEDkeiaib62ibMs3hTEl/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(250, 250, 250);height: 30px;width: 657px;border-radius: 5px;"></span><code style="padding: 15px 16px 16px;overflow-x: auto;color: rgb(56, 58, 66);display: -webkit-box;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(250, 250, 250);border-radius: 5px;"><<span style="color: rgb(166, 38, 164);line-height: 26px;">insert</span> <span style="color: rgb(166, 38, 164);line-height: 26px;">id</span>=<span style="color: rgb(80, 161, 79);line-height: 26px;">"batchSaveUser"</span> parameterType=<span style="color: rgb(80, 161, 79);line-height: 26px;">"list"</span>> <span style="color: rgb(166, 38, 164);line-height: 26px;">insert</span> <span style="color: rgb(166, 38, 164);line-height: 26px;">into</span> <span style="color: rgb(166, 38, 164);line-height: 26px;">user</span> (<span style="color: rgb(166, 38, 164);line-height: 26px;">id</span>,username,mobile_number) <span style="color: rgb(166, 38, 164);line-height: 26px;">values</span> <foreach collection=<span style="color: rgb(80, 161, 79);line-height: 26px;">"list"</span> item=<span style="color: rgb(80, 161, 79);line-height: 26px;">"item"</span> <span style="color: rgb(166, 38, 164);line-height: 26px;">index</span>=<span style="color: rgb(80, 161, 79);line-height: 26px;">"index"</span> separator=<span style="color: rgb(80, 161, 79);line-height: 26px;">","</span>> ( <span style="color: rgb(160, 161, 167);font-style: italic;line-height: 26px;">#{item.id}, #{item.username}, #{item.mobileNumber} ) </foreach> ON duplicate KEY UPDATE id = id </insert></span></code></pre> <p data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);">这里用的是Mybatis,批量插入的一个操作,<strong style="color: rgb(255, 53, 2);line-height: 1.5;">mobile_number</strong>已经加了唯一约束。这样在批量插入时,如果存在手机号相同的话,是不会再插入了的。</p>
作者:微信小助手
<p style="text-align: center;" data-mpa-powered-by="yiban.io"><span style="color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;font-size: 16px;"></span><img data-backh="300" data-backw="533" data-ratio="0.5628517823639775" src="/upload/7e30bf7e19a03729c3abaf17e93067a6.jpg" data-type="jpeg" data-w="533" style="width: 100%;height: auto;"><span style="color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;font-size: 16px;"></span></p> <p style="max-width: 100%;min-height: 1em;white-space: normal;font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-align: left;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="max-width: 100%;letter-spacing: 0.544px;color: rgb(178, 178, 178);font-family: Optima-Regular, PingFangTC-light;font-size: 13px;overflow-wrap: break-word !important;box-sizing: border-box !important;">作者 | </span><span style="max-width: 100%;letter-spacing: 0.544px;color: rgb(178, 178, 178);font-family: Optima-Regular, PingFangTC-light;font-size: 13px;overflow-wrap: break-word !important;box-sizing: border-box !important;">JingQ</span><br style="max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;"></p> <section style="margin-bottom: 15px;max-width: 100%;white-space: normal;text-align: left;font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);overflow-wrap: break-word !important;box-sizing: border-box !important;"> <span style="max-width: 100%;letter-spacing: 0.544px;color: rgb(178, 178, 178);font-family: Optima-Regular, PingFangTC-light;font-size: 13px;overflow-wrap: break-word !important;box-sizing: border-box !important;">来源 |</span> <span style="max-width: 100%;letter-spacing: 0.544px;color: rgb(178, 178, 178);font-family: Optima-Regular, PingFangTC-light;font-size: 13px;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="max-width: 100%;white-space: pre-line;overflow-wrap: break-word !important;box-sizing: border-box !important;"> </span></span> <span style="max-width: 100%;letter-spacing: 0.544px;color: rgb(178, 178, 178);font-family: Optima-Regular, PingFangTC-light;font-size: 13px;overflow-wrap: break-word !important;box-sizing: border-box !important;">sevenyuan.cn/</span> </section> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">在看大型网站的中间件技术,对于Elasticsearch有点兴趣,所以将配置流程记录了一下</p> <h3 style="margin-top: 1.2em;margin-bottom: 1em;color: rgb(53, 179, 120);font-weight: bold;font-size: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">为什么要用ELK</h3> <blockquote style="margin: 10px 5px;border-top: none;border-right: 0px solid rgb(53, 179, 120);border-bottom: none;border-left-color: rgb(53, 179, 120);font-size: 0.9em;overflow: auto;background: rgb(251, 249, 253);color: rgb(97, 97, 97);padding: 10px 10px 10px 20px;quotes: none;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">ELK实际上是三个工具,Elastricsearch + LogStash + Kibana,通过ELK,用来收集日志还有进行日志分析,最后通过可视化UI进行展示。一开始业务量比较小的时候,通过简单的SLF4J+Logger在服务器打印日志,通过grep进行简单查询,但是随着业务量增加,数据量也会不断增加,所以使用ELK可以进行大数量的日志收集和分析</p> </blockquote> <h3 style="margin-top: 1.2em;margin-bottom: 1em;color: rgb(53, 179, 120);font-weight: bold;font-size: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">简单画了一下架构图</h3> <p style="text-align: center;"><img class="rich_pages" data-backh="315" data-backw="579" data-galleryid="" data-ratio="0.5451428571428572" data-s="300,640" src="/upload/83225d664cdffbf3c05fc49d3993344f.png" data-type="png" data-w="875" style="width: 100%;height: auto;"></p> <p style="text-align: center;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&mid=2247534248&idx=2&sn=371b4db16e55b2ebce2a4b91055cdf1d&chksm=9bd3eb30aca46226cf9f7061a2e1a54565436772b760ff142f5e8290287d83e4ed72c0dd0bda&scene=21#wechat_redirect" data-itemshowtype="11" tab="innerlink" style="color: rgb(178, 178, 178);font-size: 14px;" data-linktype="2"><span style="color: rgb(178, 178, 178);font-size: 14px;">改造了以前写的数据脱敏插件,更好用了</span></a><br></p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">「在环境配置中,主要介绍Mac和linux配置,windows系统大致相同,当然,前提是大家都安装了JDK1.8及以上版本~」</p> <pre style="font-size: 15px;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;margin-top: 10px;margin-bottom: 10px;overflow: auto;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;color: rgb(89, 89, 89);letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><code style="font-size: 12px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;display: -webkit-box;overflow-x: auto;padding: 15px 16px 16px;color: rgb(171, 178, 191);background: rgb(40, 44, 52);border-radius: 5px;">[root@VM_234_23_centos ~]<span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;"># java -version</span><br>java version <span style="color: rgb(152, 195, 121);line-height: 26px;">"1.8.0_161"</span><br>Java(TM) SE Runtime Environment (build 1.8.0_161-b12)<br>Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode)<br></code></pre> <blockquote style="margin: 10px 5px;border-top: none;border-right: 0px solid rgb(53, 179, 120);border-bottom: none;border-left-color: rgb(53, 179, 120);font-size: 0.9em;overflow: auto;background: rgb(251, 249, 253);color: rgb(97, 97, 97);padding: 10px 10px 10px 20px;quotes: none;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">注意</p> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">高版本的ELK同样需要高版本的JDK支持,本文配置的ELK版本是6.0+,所以需要的JDK版本不小于1.8</p> </blockquote> <hr style="box-sizing: initial;height: 1px;overflow: visible;margin: 1.5em auto;border-style: solid;border-color: rgb(53, 179, 120);color: rgb(89, 89, 89);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"> <h3 style="margin-top: 1.2em;margin-bottom: 1em;color: rgb(53, 179, 120);font-weight: bold;font-size: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">ElasticSearch</h3> <blockquote style="margin: 10px 5px;border-top: none;border-right: 0px solid rgb(53, 179, 120);border-bottom: none;border-left-color: rgb(53, 179, 120);font-size: 0.9em;overflow: auto;background: rgb(251, 249, 253);color: rgb(97, 97, 97);padding: 10px 10px 10px 20px;quotes: none;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">Elasticsearch 是一个分布式的 RESTful 风格的搜索和数据分析引擎,能够解决不断涌现出的各种用例。作为 Elastic Stack 的核心,它集中存储您的数据,帮助您发现意料之中以及意料之外的情况。</p> </blockquote> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">Mac安装和运行</p> <pre style="font-size: 15px;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;margin-top: 10px;margin-bottom: 10px;overflow: auto;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;color: rgb(89, 89, 89);letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><code style="font-size: 12px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;display: -webkit-box;overflow-x: auto;padding: 15px 16px 16px;color: rgb(171, 178, 191);background: rgb(40, 44, 52);border-radius: 5px;">安装:brew install elasticsearch<br>运行:elasticsearch<br></code></pre> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">linux: 从Elasticsearch官方地址下载(也可以下载完,通过ftp之类的工具传上去),gz文件的话通过tar进行解压缩,然后进入bin目录下运行软件</p> <pre style="font-size: 15px;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;margin-top: 10px;margin-bottom: 10px;overflow: auto;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;color: rgb(89, 89, 89);letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><code style="font-size: 12px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;display: -webkit-box;overflow-x: auto;padding: 15px 16px 16px;color: rgb(171, 178, 191);background: rgb(40, 44, 52);border-radius: 5px;">[root@VM_234_23_centos app]<span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;"># curl -L -O https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.2.4.tar.gz</span><br>[root@VM_234_23_centos app]<span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;"># tar -zxvf elasticsearch-6.2.4.tar.gz</span><br>[root@VM_234_23_centos app]<span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;"># cd elasticsearch-6.2.4</span><br>[root@VM_234_23_centos elasticsearch-6.2.4]<span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;"># ./bin/elasticsearch</span><br></code></pre> <blockquote style="margin: 10px 5px;border-top: none;border-right: 0px solid rgb(53, 179, 120);border-bottom: none;border-left-color: rgb(53, 179, 120);font-size: 0.9em;overflow: auto;background: rgb(251, 249, 253);color: rgb(97, 97, 97);padding: 10px 10px 10px 20px;quotes: none;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">注意</p> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">在Linux机器上,运行elasticsearch需要一个新的用户组,文章最后有Elastic在linux安装的踩坑记录</p> </blockquote> <hr style="box-sizing: initial;height: 1px;overflow: visible;margin: 1.5em auto;border-style: solid;border-color: rgb(53, 179, 120);color: rgb(89, 89, 89);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"> <h3 style="margin-top: 1.2em;margin-bottom: 1em;color: rgb(53, 179, 120);font-weight: bold;font-size: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">Logstash</h3> <blockquote style="margin: 10px 5px;border-top: none;border-right: 0px solid rgb(53, 179, 120);border-bottom: none;border-left-color: rgb(53, 179, 120);font-size: 0.9em;overflow: auto;background: rgb(251, 249, 253);color: rgb(97, 97, 97);padding: 10px 10px 10px 20px;quotes: none;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">Logstash 是开源的服务器端数据处理管道,能够同时从多个来源采集数据,转换数据,然后将数据发送到您最喜欢的 “存储库” 中。(我们的存储库当然是 Elasticsearch。)-官方卖萌</p> </blockquote> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">「1. 软件安装」</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">Mac安装:</p> <pre style="font-size: 15px;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;margin-top: 10px;margin-bottom: 10px;overflow: auto;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;color: rgb(89, 89, 89);letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><code style="font-size: 12px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;display: -webkit-box;overflow-x: auto;padding: 15px 16px 16px;color: rgb(171, 178, 191);background: rgb(40, 44, 52);border-radius: 5px;">brew install logstash<br></code></pre> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">linux安装:</p> <pre style="font-size: 15px;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;margin-top: 10px;margin-bottom: 10px;overflow: auto;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;color: rgb(89, 89, 89);letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><code style="font-size: 12px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;display: -webkit-box;overflow-x: auto;padding: 15px 16px 16px;color: rgb(171, 178, 191);background: rgb(40, 44, 52);border-radius: 5px;">[root@VM_234_23_centos app]<span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;"># curl -L -O https://artifacts.elastic.co/downloads/logstash/logstash-6.3.2.tar.gz</span><br> % Total % Received % Xferd Average Speed Time Time Time Current<br> Dload Upload Total Spent Left Speed<br>100 137M 100 137M 0 0 5849k 0 0:00:24 0:00:24 --:--:-- 6597k<br>[root@VM_234_23_centos app]<span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;"># tar -zxvf logstash-6.3.2.tar.gz</span><br></code></pre> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">「2. 修改配置文件」</p> <pre style="font-size: 15px;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;margin-top: 10px;margin-bottom: 10px;overflow: auto;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;color: rgb(89, 89, 89);letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><code style="font-size: 12px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;display: -webkit-box;overflow-x: auto;padding: 15px 16px 16px;color: rgb(171, 178, 191);background: rgb(40, 44, 52);border-radius: 5px;">vim /etc/logstash.conf<br></code></pre> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">「conf文件,指定要使用的插件,和配置对应的elasticsearch的hosts」</p> <pre style="font-size: 15px;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;margin-top: 10px;margin-bottom: 10px;overflow: auto;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;color: rgb(89, 89, 89);letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><code style="font-size: 12px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;display: -webkit-box;overflow-x: auto;padding: 15px 16px 16px;color: rgb(171, 178, 191);background: rgb(40, 44, 52);border-radius: 5px;">input { stdin { } }<br>output {<br> elasticsearch { hosts => [<span style="color: rgb(152, 195, 121);line-height: 26px;">"localhost:9200"</span>] }<br> stdout { codec => rubydebug }<br>}<br></code></pre> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">「3. 运行」</p> <pre style="font-size: 15px;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;margin-top: 10px;margin-bottom: 10px;overflow: auto;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;color: rgb(89, 89, 89);letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><code style="font-size: 12px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;display: -webkit-box;overf
作者:微信小助手
<p style="white-space: normal;text-align: center;"><span style="color: rgb(255, 169, 0);font-size: 15px;">↓</span><span style="color: rgb(255, 169, 0);font-size: 15px;">推荐关注↓</span><span style="font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;max-width: 100%;white-space: pre-wrap;color: rgb(255, 41, 65);font-size: 14px;line-height: 22.4px;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></p> <section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzA5NjUxMTM2MQ==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/mshqAkialV7FvgHwjwFbEbT0nNZU2AVPsmAuuZfXfp0Yc8H3FNkbiaKZYUJNichcJ3lZj4HiceOTXAeTnPHJrLFklA/0?wx_fmt=png" data-nickname="大前端技术之路" data-alias="frontroute" data-signature="分享Web前端,Node.js、React Native等大前端技术栈精选" data-from="0"></mpprofile> </section> <p style="white-space: normal;"><span style="font-size: 15px;"></span></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;overflow-wrap: break-word;text-align: left;font-family: Helvetica;"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">为了让还没听说过这个特性的小伙伴们有一个大致了解,以下是一些关于该特性的简要介绍:</p> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;background: rgba(0, 0, 0, 0.05);color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(255, 218, 169);"> <p style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;font-size: 15px;">async/await是一种编写异步代码的新方法。在这之前编写异步代码使用的是回调函数和promise。<br>async/await实际是建立在promise之上的。因此你不能把它和回调函数搭配使用。<br>async/await可以使异步代码在形式上更接近于同步代码。这就是它最大的价值。</p> </blockquote> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 18px;color: #3da742;">语法</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">假设有一个getJSON方法,它返回一个promise,该promise会被resolve为一个JSON对象。我们想要调用该方法,输出得到的JSON对象,最后返回"done"。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">以下是使用promise的实现方式:</p> <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("https://mmbiz.qpic.cn/mmbiz_svg/3Lqm1xHojtYueY5PvxQMH39rFyy3yCicOibUljX4icKg1WEmPvibheYVwx63xbcwf7e1RrA1kKMtthdBakoCbM4edApqGP4Ps7eS/640?wx_fmt=svg") 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;">const</span> makeRequest = <span style="line-height: 26px;"><span style="line-height: 26px;">()</span> =></span><br> getJSON()<br> .then(<span style="line-height: 26px;"><span style="line-height: 26px;">data</span> =></span> {<br> <span style="color: #e6c07b;line-height: 26px;">console</span>.log(data)<br> <span style="color: #c678dd;line-height: 26px;">return</span> <span style="color: #98c379;line-height: 26px;">"done"</span><br> })<br>makeRequest()<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">使用async/await则是这样的:</p> <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("https://mmbiz.qpic.cn/mmbiz_svg/3Lqm1xHojtYueY5PvxQMH39rFyy3yCicOibUljX4icKg1WEmPvibheYVwx63xbcwf7e1RrA1kKMtthdBakoCbM4edApqGP4Ps7eS/640?wx_fmt=svg") 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;">const</span> makeRequest = <span style="color: #c678dd;line-height: 26px;">async</span> () => {<br> <span style="color: #e6c07b;line-height: 26px;">console</span>.log(<span style="color: #c678dd;line-height: 26px;">await</span> getJSON())<br> <span style="color: #c678dd;line-height: 26px;">return</span> <span style="color: #98c379;line-height: 26px;">"done"</span><br>}<br><br>makeRequest()<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">使用async/await时有以下几个区别:</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在定义函数时我们使用了async关键字。await关键字只能在使用async定义的函数的内部使用。所有async函数都会返回一个promise,该promise最终resolve的值就是你在函数中return的内容。<br>由于第一点中的原因,你不能在顶级作用域中await一个函数。因为顶级作用域不是一个async方法。</p> <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("https://mmbiz.qpic.cn/mmbiz_svg/3Lqm1xHojtYueY5PvxQMH39rFyy3yCicOibUljX4icKg1WEmPvibheYVwx63xbcwf7e1RrA1kKMtthdBakoCbM4edApqGP4Ps7eS/640?wx_fmt=svg") 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: #5c6370;font-style: italic;line-height: 26px;">// this will not work in top level</span><br><span style="color: #5c6370;font-style: italic;line-height: 26px;">// await makeRequest()</span><br> <br><span style="color: #5c6370;font-style: italic;line-height: 26px;">// this will work</span><br>makeRequest().then(<span style="line-height: 26px;">(<span style="line-height: 26px;">result</span>) =></span> {<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// do something</span><br>})<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">await getJSON()意味着直到getJSON()返回的promise在resolve之后,console.log才会执行并输出resolove的值。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span><span style="font-size: 20px;color: #ab1942;">为何使用async/await编写出来的代码更好呢?</span></h2> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 18px;color: #3da742;">1. 简洁</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">看看我们节省了多少代码吧。即使是在这么一个简单的例子中,我们也节省了可观的代码。我们不需要为.then编写一个匿名函数来处理返回结果,也不需要创建一个data变量来保存我们实际用不到的值。我们还避免了代码嵌套。这些小优点会在真实项目中变得更加明显。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 18px;color: #3da742;">2. 错误处理</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">async/await终于使得用同一种构造(古老而好用的try/catch) 处理同步和异步错误成为可能。在下面这段使用promise的代码中,try/catch不能捕获JSON.parse抛出的异常,因为该操作是在promise中进行的。要处理JSON.parse抛出的异常,你需要在promise上调用.catch并重复一遍异常处理的逻辑。通常在生产环境中异常处理逻辑都远比console.log要复杂,因此这会导致大量的冗余代码。</p> <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("https://mmbiz.qpic.cn/mmbiz_svg/3Lqm1xHojtYueY5PvxQMH39rFyy3yCicOibUljX4icKg1WEmPvibheYVwx63xbcwf7e1RrA1kKMtthdBakoCbM4edApqGP4Ps7eS/640?wx_fmt=svg") 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;">const</span> makeRequest = <span style="line-height: 26px;"><span style="line-height: 26px;">()</span> =></span> {<br> <span style="color: #c678dd;line-height: 26px;">try</span> {<br> getJSON()<br> .then(<span style="line-height: 26px;"><span style="line-height: 26px;">result</span> =></span> {<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// this parse may fail</span><br> <span style="color: #c678dd;line-height: 26px;">const</span> data = <span style="color: #e6c07b;line-height: 26px;">JSON</span>.parse(result)<br> <span style="color: #e6c07b;line-height: 26px;">console</span>.log(data)<br> })<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// uncomment this block to handle asynchronous errors</span><br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// .catch((err) => {</span><br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// console.log(err)</span><br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// })</span><br> } <span style="color: #c678dd;line-height: 26px;">catch</span> (err) {<br> <span style="color: #e6c07b;line-height: 26px;">console</span>.log(err)<br> }<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">现在看看使用了async/await的情况,catch代码块现在可以捕获JSON.parse抛出的异常了:</p> <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("https://mmbiz.qpic.cn/mmbiz_svg/3Lqm1xHojtYueY5PvxQMH39rFyy3yCicOibUljX4icKg1WEmPvibheYVwx63xbcwf7e1RrA1kKMtthdBakoCbM4edApqGP4Ps7eS/640?wx_fmt=svg") 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;">const</span> makeRequest = <span style="color: #c678dd;line-height: 26px;">async</span> () => {<br> <span style="color: #c678dd;line-height: 26px;">try</span> {<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// this parse may fail</span><br> <span style="color: #c678dd;line-height: 26px;">const</span> data = <span style="color: #e6c07b;line-height: 26px;">JSON</span>.parse(<span style="color: #c678dd;line-height: 26px;">await</span> getJSON())<br> <span style="color: #e6c07b;line-height: 26px;">console</span>.log(data)<br> } <span style="color: #c678dd;line-height: 26px;">catch</span> (err) {<br> <span style="color: #e6c07b;line-height: 26px;">console</span>.log(err)<br> }<br>}<br></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 18px;color: #3da742;">3. 条件分支</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">假设有如下逻辑的代码。请求数据,然后根据返回数据中的某些内容决定是直接返回这些数据还是继续请求更多数据:</p> <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("https://mmbiz.qpic.cn/mmbiz_svg/3Lqm1xHojtYueY5PvxQMH39rFyy3yCicOibUljX4icKg1WEmPvibheYVwx63xbcwf7e1RrA1kKMtthdBakoCbM4edApqGP4Ps7eS/640?wx_fmt=svg") 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;">const</span> makeRequest = <span style="line-height: 26px;"><span style="line-height: 26px;">()</span> =></span> {<br> <span style="color: #c678dd;line-height: 26px;">return</span> getJSON()<br> .then(<span style="line-height: 26px;"><span style="line-height: 26px;">data</span> =></span> {<br> <span style="color: #c678dd;line-height: 26px;">if</span> (data.needsAnotherRequest) {<br> <span style="color: #c678dd;line-height: 26px;">return</span> makeAnotherRequest(data)<br> .then(<span style="line-height: 26px;"><span style="line-height: 26px;">moreData</span> =></span> {<br> <span style="color: #e6c07b;line-height: 26px;">console</span>.log(moreData)<br> <span style="color: #c678dd;line-height: 26px;">return</span> moreData<br> })<br> } <span style="color: #c678dd;line-height: 26px;">else</span> {<br> <span style="color: #e6c07b;line-height: 26px;">console</span>.log(data)<br> <span style="color: #c678dd;line-height: 26px;">return</span> data<br> }<br> })<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">只是阅读这些代码已经够让你头疼的了。一不小心你就会迷失在这些嵌套(6层),空格,返回语句中。(当然我们一般用请求数据的返回值作为判断条件不会写成这样,也许我这个小白会...) 在使用async/await改写后,这段代码的可读性大大提高了:</p> <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("https://mmbiz.qpic.cn/mmbiz_svg/3Lqm1xHojtYueY5PvxQMH39rFyy3yCicOibUljX4icKg1WEmPvibheYVwx63xbcwf7e1RrA1kKMtthdBakoCbM4edApqGP4Ps7eS/640?wx_fmt=svg") 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;">const</span> makeRequest = <span style="color: #c678dd;line-height: 26px;">async</span> () => {<br> <span style="color: #c678dd;line-height: 26px;">const</span> data = <span style="color: #c678dd;line-height: 26px;">await</span> getJSON()<br> <span style="color: #c678dd;line-height: 26px;">if</span> (data.needsAnotherRequest) {<br> <span style="color: #c678dd;line-height: 26px;">const</span> moreData = <span style="color: #c678dd;line-height: 26px;">await</span> makeAnotherRequest(data);<br> <span style="color: #e6c07b;line-height: 26px;">console</span>.log(moreData)<br> <span style="color: #c678dd;line-height: 26px;">return</span> moreData<br> } <span style="color: #c678dd;line-height: 26px;">else</span> {<br> <span style="color: #e6c07b;line-height: 26px;">console</span>.log(data)<br> <span style="color: #c678dd;line-height: 26px;">return</span> data <br> }<br>}<br></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 18px;color: #3da742;">4. 中间值</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">比如你向一个url1发送请求,拿到返回值1,然后用这个返回值1当作参数去请求url2,拿到返回值2,然后拿返回值1和返回值2作为参数去请求url3,拿到最终的返回结果。<br>对应的代码看起来是这样的:</p> <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("https://mmbiz.qpic.cn/mmbiz_svg/3Lqm1xHojtYueY5PvxQMH39rFyy3yCicOibUljX4icKg1WEmPvibheYVwx63xbcwf7e1RrA1kKMtthdBakoCbM4edApqGP4Ps7eS/640?wx_fmt=svg") 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;">const</span> makeRequest = <span style="line-height: 26px;"><span style="line-height: 26px;">()</span> =></span> {<br> <span style="color: #c678dd;line-height: 26px;">return</span> promise1()<br> .then(<span style="line-height: 26px;"><span style="line-height: 26px;">value1</span> =></span> {<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// do something</span><br> <span style="color: #c678dd;line-height: 26px;">return</span> promise2(value1)<br> .then(<span style="line-height: 26px;"><span style="line-height: 26px;">value2</span> =></span> {<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// do something </span><br> <span style="color: #c678dd;line-height: 26px;">return</span> promise3(value1, value2)<br> })<br> })<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">如果promise3没有用到value1,那么我们就可以把这几个promise改成嵌套的模式。如果你不喜欢这种编码方式,你也可以把value1和value2封装在一个Promsie.all调用中以避免深层次的嵌套:</p> <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("https://mmbiz.qpic.cn/mmbiz_svg/3Lqm1xHojtYueY5PvxQMH39rFyy3yCicOibUljX4icKg1WEmPvibheYVwx63xbcwf7e1RrA1kKMtthdBakoCbM4edApqGP4Ps7eS/640?wx_fmt=svg") 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;">const</span> makeRequest = <span style="line-height: 26px;"><span style="line-height: 26px;">()</span> =></span> {<br> <span style="color: #c678dd;line-height: 26px;">return</span> promise1()<br> .then(<span style="line-height: 26px;"><span style="line-height: 26px;">value1</span> =></span> {<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// do something</span><br> <span style="color: #c678dd;line-height: 26px;">return</span> <span style="color: #e6c07b;line-height: 26px;">Promise</span>.all([value1, promise2(value1)])<br> })<br> .then(<span style="line-height: 26px;">(<span style="line-height: 26px;">[value1, value2]</span>) =></span> {<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// do something </span><br> <span style="color: #c678dd;line-height: 26px;">return</span> promise3(value1, value2)<br> })<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">这种方式为了保证可读性而牺牲了语义。除了避免嵌套的promise,没有其它理由要把value1和value2放到一个数组里。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">同样的逻辑如果换用async/await编写就会非常简单,直观。</p> <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("https://mmbiz.qpic.cn/mmbiz_svg/3Lqm1xHojtYueY5PvxQMH39rFyy3yCicOibUljX4icKg1WEmPvibheYVwx63xbcwf7e1RrA1kKMtthdBakoCbM4edApqGP4Ps7eS/640?wx_fmt=svg") 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;">const</span> makeRequest = <span style="color: #c678dd;line-height: 26px;">async</span> () => {<br> <span style="color: #c678dd;line-height: 26px;">const</span> value1 = <span style="color: #c678dd;line-height: 26px;">await</span> promise1()<br> <span style="color: #c678dd;line-height: 26px;">const</span> value2 = <span style="color: #c678dd;line-height: 26px;">await</span> promise2(value1)<br> <span style="color: #c678dd;line-height: 26px;">return</span> promise3(value1, value2)<br>}<br></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 18px;color: #3da742;">5. 异常堆栈</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">假设有一段串行调用多个promise的代码,在promise串中的某一点抛出了异常:</p> <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("https://mmbiz.qpic.cn/mmbiz_svg/3Lqm1xHojtYueY5PvxQMH39rFyy3yCicOibUljX4icKg1WEmPvibheYVwx63xbcwf7e1RrA1kKMtthdBakoCbM4edApqGP4Ps7eS/640?wx_fmt=svg") 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;">const</span> makeRequest = <span style="line-height: 26px;"><span style="line-height: 26px;">()</span> =></span> {<br> <span style="color: #c678dd;line-height: 26px;">return</span> callAPromise()<br> .then(<span style="line-height: 26px;"><span style="line-height: 26px;">()</span> =></span> callAPromise())<br> .then(<span style="line-height: 26px;"><span style="line-height: 26px;">()</span> =></span> callAPromise())<br> .then(<span style="line-height: 26px;"><span style="line-height: 26px;">()</span> =></span> callAPromise())<br> .then(<span style="line-height: 26px;"><span style="line-height: 26px;">()</span> =></span> callAPromise())<br> .then(<span style="line-height: 26px;"><span style="line-height: 26px;">()</span> =></span> {<br> <span style="color: #c678dd;line-height: 26px;">throw</span> <span style="color: #c678dd;line-height: 26px;">new</span> <span style="color: #e6c07b;line-height: 26px;">Error</span>(<span style="color: #98c379;line-height: 26px;">"oops"</span>);<br> })<br>}<br><br>makeRequest()<br> .catch(<span style="line-height: 26px;"><span style="line-height: 26px;">err</span> =></span> {<br> <span style="color: #e6c07b;line-height: 26px;">console</span>.log(err);<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// output</span><br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// Error: oops at callAPromise.then.then.then.then.then (index.js:8:13)</span><br> })<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">从promise串返回的异常堆栈中没有包含关于异常是从哪一个环节抛出的信息。更糟糕的是,它还会误导你,它包含的唯一的函数名是callAPromise,然而该函数与此异常并无关系。(这种情况下文件名和行号还是有参考价值的)。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">然而,在使用了async/await的代码中,异常堆栈指向了正确的函数:</p> <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("https://mmbiz.qpic.cn/mmbiz_svg/3Lqm1xHojtYueY5PvxQMH39rFyy3yCicOibUljX4icKg1WEmPvibheYVwx63xbcwf7e1RrA1kKMtthdBakoCbM4edApqGP4Ps7eS/640?wx_fmt=svg") 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;">const</span> makeRequest = <span style="color: #c678dd;line-height: 26px;">async</span> () => {<br> <span style="color: #c678dd;line-height: 26px;">await</span> callAPromise()<br> <span style="color: #c678dd;line-height: 26px;">await</span> callAPromise()<br> <span style="color: #c678dd;line-height: 26px;">await</span> callAPromise()<br> <span style="color: #c678dd;line-height: 26px;">await</span> callAPromise()<br> <span style="color: #c678dd;line-height: 26px;">await</span> callAPromise()<br> <span style="color: #c678dd;line-height: 26px;">throw</span> <span style="color: #c678dd;line-height: 26px;">new</span> <span style="color: #e6c07b;line-height: 26px;">Error</span>(<span style="color: #98c379;line-height: 26px;">"oops"</span>);<br>}<br><br>makeRequest()<br> .catch(<span style="line-height: 26px;"><span style="line-height: 26px;">err</span> =></span> {<br> <span style="color: #e6c07b;line-height: 26px;">console</span>.log(err);<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// output</span><br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// Error: oops at makeRequest (index.js:7:9)</span><br> })<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">这带来的好处在本地开发环境中可能并不明显,但当你想要在生产环境的服务器上获取有意义的异常信息时,这会非常有用。在这种情况下,知道异常来自makeRequest而不是一连串的then调用会有意义的多。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 18px;color: #3da742;">6. 调试</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">最后压轴的一点,使用async/await最大的优势在于它很容易被调试。由于以下两个原因,调试promise一直以来都是很痛苦的。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">你不能在一个返回表达式的箭头函数中设置断点(因为没有代码块)</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><img data-ratio="0.3525" src="/upload/db7ff15605307a5179c3c74edd48ccab.png" data-type="png" data-w="800" style="display: block;margin-right: auto;margin-left: auto;"> <br></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">如果你在一个.then代码块中使用调试器的步进(step-over)功能,调试器并不会进入后续的.then代码块,因为调试器只能跟踪同步代码的『每一步』。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">通过使用async/await,你不必再使用箭头函数。你可以对await语句执行步进操作,就好像他们都是普通的同步调用一样。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><img data-ratio="0.34" src="/upload/90fec63e68c294c4a60409c386d374d9.png" data-type="png" data-w="800" style="display: block;margin-right: auto;margin-left: auto;"> <br></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">结论 async/await是过去几年中JavaScript引入的最具革命性的特性之一。它使你意识到promise在语法上的糟糕之处,并提供了一种简单,直接的替代方案。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">参考文章</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">https://loveky.github.io/2017/04/09/translte-6-reasons-why-javascripts-async-await-blows-promises-away/</p> </section> <p style="white-space: normal;"><span style="font-size: 15px;"></span><br></p> <blockquote style="white-space: normal;caret-color: rgb(0, 0, 0);font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;"> <p><span style="font-size: 14px;">转自:Angus安格斯</span></p> <p><span style="font-size: 14px;">https://juejin.cn/post/6960855679208783903</span></p> </blockquote> <p style="white-space: normal;text-align: center;"><span style="font-size: 15px;color: rgb(136, 136, 136);"></span></p> <p style="white-space: normal;caret-color: rgb(0, 0, 0);color: rgb(0, 0, 0);text-align: center;"><span style="font-size: 15px;color: rgb(136, 136, 136);">- EOF -</span></p> <section donone="shifuMouseDownCard('shifu_c_030')" label="Copyright Reserved by PLAYHUDONG." style="margin-top: 1em;margin-bottom: 1em;white-space: normal;text-align: start;max-width: 100%;caret-color: rgb(0, 0, 0);color: rgb(0, 0, 0);border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-left: 1em;max-width: 100%;line-height: 1.4;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="padding: 3px 8px;max-width: 100%;border-radius: 4px;color: rgb(255, 255, 255);background-color: rgb(255, 105, 31);font-family: inherit;text-align: inherit;text-decoration: inherit;font-size: 16px;box-sizing: border-box !important;overflow-wrap: break-word !important;">推荐阅读</span> <span style="margin-left: 4px;padding: 3px 8px;max-width: 100%;border-radius: 1.2em;color: rgb(255, 255, 255);line-height: 1.2;background-color: rgb(204, 204, 204);font-family: inherit;text-align: inherit;text-decoration: inherit;border-color: rgb(249, 110, 87);font-size: 12px;box-sizing: border-box !important;overflow-wrap: break-word !important;">点击标题可跳转</span> </section> <section style="margin-top: -11px;padding: 22px 16px 16px;max-width: 100%;border-width: 1px;border-style: solid;border-color: rgb(255, 105, 31);color: rgb(51, 51, 51);font-size: 1em;font-family: inherit;text-align: inherit;text-decoration: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="max-width: 100%;min-height: 1em;line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="text-decoration: underline;font-size: 13px;">1、<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzAxODE2MjM1MA==&mid=2651572387&idx=2&sn=dbff7ee64d9c4895cf2636c26a525e99&chksm=80251f62b7529674693ed628a336f7cc87cf81fdf8cdb311b344f12184206638376c87ebc796&scene=21#wechat_redirect" data-itemshowtype="11" tab="innerlink" data-linktype="2">使用顶层 await 简化 JS 代码</a></span></p> <p style="max-width: 100%;min-height: 1em;line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="text-decoration: underline;font-size: 13px;">2、<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzAxODE2MjM1MA==&mid=2651573178&idx=2&sn=a421c5b8d9c8585b4e776e4b88a56cbb&chksm=80251c7bb752956d13e84990854d1fc5c58082ad875386b7114e73589ab156d6d85cf59112b1&scene=21#wechat_redirect" data-itemshowtype="11" tab="innerlink" data-linktype="2">探索 Node.js 异步 Hooks</a></span></p> <p style="max-width: 100%;min-height: 1em;line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="text-decoration: underline;font-size: 13px;">3、<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzAxODE2MjM1MA==&mid=2651567035&idx=2&sn=68d45e1a62f505e4be7a60ebb35f7f1c&chksm=8025647ab752ed6c784b69ba2a0d34aa01c11dca1c7d9114f29fb05e1bc2b11f8a44ee6d9377&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2">实现一个 async/await (typescript 版)</a></span></p> </section> </section> <p style="white-space: normal;"><span style="max-width: 100%;font-size: 14px;color: rgb(255, 169, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"></span><br></p> <p style="white-space: normal;max-width: 100%;min-height: 1em;text-align: center;"><span style="max-width: 100%;font-size: 14px;color: rgb(255, 169, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">觉得本文对你有帮助?请分享给更多人</span></p> <p style="white-space: normal;max-width: 100%;min-height: 1em;text-align: center;"><span style="font-size: 15px;"><span style="max-width: 100%;color: rgb(255, 169, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">推荐关注「前端大全」,提升前端技能</span></span></p> <section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzAxODE2MjM1MA==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/zPh0erYjkib1dokUibGkodosUGPkEMoBlHMYPlyR5bap7RggniaMtDkQYXE0LwwvmsgMiargkJ6FVOkCstZ6fbiaAyQ/0?wx_fmt=png" data-nickname="前端大全" data-alias="FrontDev" data-signature="点击获取精选前端开发资源。「前端大全」日常分享 Web 前端相关的技术文章、实用案例、工具资源、精选课程、热点资讯。" data-from="0"></mpprofile> </section> <p style="white-space: normal;text-align: right;"><span style="font-size: 14px;"></span><span style="font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;caret-color: rgb(51, 51, 51);max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">点赞和在看就是最大的支持</span><span style="font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;caret-color: rgb(51, 51, 51);max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">❤️</span></p>
作者:微信小助手
<section style="margin-bottom: 10px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;font-size: 15px;letter-spacing: 1px;color: rgb(0, 0, 0);font-family: PingFangSC-Light;vertical-align: middle;display: inline-block;line-height: 0;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img class="__bg_gif" data-ratio="0.6666666666666666" data-type="gif" data-w="300" width="34px" src="/upload/bc611ab04bb2305c37bf5328df6fe6bd.png" style="font-family: -webkit-standard;letter-spacing: 0.544px;caret-color: rgb(0, 0, 0);vertical-align: middle;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 34px !important;"> </section> <section style="max-width: 100%;font-size: 15px;letter-spacing: 1px;color: rgb(0, 0, 0);font-family: PingFangSC-Light;vertical-align: middle;display: inline-block;line-height: 0;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: rgb(136, 136, 136);box-sizing: border-box !important;overflow-wrap: break-word !important;"> 关注</span> </section> <section style="max-width: 100%;font-size: 15px;letter-spacing: 1px;color: rgb(0, 0, 0);font-family: PingFangSC-Light;vertical-align: middle;display: inline-block;line-height: 0;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: rgb(64, 64, 64);font-size: 16px;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">“</span> <span data-darkmode-bgcolor="rgb(36, 36, 36)" data-darkmode-original-bgcolor="rgb(255, 255, 255)" data-darkmode-color="rgb(120, 172, 254)" data-darkmode-original-color="rgb(120, 172, 254)" style="max-width: 100%;font-size: 16px;letter-spacing: 0.544px;color: rgb(120, 172, 254);box-sizing: border-box !important;overflow-wrap: break-word !important;">脚本之家</span> </section> <section style="max-width: 100%;font-size: 15px;letter-spacing: 1px;color: rgb(0, 0, 0);font-family: PingFangSC-Light;vertical-align: middle;display: inline-block;line-height: 0;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: rgb(136, 136, 136);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">”</span>,与百万开发者在一起</span> </section> </section> <section style="max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img class="rich_pages" data-cropselx1="0" data-cropselx2="578" data-cropsely1="0" data-cropsely2="385" data-ratio="0.6670212765957447" data-s="300,640" src="/upload/585f23d6b21f612d0f5531462e40d063.jpg" data-type="jpeg" data-w="940" style="box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 578px !important;"> </section> <p style="margin-bottom: 15px;max-width: 100%;min-height: 1em;white-space: normal;text-align: left;color: rgb(59, 69, 67);font-size: 15px;background-color: rgb(255, 255, 255);font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 1px;line-height: normal;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 14px;color: rgb(136, 136, 136);box-sizing: border-box !important;overflow-wrap: break-word !important;">本文经授权转自公众号</span><span style="max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 14px;color: rgb(136, 136, 136);box-sizing: border-box !important;overflow-wrap: break-word !important;"> Java建设者</span></p> <p style="margin-bottom: 15px;max-width: 100%;min-height: 1em;white-space: normal;text-align: left;color: rgb(59, 69, 67);font-size: 15px;background-color: rgb(255, 255, 255);font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 1px;line-height: normal;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 14px;color: rgb(136, 136, 136);box-sizing: border-box !important;overflow-wrap: break-word !important;">作者:cxuan</span></p> <p style="margin-bottom: 15px;max-width: 100%;min-height: 1em;white-space: normal;text-align: left;color: rgb(59, 69, 67);font-size: 15px;background-color: rgb(255, 255, 255);font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 1px;line-height: normal;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(136, 136, 136);font-size: 14px;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;">如若转载请联系原公众号</span></p> <p data-mpa-powered-by="yiban.io" style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">这是 MySQL 基础系列的第四篇文章,之前的三篇文章见如下链接</p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5NTY1MjY0MQ==&mid=2650755885&idx=4&sn=287393281fe08bfa6d1a3251e82c9066&chksm=befec66389894f7542a86df4aa50e4b73a06725ecc53b31336e528cb9609ea9c8b1c02ccac12&scene=21#wechat_redirect" textvalue="138 张图带你 MySQL 入门" data-itemshowtype="0" tab="innerlink" data-linktype="2">138 张图带你 MySQL 入门</a><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5NTY1MjY0MQ==&mid=2650806073&idx=5&sn=7c3a0b26f20063c19e97ab91db091285&chksm=bd0182778a760b61954cce345b5997260b32e720c3cab627d99b65e92403390266f166b566fe&scene=21#wechat_redirect" textvalue="47 张图带你 MySQL 进阶!!!" data-itemshowtype="11" tab="innerlink" data-linktype="2">47 张图带你 MySQL 进阶!!!</a><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5NTY1MjY0MQ==&mid=2650786929&idx=5&sn=2aa9040f6e6772c53d5958b58dc08852&chksm=befe593f8989d029a3777726955c9636ecfae22934c2aa4a6cadeb9dec2ec470ec17b331e9f5&scene=21#wechat_redirect" textvalue="炸裂!MySQL 82 张图带你飞!" data-itemshowtype="11" tab="innerlink" data-linktype="2">炸裂!MySQL 82 张图带你飞!</a></p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">一般传统互联网公司很少接触到 SQL 优化问题,其原因是数据量小,大部分厂商的数据库性能能够满足日常的业务需求,所以不需要进行 SQL 优化,但是随着应用程序的不断变大,数据量的激增,数据库自身的性能跟不上了,此时就需要从 SQL 自身角度来进行优化,这也是我们这篇文章所讨论的。</p> <h2 style="margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.4em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">SQL 优化步骤</span></h2> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">当面对一个需要优化的 SQL 时,我们有哪几种排查思路呢?</p> <h3 style="margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.3em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;color: rgb(62, 62, 62);line-height: inherit;border-bottom: 2px solid rgb(33, 152, 99);font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin-right: 3px;padding-top: 3px;padding-right: 10px;padding-left: 10px;max-width: 100%;font-size: inherit;color: rgb(255, 255, 255);line-height: inherit;display: inline-block;font-weight: normal;background: rgb(33, 152, 99);border-top-right-radius: 3px;border-top-left-radius: 3px;box-sizing: border-box !important;overflow-wrap: break-word !important;">通过 show status 命令了解 SQL 执行次数</span></h3> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">首先,我们可以使用 <strong style="max-width: 100%;color: rgb(19, 92, 224);font-size: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">show status</strong> 命令查看服务器状态信息。show status 命令会显示每个服务器变量 variable_name 和 value,状态变量是只读的。如果使用 SQL 命令,可以使用 like 或者 where 条件来限制结果。like 可以对变量名做标准模式匹配。</p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages" data-galleryid="" data-ratio="0.5986301369863014" data-s="300,640" src="/upload/2b926b313ab7544ae88b2e167e1c5737.png" data-type="png" data-w="1460" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 670px !important;visibility: visible !important;"><span style="max-width: 100%;color: rgb(62, 62, 62);font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: 16px;text-align: start;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">图我没有截全,下面还有很多变量,读者可以自己尝试一下。也可以在操作系统上使用 <strong style="max-width: 100%;color: rgb(19, 92, 224);font-size: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">mysqladmin extended-status</strong> 命令来获取这些消息。</p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">但是我执行 mysqladmin extended-status 后,出现这个错误。</p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages" data-galleryid="" data-ratio="0.11519607843137254" data-s="300,640" src="/upload/7105f57c58844894bf4213387526dafd.png" data-type="png" data-w="1632" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 670px !important;visibility: visible !important;"></p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">应该是我没有输入密码的原因,使用 <strong style="max-width: 100%;color: rgb(19, 92, 224);font-size: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">mysqladmin -P3306 -uroot -p -h127.0.0.1 -r -i 1 extended-status</strong> 后,问题解决。<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">这里需要注意一下 show status 命令中可以添加统计结果的级别,这个级别有两个</p> <ul class="list-paddingleft-2" style="padding-left: 32px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;list-style-position: initial;list-style-image: initial;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);overflow-wrap: break-word !important;"> <li style="margin-bottom: 0.5em;max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">session 级:默认当前链接的统计结果</span></p></li> <li style="margin-bottom: 0.5em;max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">global 级:自数据库上次启动到现在的统计结果</span></p></li> </ul> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">如果不指定统计结果级别的话,默认使用 session 级别。</p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">对于 show status 查询出来的统计结果,有两类参数需要注意下,一类是以 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);box-sizing: border-box !important;overflow-wrap: break-word !important;">Com_</code> 为开头的参数,一类是以 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);box-sizing: border-box !important;overflow-wrap: break-word !important;">Innodb_</code> 为开头的参数。</p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">下面是 Com_ 为开头的参数,参数很多,我同样没有截全。</p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages" data-galleryid="" data-ratio="1.7275747508305648" data-s="300,640" src="/upload/d1124d78644cc50da377e10d31e5304b.png" data-type="png" data-w="602" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 467px !important;visibility: visible !important;"></p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">Com_xxx 表示的是每个 xxx 语句执行的次数,我们通常关心的是 select 、insert 、update、delete 语句的执行次数,即</p> <ul class="list-paddingleft-2" style="padding-left: 32px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;list-style-position: initial;list-style-image: initial;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);overflow-wrap: break-word !important;"> <li style="margin-bottom: 0.5em;max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">Com_select:执行 select 操作的次数,一次查询会使结果 + 1。</span></p></li> <li style="margin-bottom: 0.5em;max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">Com_insert:执行 INSERT 操作的次数,对于批量插入的 INSERT 操作,只累加一次。</span></p></li> <li style="margin-bottom: 0.5em;max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">Com_update:执行 UPDATE 操作的次数。</span></p></li> <li style="margin-bottom: 0.5em;max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">Com_delete:执行 DELETE 操作的次数。</span></p></li> </ul> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">以 Innodb_ 为开头的参数主要有</p> <ul class="list-paddingleft-2" style="padding-left: 32px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;list-style-position: initial;list-style-image: initial;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);overflow-wrap: break-word !important;"> <li style="margin-bottom: 0.5em;max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">Innodb_rows_read:执行 select 查询返回的行数。</span></p></li> <li style="margin-bottom: 0.5em;max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">Innodb_rows_inserted:执行 INSERT 操作插入的行数。</span></p></li> <li style="margin-bottom: 0.5em;max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">Innodb_rows_updated:执行 UPDATE 操作更新的行数。</span></p></li> <li style="margin-bottom: 0.5em;max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">Innodb_rows_deleted:执行 DELETE 操作删除的行数。</span></p></li> </ul> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">通过上面这些参数执行结果的统计,我们能够大致了解到当前数据库是以更新(包括插入、删除)为主还是查询为主。</p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">除此之外,还有一些其他参数用于了解数据库的基本情况。</p> <ul class="list-paddingleft-2" style="padding-left: 32px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;list-style-position: initial;list-style-image: initial;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);overflow-wrap: break-word !important;"> <li style="margin-bottom: 0.5em;max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">Connections:查询 MySQL 数据库的连接次数,这个次数是不管连接是否成功都算上。</span></p></li> <li style="margin-bottom: 0.5em;max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">Uptime:服务器的工作时间。</span></p></li> <li style="margin-bottom: 0.5em;max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">Slow_queries:满查询次数。</span></p></li> <li style="margin-bottom: 0.5em;max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">Threads_connected:查看当前打开的连接的数量。</span></p></li> </ul> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">下面这个博客汇总了几乎所有 show status 的参数,可以当作参考手册。</p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">https://blog.csdn.net/ayay_870621/article/details/88633092</p> <h3 style="margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.3em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;color: rgb(62, 62, 62);line-height: inherit;border-bottom: 2px solid rgb(33, 152, 99);font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin-right: 3px;padding-top: 3px;padding-right: 10px;padding-left: 10px;max-width: 100%;font-size: inherit;color: rgb(255, 255, 255);line-height: inherit;display: inline-block;font-weight: normal;background: rgb(33, 152, 99);border-top-right-radius: 3px;border-top-left-radius: 3px;box-sizing: border-box !important;overflow-wrap: break-word !important;">定位执行效率较低的 SQL</span></h3> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">定位执行效率比较慢的 SQL 语句,一般有两种方式</p> <ul class="list-paddingleft-2" style="padding-left: 32px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;list-style-position: initial;list-style-image: initial;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);overflow-wrap: break-word !important;"> <li style="margin-bottom: 0.5em;max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;">可以通过<strong style="max-width: 100%;color: rgb(19, 92, 224);font-size: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">慢查询日志</strong>来定位哪些执行效率较低的 SQL 语句。</p></li> </ul> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">MySQL 中提供了一个慢查询的日志记录功能,可以把查询 SQL 语句时间大于多少秒的语句写入慢查询日志,日常维护中可以通过慢查询日志的记录信息快速准确地判断问题所在。用 --log-slow-queries 选项启动时,mysqld 会写一个包含所有执行时间超过 long_query_time 秒的 SQL 语句的日志文件,通过查看这个日志文件定位效率较低的 SQL 。</p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">比如我们可以在 my.cnf 中添加如下代码,然后退出重启 MySQL。</p> <pre style="max-width: 100%;letter-spacing: 0.544px;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;font-size: 14px;color: rgb(233, 105, 0);line-height: 18px;border-radius: 0px;background: rgb(248, 248, 248);font-family: Consolas, Inconsolata, Courier, monospace;letter-spacing: 0px;box-sizing: border-box !important;overflow-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">log-slow-queries = /tmp/mysql-slow.log<br style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">long_query_time = 2<br style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;"></code></pre> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">通常我们设置最长的查询时间是 2 秒,表示查询时间超过 2 秒就记录了,通常情况下 2 秒就够了,然而对于很多 WEB 应用来说,2 秒时间还是比较长的。</p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">也可以通过命令来开启:</p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">我们先查询 MySQL 慢查询日志是否开启</p> <pre style="max-width: 100%;letter-spacing: 0.544px;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;font-size: 14px;color: rgb(233, 105, 0);line-height: 18px;border-radius: 0px;background: rgb(248, 248, 248);font-family: Consolas, Inconsolata, Courier, monospace;letter-spacing: 0px;box-sizing: border-box !important;overflow-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">show variables like "%slow%";<br style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;"></code></pre> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages" data-galleryid="" data-ratio="0.3702290076335878" data-s="300,640" src="/upload/fd27b65882f5ac9d6dcabd4eba4b26f2.png" data-type="png" data-w="1048" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 670px !important;visibility: visible !important;"></p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">启用慢查询日志</p> <pre style="max-width: 100%;letter-spacing: 0.544px;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;font-size: 14px;color: rgb(233, 105, 0);line-height: 18px;border-radius: 0px;background: rgb(248, 248, 248);font-family: Consolas, Inconsolata, Courier, monospace;letter-spacing: 0px;box-sizing: border-box !important;overflow-wrap: normal !important;display: block !important;word-break: normal !important;overflow: auto !important;">set global slow_query_log='ON';<br style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;"></code></pre> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages" data-galleryid="" data-ratio="0.1657754010695187" data-s="300,640" src="/upload/cb3e37c6e8e303b2c528ef725cb24a08.png" data-type="png" data-w="1122" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 670px !important;visibility: visible !important;"></p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">然后再次查询慢查询是否开启</p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages" data-galleryid="" data-ratio="0.39122137404580154" data-s="300,640" src="/upload/a61462fe99b68b0321cfe9265768cd33.png" data-type="png" data-w="1048" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 670px !important;visibility: visible !important;"></p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">如图所示,我们已经开启了慢查询日志。</p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">慢查询日志会在查询结束以后才记录,所以在应用反应执行效率出现问题的时候慢查询日志并不能定位问题,此时应该使用 <strong style="max-width: 100%;color: rgb(19, 92, 224);font-size: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">show processlist</strong> 命令查看当前 MySQL 正在进行的线程。包括线程的状态、是否锁表等,可以实时的查看 SQL 执行情况。同样,使用<strong style="max-width: 100%;color: rgb(19, 92, 224);font-size: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">mysqladmin processlist</strong>语句也能得到此信息。</p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages" data-galleryid="" data-ratio="0.22443890274314215" data-s="300,640" src="/upload/dea4ad988574ddfdf37585571eae08d7.png" data-type="png" data-w="1604" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 670px !important;visibility: visible !important;"></p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">下面就来解释一下各个字段对应的概念</p> <ul class="list-paddingleft-2" style="padding-left: 32px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;list-style-position: initial;list-style-image: initial;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);overflow-wrap: break-word !important;"> <li style="margin-bottom: 0.5em;max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">Id :Id 就是一个标示,在我们使用 kill 命令杀死进程的时候很有用,比如 kill 进程号。</span></p></li> <li style="margin-bottom: 0.5em;max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">User:显示当前的用户,如果不是 root,这个命令就只显示你权限范围内的 SQL 语句。</span></p></li> <li style="margin-bottom: 0.5em;max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">Host:显示 IP
作者:微信小助手
<p style="text-align: center;" data-mpa-powered-by="yiban.io"><span style="color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;font-size: 16px;"></span><img data-backh="354" data-backw="500" data-ratio="0.708" src="/upload/4584a412743ac346f4a3bad7db5c3238.jpg" data-type="jpeg" data-w="500" style="width: 100%;height: auto;"><span style="color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;font-size: 16px;"></span></p> <p style="max-width: 100%;min-height: 1em;white-space: normal;font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-align: left;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.75px;">我们数据库中的数据一直在变化,有时候我们希望能监听数据库数据的变化并根据变化做出一些反应,比如更新对应变化数据的缓存、增量同步到其它数据源、对数据进行检测和审计等等。</span><span style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.75px;">而这种技术就叫</span><strong style="font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.75px;color: rgb(53, 179, 120);">变更数据捕获(Change Data Capture)</strong><span style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.75px;">。</span><span style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.75px;">对于这种技术我们可能知道一个国内比较知名的框架</span><strong style="font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.75px;color: rgb(53, 179, 120);">Canal</strong><span style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.75px;">,非常好用!</span><span style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.75px;">但是</span><strong style="font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.75px;color: rgb(53, 179, 120);">Canal</strong><span style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.75px;">有一个局限性就是只能用于</span><strong style="font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.75px;color: rgb(53, 179, 120);">Mysql</strong><span style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.75px;">的变更数据捕获。</span><span style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.75px;">今天来介绍另一种更加强大的分布式CDC框架</span><strong style="font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.75px;color: rgb(53, 179, 120);">Debezium</strong><span style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.75px;">。</span><span style="max-width: 100%;letter-spacing: 0.544px;color: rgb(178, 178, 178);font-family: Optima-Regular, PingFangTC-light;font-size: 13px;overflow-wrap: break-word !important;box-sizing: border-box !important;"></span></p> <h3 style="margin-top: 1.2em;margin-bottom: 1em;color: rgb(53, 179, 120);font-weight: bold;font-size: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">Debezium</h3> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">提起<strong style="color: rgb(53, 179, 120);">Debezium</strong>这个框架,相信大多数普通开发者都比较陌生,但是提及它所属的公司大家一定不会陌生。</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: center;white-space: normal;background-color: rgb(255, 255, 255);"><img data-backh="175" data-backw="570" data-ratio="0.3074074074074074" src="/upload/f17f0e7c646246efb0b69706efdbcd70.png" data-type="png" data-w="1080" style="width: 100%;height: auto;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&mid=2247534448&idx=1&sn=a8cd3973ed6850d1cb5cbec7637eca16&chksm=9bd3eae8aca463feb3adcef2e10dc557c87fc071617f4d4816c562197fc4dc14f83b4ed7a20e&scene=21#wechat_redirect" textvalue="红帽公司" data-itemshowtype="0" tab="innerlink" data-linktype="2"><span style="color: rgb(178, 178, 178);font-size: 14px;">红帽公司</span></a></p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">没错就是开源界最成功的<strong style="color: rgb(53, 179, 120);">红帽公司</strong>。<strong style="color: rgb(53, 179, 120);">Debezium</strong>是为捕获数据更改的流式处理框架,开源免费。<strong style="color: rgb(53, 179, 120);">Debezium</strong>近乎实时地监控数据库行级别(row-level)的数据变更,并针对变更可以做出反应。而且只有已提交的变更才是可见的,所以不用担心事务问题或者更改被回滚的问题。<strong style="color: rgb(53, 179, 120);">Debezium</strong>为所有的数据库更改事件提供了一个统一的模型,所以不用担心每种数据库系统的复杂性。<strong style="color: rgb(53, 179, 120);">Debezium</strong>提供了对<strong style="color: rgb(53, 179, 120);">MongoDB</strong>、<strong style="color: rgb(53, 179, 120);">MySQL</strong>、<strong style="color: rgb(53, 179, 120);">PostgreSQL</strong>、<strong style="color: rgb(53, 179, 120);">SQL Server</strong>、<strong style="color: rgb(53, 179, 120);">Oracle</strong>、<strong style="color: rgb(53, 179, 120);">DB2</strong>等数据库的支持。</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">另外借助于<strong style="color: rgb(53, 179, 120);">Kafka Connector</strong>可以开发出一个基于事件流的变更捕获平台,具有高容错率和极强的扩展性。</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: center;white-space: normal;background-color: rgb(255, 255, 255);"><img data-backh="129" data-backw="570" data-ratio="0.22685185185185186" src="/upload/7f1d72a0f16ef94acf20256982cf6135.png" data-type="png" data-w="1080" style="width: 100%;height: auto;"> <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&mid=2247534448&idx=4&sn=a405d7cf246fb10e6a29aad299e9b624&chksm=9bd3eae8aca463fea76e553ca74336b1798d5d4a88ef0085871f4e31e687b8f44462055c7481&scene=21#wechat_redirect" textvalue="Debezium Kafka 架构" data-itemshowtype="11" tab="innerlink" data-linktype="2"><span style="color: rgb(178, 178, 178);font-size: 14px;">Debezium Kafka 架构</span></a></p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">如图所示,部署了用于 MySQL 和 PostgresSQL 的 Debezium Kafka连接器以捕获对这两种类型数据库的更改事件,然后将这些更改通过下游的Kafka Connector将记录传输到其他系统或者数据库(例如 <strong style="color: rgb(53, 179, 120);">Elasticsearch</strong>、数据仓库、分析系统)或缓存。</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">另一种玩法就是将<strong style="color: rgb(53, 179, 120);">Debezium</strong>内置到应用程序中,来做一个类似消息总线的设施,将数据变更事件传递给订阅的下游系统中。</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: center;white-space: normal;background-color: rgb(255, 255, 255);"><img data-backh="164" data-backw="570" data-ratio="0.28703703703703703" src="/upload/daab6e4cd4f950aef490e8c70dd55fec.png" data-type="png" data-w="1080" style="width: 100%;height: auto;"> <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&mid=2247534448&idx=2&sn=9e8ac2f6907b03b6379239
作者:微信小助手
<section powered-by="xiumi.us"> <section> <section powered-by="xiumi.us"> <section> <br> </section> <section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzU5NDg5MzM5NQ==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/BdQKIO6XpMXZa2U8FCySWQFV4y6HRtFxddNQ6d2hDu4cjqr8wOfrtBDKayTeRia44dtR9wJErHNGACdkMz8xvyQ/0?wx_fmt=png" data-nickname="波哥的IT人生" data-alias="itboge" data-signature="十五年IT老兵!全栈开发、运维开发、devops,python、vue等视频教学,IT行业技术与资讯分享!"></mpprofile> </section> </section> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-weight: bold;font-size: 20px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(0, 82, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">文章来</strong><strong style="max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(0, 82, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">源:</strong><strong style="max-width: 100%;color: rgba(0, 0, 0, 0.498);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(0, 82, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">自安全鸭</span></strong></span></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-weight: bold;font-size: 20px;box-sizing: border-box !important;overflow-wrap: break-word !important;">一、Linux安全加固常见查询命令</span></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;font-weight: bold;box-sizing: border-box !important;overflow-wrap: break-word !important;">1.应按照不同的用户分配不同的账号。避免不同用户间共享账号。避免用户账号和设备间通信使用的账号共享</span></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="nginx"><code style=" max-width: 1000%;text-align: left;white-space: pre-wrap;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important; "><span class="code-snippet_outer" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet__attribute" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">cat</span> /etc/passwd</span></code><code style=" max-width: 1000%;text-align: left;white-space: pre-wrap;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important; "><span class="code-snippet_outer" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet__comment" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">#</span></span></code></pre> </section> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;">不同的用户拥有不同的账号;</p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="nginx"><code style=" max-width: 1000%;text-align: left;white-space: pre-wrap;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important; "><span class="code-snippet_outer" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet__attribute" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">useradd</span> username <span class="code-snippet__comment" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">#创建账号</span></span></code><code style=" max-width: 1000%;text-align: left;white-space: pre-wrap;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important; "><span class="code-snippet_outer" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">passwd username <span class="code-snippet__comment" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">#设置密码</span></span></code><code style=" max-width: 1000%;text-align: left;white-space: pre-wrap;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important; "><span class="code-snippet_outer" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">chmod <span class="code-snippet__number" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">750</span> directory <span class="code-snippet__comment" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">#为要更改权限的目录根据实际情况设置权限</span></span></code></pre> </section> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;font-weight: bold;box-sizing: border-box !important;overflow-wrap: break-word !important;">2.应删除或锁定与设备运行、维护等工作无关的账号。</span></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="perl"><code style=" max-width: 1000%;text-align: left;white-space: pre-wrap;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important; "><span class="code-snippet_outer" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">cat /etc/passwd | <span class="code-snippet__keyword" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">grep</span> -i -E <span class="code-snippet__string" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">"listen|gdm|webservd|nobody|nobody4|noaccess"</span></span></code><code style=" max-width: 1000%;text-align: left;white-space: pre-wrap;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important; "><span class="code-snippet_outer" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">cat /etc/shadow | <span class="code-snippet__keyword" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">grep</span> -i -E <span class="code-snippet__string" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">"listen|gdm|webservd|nobody|nobody4|noaccess"</span></span></code><code style=" max-width: 1000%;text-align: left;white-space: pre-wrap;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important; "><span class="code-snippet_outer" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet__comment" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">#锁定用户:#修改/etc/shadow 文件,用户名后加*LK*</span></span></code><code style=" max-width: 1000%;text-align: left;white-space: pre-wrap;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important; "><span class="code-snippet_outer" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet__comment" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">#将/etc/passwd文件中的shell域设置成/bin/false,/bin/false是最严格的禁止login选项,一切服务都不能用</span></span></code><code style=" max-width: 1000%;text-align: left;white-space: pre-wrap;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important; "><span class="code-snippet_outer" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet__comment" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">#/usr/sbin/nologin:nologin会礼貌的向用户显示一条信息,并拒绝用户登录</span></span></code><code style=" max-width: 1000%;text-align: left;white-space: pre-wrap;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important; "><span class="code-snippet_outer" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">passwd -l username <span class="code-snippet__comment" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">#锁定用户</span></span></code><code style=" max-width: 1000%;text-align: left;white-space: pre-wrap;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important; "><span class="code-snippet_outer" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">passwd – d username <span class="code-snippet__comment" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">#解锁用户。原有密码失效,登录需输入新密码</span></span></code></pre> </section> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;box-sizing: border-box !important;overflow-wrap: break-word !important;">3.</span><span style="max-width: 100%;font-size: 16px;font-family: SimSun, STSong;box-sizing: border-box !important;overflow-wrap: break-word !important;">根据系统要求及用户的业务需求,建立多帐户组,将用户账号分配到相应的帐户组</span></strong><span style="max-width: 100%;font-size: 16px;font-family: SimSun, STSong;font-weight: bold;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="cs"><code style=" max-width: 1000%;text-align: left;white-space: pre-wrap;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important; "><span class="code-snippet_outer" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">cat /etc/passwd </span></code><code style=" max-width: 1000%;text-align: left;white-space: pre-wrap;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important; "><span class="code-snippet_outer" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">cat /etc/<span class="code-snippet__keyword" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">group</span></span></code><code style=" max-width: 1000%;text-align: left;white-space: pre-wrap;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important; "><span class="code-snippet_outer"><br></span></code><code style=" max-width: 1000%;text-align: left;white-space: pre-wrap;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important; "><span class="code-snippet_outer" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">groupadd –g GID groupname <span class="code-snippet__meta" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">#创建一个组,并为其设置 GID 号,若不设 GID,系统会自动为该组分配一个 GID 号</span></span></code><code style=" max-width: 1000%;text-align: left;white-space: pre-wrap;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important; "><span class="code-snippet_outer" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">usermod –g <span class="code-snippet__keyword" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">group</span> username <span class="code-snippet__meta" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">#将用户 username 分配到 group 组中</span></span></code></pre> </section> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;box-sizing: border-box !important;overflow-wrap: break-word !important;">4.</span><span style="max-width: 100%;font-size: 16px;font-family: SimSun, STSong;box-sizing: border-box !important;overflow-wrap: break-word !important;">使用</span><span style="max-width: 100%;font-size: 16px;font-family: SimSun, STSong;box-sizing: border-box !important;overflow-wrap: break-word !important;">PAM</span><span style="max-width: 100%;font-size: 16px;font-family: SimSun, STSong;box-sizing: border-box !important;overflow-wrap: break-word !important;">禁止任何人</span><span style="max-width: 100%;font-size: 16px;font-family: SimSun, STSong;box-sizing: border-box !important;overflow-wrap: break-word !important;">su</span><span style="max-width: 100%;font-size: 16px;font-family: SimSun, STSong;box-sizing: border-box !important;overflow-wrap: break-word !important;">为</span><span style="max-width: 100%;font-size: 16px;font-family: SimSun, STSong;box-sizing: border-box !important;overflow-wrap: break-word !important;">root</span></strong></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="properties"><code style=" max-width: 1000%;text-align: left;white-space: pre-wrap;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important; "><span class="code-snippet_outer" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet__attr" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">cat</span> <span class="code-snippet__string" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">/etc/pam.d/su</span></span></code><code style=" max-width: 1000%;text-align: left;white-space: pre-wrap;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important; "><span class="code-snippet_outer" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span></code><code style=" max-width: 1000%;text-align: left;white-space: pre-wrap;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important; "><span class="code-snippet_outer" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet__attr" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">auth</span> <span class="code-snippet__string" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">sufficient /lib/security/pam_rootok.so</span></span></code><code style=" max-width: 1000%;text-align: left;white-space: pre-wrap;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important; "><span class="code-snippet_outer" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet__attr" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">auth</span> <span class="code-snippet__string" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">required /lib/security/pam_wheel.so group=wheel</span></span></code><code style=" max-width: 1000%;text-align: left;white-space: pre-wrap;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important; "><span class="code-snippet_outer" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet__comment" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">#有这两行表明只有wheel组的成员可以使用su命令成为root用户。即符合要求</span></span></code><code style=" max-width: 1000%;text-align: left;white-space: pre-wrap;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important; "><span class="code-snippet_outer" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet__attr" style="max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">usermod –G groupname username #把用户添加到wheel组,使它可以使用su命令成为root用户</span></span></code></pre> </section> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;box-sizing: border-box !important;overflow-wrap: break-word !important;">5.</span><span style="max-width: 100%;font-size: 16px;font-family: SimSun, STSong;box-sizing: border-box !important;overflow-wrap: break-word !important;">对于采用静态口令认证技术的设备,口令长度至少</span><span style="max-width: 100%;font-size: 16px;font-family: SimSun, STSong;box-sizing: border-box !important;overflow-wrap: break-word !important;">8</span><span style="max-width: 100%;font-size: 16px;font-family: SimSun, STSong;box-sizing: border-box !important;overflow-wrap: break-word !important;">位,并包括数字、小写字母、大写字�
作者:微信小助手
<pre style="" data-mpa-powered-by="yiban.io"> <section data-tools="135编辑器" data-id="95966" style="font-size: 16px;"> <section data-tools="135编辑器" data-id="92987"> <section data-width="100%" style="padding-top: 20px;padding-bottom: 20px;width: 578px;text-align: center;"> <section style="display: inline-block;"> <section style="display: inline-block;"> <section data-width="100%" style="width: 364px;"> <section style="padding-right: 0.5em;padding-left: 0.5em;background: rgb(255, 201, 15);color: rgb(0, 0, 0);border-radius: 25px;justify-content: center;display: -webkit-flex;align-items: center;"> <section data-brushtype="text" style="padding-right: 0.5em;padding-left: 0.5em;height: 35px;display: inline-block;line-height: 35px;letter-spacing: 1px;font-weight: bold;"> <br> </section> <section data-brushtype="text" style="padding-right: 0.5em;padding-left: 0.5em;height: 35px;display: inline-block;line-height: 35px;letter-spacing: 1px;font-weight: bold;"> 今日干货推送 </section> </section> </section> </section> </section> </section> </section> </section> <section data-role="paragraph"> <p style="text-align: center;"><br></p> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.45188284518828453" data-s="300,640" src="/upload/d7b20e563b6aa3658df7d553f264722b.jpg" data-type="jpeg" data-w="956" style=""></p> </section></pre> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style=""> <h3 data-tool="mdnice编辑器" style="margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;margin-top: 1.2em;"><span style="background-image: url("https://mmbiz.qpic.cn/mmbiz_png/tWOhQMr1wdBpCrR8MBf6XIzvFtITWOicRMhodHMFes9k2EMNlELr74czI6kvGhAOL94cZpMbxFxMLJFOFbib74Iw/640?wx_fmt=png");background-size: 100% 100%;background-repeat: no-repeat;display: inline-block;width: 16px;height: 15px;line-height: 15px;margin-bottom: -1px;"></span><span style="display: none;"></span><span style="font-size: 17px;display: inline-block;margin-left: 8px;color: rgb(72, 179, 120);">一、摘要</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">在实际的业务开发过程中,我们常常会碰到需要与第三方互联网公司进行技术对接,例如支付宝支付对接、微信支付对接、高德地图查询对接等等服务,如果你是一个创业型互联网,大部分可能都是对接别的公司api接口。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">当你的公司体量上来了时候,这个时候可能有一些公司开始找你进行技术对接了,转变成由你来提供api接口,那这个时候,我们应该如何设计并保证API接口安全呢?</p> <h3 data-tool="mdnice编辑器" style="margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;margin-top: 1.2em;"><span style="background-image: url("https://mmbiz.qpic.cn/mmbiz_png/tWOhQMr1wdBpCrR8MBf6XIzvFtITWOicRMhodHMFes9k2EMNlELr74czI6kvGhAOL94cZpMbxFxMLJFOFbib74Iw/640?wx_fmt=png");background-size: 100% 100%;background-repeat: no-repeat;display: inline-block;width: 16px;height: 15px;line-height: 15px;margin-bottom: -1px;"></span><span style="display: none;"></span><span style="font-size: 17px;display: inline-block;margin-left: 8px;color: rgb(72, 179, 120);">二、方案介绍</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">最常用的方案,主要有两种:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> token方案 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 接口签名 </section></li> </ul> <h4 data-tool="mdnice编辑器" style="margin-bottom: 15px;font-weight: bold;color: black;font-size: 18px;margin-top: 30px;"><span style="display: none;"></span>2.1、token方案<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">其中 token 方案,是一种在web端使用最广的接口鉴权方案,我记得在之前写过一篇《手把手教你,使用JWT实现单点登录》的文章,里面介绍的比较详细,有兴趣的朋友可以看一下,没了解的也没关系,我们在此简单的介绍一下 token 方案。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.6885007278020379" src="/upload/828c79e9b2d53d9c14876254f674fbff.png" data-type="png" data-w="687" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">从上图,我们可以很清晰的看到,token 方案的实现主要有以下几个步骤:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 1、用户登录成功之后,服务端会给用户生成一个唯一有效的凭证,这个有效值被称为token </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 2、当用户每次请求其他的业务接口时,需要在请求头部带上token </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 3、服务端接受到客户端业务接口请求时,会验证token的合法性,如果不合法会提示给客户端;如果合法,才会进入业务处理流程。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">在实际使用过程中,当用户登录成功之后,生成的token存放在redis中时是有时效的,一般设置为2个小时,过了2个小时之后会自动失效,这个时候我们就需要重新登录,然后再次获取有效token。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">token方案,是目前业务类型的项目当中使用最广的方案,而且实用性非常高,可以很有效的防止黑客们进行抓包、爬取数据。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">但是 token 方案也有一些缺点!最明显的就是与第三方公司进行接口对接的时候,当你的接口请求量非常大,这个时候 token 突然失效了,会有大量的接口请求失败。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">这个我深有体会,我记得在很早的时候,跟一家中、大型互联网公司进行联调的时候,他们提供给我的接口对接方案就是token方案,当时我司的流量高峰期时候,请求他们的接口大量报错,原因就是因为token失效了,当token失效时,我们会调用他们刷新token接口,刷新完成之后,在token失效与重新刷新token这个时间间隔期间,就会出现大量的请求失败的日志,因此在实际API对接过程中,我不推荐大家采用 token方案。</p> <h4 data-tool="mdnice编辑器" style="margin-bottom: 15px;font-weight: bold;color: black;font-size: 18px;margin-top: 30px;"><span style="display: none;"></span>2.2、接口签名<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">接口签名,顾名思义,就是通过一些签名规则对参数进行签名,然后把签名的信息放入请求头部,服务端收到客户端请求之后,同样的只需要按照已定的规则生产对应的签名串与客户端的签名信息进行对比,如果一致,就进入业务处理流程;如果不通过,就提示签名验证失败。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.46296296296296297" src="/upload/3a033b2ad25ff879c389ec5729ac328e.jpg" data-type="jpeg" data-w="1080" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">在接口签名方案中,主要有四个核心参数:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 1、appid表示应用ID,其中与之匹配的还有appsecret,表示应用密钥,用于数据的签名加密,不同的对接项目分配不同的appid和appsecret,保证数据安全 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 2、timestamp 表示时间戳,当请求的时间戳与服务器中的时间戳,差值在5分钟之内,属于有效请求,不在此范围内,属于无效请求 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 3、nonce 表示临时流水号,用于防止重复提交验证 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 4、signature 表示签名字段,用于判断接口请求是否有效。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">其中签名的生成规则,分两个步骤:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 第一步:对请求参数进行一次md5加密签名 </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("https://mmbiz.qpic.cn/mmbiz_svg/3Lqm1xHojtYV02xvhcJIbKuG495Kussib6UcCKRR6Hd9gcvlsJSEzTcaXGek3BzeuqNI0qZu3CtREubY7GGHYbSMKTzAfC0E8/640?wx_fmt=svg") 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;">//步骤一<br>String 参数1 = 请求方式 + 请求URL相对地址 + 请求Body字符串;<br>String 参数1加密结果= md5(参数1)<br></code></pre> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 第二步:对第一步签名结果,再进行一次md5加密签名 </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("https://mmbiz.qpic.cn/mmbiz_svg/3Lqm1xHojtYV02xvhcJIbKuG495Kussib6UcCKRR6Hd9gcvlsJSEzTcaXGek3BzeuqNI0qZu3CtREubY7GGHYbSMKTzAfC0E8/640?wx_fmt=svg") 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;">//步骤二<br>String 参数2 = appsecret + timestamp + nonce + 参数1加密结果;<br>String 参数2加密结果= md5(参数2)<br></code></pre> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">参数2加密结果,就是我们要的最终签名串。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">接口签名方案,尤其是在接口请求量很大的情况下,依然很稳定。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">换句话说,你可以将接口签名看作成对token方案的一种补充。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">但是如果想把接口签名方案,推广到前后端对接,答案是:不适合。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">因为签名计算非常复杂,其次,就是容易泄漏appsecret!</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">说了这么多,下面我们就一起来用程序实践一下吧!</p> <h3 data-tool="mdnice编辑器" style="margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;margin-top: 1.2em;"><span style="background-image: url("https://mmbiz.qpic.cn/mmbiz_png/tWOhQMr1wdBpCrR8MBf6XIzvFtITWOicRMhodHMFes9k2EMNlELr74czI6kvGhAOL94cZpMbxFxMLJFOFbib74Iw/640?wx_fmt=png");background-size: 100% 100%;background-repeat: no-repeat;display: inline-block;width: 16px;height: 15px;line-height: 15px;margin-bottom: -1px;"></span><span style="display: none;"></span><span style="font-size: 17px;display: inline-block;margin-left: 8px;color: rgb(72, 179, 120);">二、程序实践</span><span style="display: none;"></span></h3> <h4 data-tool="mdnice编辑器" style="margin-bottom: 15px;font-weight: bold;color: black;font-size: 18px;margin-top: 30px;"><span style="display: none;"></span>2.1、token方案<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">就像上文所说,token方案重点在于,当用户登录成功之后,我们只需要生成好对应的token,然后将其返回给前端,在下次请求业务接口的时候,需要把token带上。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">具体的实践,也可以分两种:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 第一种:采用uuid生成token,然后将token存放在redis中,同时设置有效期2个小时 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 第二种:采用JWT工具来生成token,这种token是可以跨平台的,天然支持分布式,其实本质也是采用时间戳+密钥,来生成一个token。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">下面,我们介绍的是第二种实现方式。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">首先,编写一个jwt 工具。</p> <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("https://mmbiz.qpic.cn/mmbiz_svg/3Lqm1xHojtYV02xvhcJIbKuG495Kussib6UcCKRR6Hd9gcvlsJSEzTcaXGek3BzeuqNI0qZu3CtREubY7GGHYbSMKTzAfC0E8/640?wx_fmt=svg") 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> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span> <span style="color: #e6c07b;line-height: 26px;">JwtTokenUtil</span> </span>{<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">//定义token返回头部</span><br> <span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">static</span> <span style="color: #c678dd;line-height: 26px;">final</span> String AUTH_HEADER_KEY = <span style="color: #98c379;line-height: 26px;">"Authorization"</span>;<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">//token前缀</span><br> <span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">static</span> <span style="color: #c678dd;line-height: 26px;">final</span> String TOKEN_PREFIX = <span style="color: #98c379;line-height: 26px;">"Bearer "</span>;<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">//签名密钥</span><br> <span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">static</span> <span style="color: #c678dd;line-height: 26px;">final</span> String KEY = <span style="color: #98c379;line-height: 26px;">"q3t6w9z$C&F)J@NcQfTjWnZr4u7x"</span>;<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">//有效期默认为 2hour</span><br> <span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">static</span> <span style="color: #c678dd;line-height: 26px;">final</span> Long EXPIRATION_TIME = <span style="color: #d19a66;line-height: 26px;">1000L</span>*<span style="color: #d19a66;line-height: 26px;">60</span>*<span style="color: #d19a66;line-height: 26px;">60</span>*<span style="color: #d19a66;line-height: 26px;">2</span>;<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">/**<br> * 创建TOKEN<br> * <span style="color: #c678dd;line-height: 26px;">@param</span> content<br> * <span style="color: #c678dd;line-height: 26px;">@return</span><br> */</span><br> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">static</span> String <span style="color: #61aeee;line-height: 26px;">createToken</span><span style="line-height: 26px;">(String content)</span></span>{<br> <span style="color: #c678dd;line-height: 26px;">return</span> TOKEN_PREFIX + JWT.create()<br> .withSubject(content)<br> .withExpiresAt(<span style="color: #c678dd;line-height: 26px;">new</span> Date(System.currentTimeMillis() + EXPIRATION_TIME))<br> .sign(Algorithm.HMAC512(KEY));<br> }<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">/**<br> * 验证token<br> * <span style="color: #c678dd;line-height: 26px;">@param</span> token<br> */</span><br> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">static</span> String <span style="color: #61aeee;line-height: 26px;">verifyToken</span><span style="line-height: 26px;">(String token)</span> <span style="color: #c678dd;line-height: 26px;">throws</span> Exception </span>{<br> <span style="color: #c678dd;line-height: 26px;">try</span> {<br> <span style="color: #c678dd;line-height: 26px;">return</span> JWT.require(Algorithm.HMAC512(KEY))<br> .build()<br> .verify(token.replace(TOKEN_PREFIX, <span style="color: #98c379;line-height: 26px;">""</span>))<br> .getSubject();<br> } <span style="color: #c678dd;line-height: 26px;">catch</span> (TokenExpiredException e){<br> <span style="color: #c678dd;line-height: 26px;">throw</span> <span style="color: #c678dd;line-height: 26px;">new</span> Exception(<span style="color: #98c379;line-height: 26px;">"token已失效,请重新登录"</span>,e);<br> } <span style="color: #c678dd;line-height: 26px;">catch</span> (JWTVerificationException e) {<br> <span style="color: #c678dd;line-height: 26px;">throw</span> <span style="color: #c678dd;line-height: 26px;">new</span> Exception(<span style="color: #98c379;line-height: 26px;">"token验证失败!"</span>,e);<br> }<br> }<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">接着,我们在登录的时候,生成一个token,然后返回给客户端。</p> <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("https://mmbiz.qpic.cn/mmbiz_svg/3Lqm1xHojtYV02xvhcJIbKuG495Kussib6UcCKRR6Hd9gcvlsJSEzTcaXGek3BzeuqNI0qZu3CtREubY7GGHYbSMKTzAfC0E8/640?wx_fmt=svg") 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: #61aeee;line-height: 26px;">@RequestMapping</span>(value = <span style="color: #98c379;line-height: 26px;">"/login"</span>, method = RequestMethod.POST, produces = {<span style="color: #98c379;line-height: 26px;">"application/json;charset=UTF-8"</span>})<br><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> UserVo <span style="color: #61aeee;line-height: 26px;">login</span><span style="line-height: 26px;">(@RequestBody UserDto userDto, HttpServletResponse response)</span></span>{<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">//...参数合法性验证</span><br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">//从数据库获取用户信息</span><br> User dbUser = userService.selectByUserNo(userDto.getUserNo);<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">//....用户、密码验证</span><br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">//创建token,并将token放在响应头</span><br> UserToken userToken = <span style="color: #c678dd;line-height: 26px;">new</span> UserToken();<br> BeanUtils.copyProperties(dbUser,userToken);<br> String token = JwtTokenUtil.createToken(JSONObject.toJSONString(userToken));<br> response.setHeader(JwtTokenUtil.AUTH_HEADER_KEY, token);<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">//定义返回结果</span><br> UserVo result = <span style="color: #c678dd;line-height: 26px;">new</span> UserVo();<br> BeanUtils.copyProperties(dbUser,result);<br> <span style="color: #c678dd;line-height: 26px;">return</span> result;<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">最后,编写一个统一拦截器,用于验证客户端传入的token是否有效。</p> <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("https://mmbiz.qpic.cn/mmbiz_svg/3Lqm1xHojtYV02xvhcJIbKuG495Kussib6UcCKRR6Hd9gcvlsJSEzTcaXGek3BzeuqNI0qZu3CtREubY7GGHYbSMKTzAfC0E8/640?wx_fmt=svg") 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: #61aeee;line-height: 26px;">@Slf</span>4j<br><span style="color: #c678dd;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span> <span style="color: #e6c07b;line-height: 26px;">AuthenticationInterceptor</span> <span style="color: #c678dd;line-height: 26px;">implements</span> <span style="color: #e6c07b;line-height: 26px;">HandlerInterceptor</span> </span>{<br> <span style="color: #61aeee;line-height: 26px;">@Override</span><br> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">boolean</span> <span style="color: #61aeee;line-height: 26px;">preHandle</span><span style="line-height: 26px;">(HttpServletRequest request, HttpServletResponse response, Object handler)</span> <span style="color: #c678dd;line-height: 26px;">throws</span> Exception </span>{<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// 从http请求头中取出token</span><br> <span style="color: #c678dd;line-height: 26px;">final</span> String token = request.getHeader(JwtTokenUtil.AUTH_HEADER_KEY);<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">//如果不是映射到方法,直接通过</span><br> <span style="color: #c678dd;line-height: 26px;">if</span>(!(handler <span style="color: #c678dd;line-height: 26px;">instanceof</span> HandlerMethod)){<br> <span style="color: #c678dd;line-height: 26px;">return</span> <span style="color: #c678dd;line-height: 26px;">true</span>;<br> }<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">//如果是方法探测,直接通过</span><br> <span style="color: #c678dd;line-height: 26px;">if</span> (HttpMethod.OPTIONS.equals(request.getMethod())) {<br> response.setStatus(HttpServletResponse.SC_OK);<br> <span style="color: #c678dd;line-height: 26px;">return</span> <span style="color: #c678dd;line-height: 26px;">true</span>;<br> }<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">//如果方法有JwtIgnore注解,直接通过</span><br> HandlerMethod handlerMethod = (HandlerMethod) handler;<br> Method method=handlerMethod.getMethod();<br> <span style="color: #c678dd;line-height: 26px;">if</span> (method.isAnnotationPresent(JwtIgnore<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>)) </span>{<br> JwtIgnore jwtIgnore = method.getAnnotation(JwtIgnore<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>)</span>;<br> <span style="color: #c678dd;line-height: 26px;">if</span>(jwtIgnore.value()){<br> <span style="color: #c678dd;line-height: 26px;">return</span> <span style="color: #c678dd;line-height: 26px;">true</span>;<br> }<br> }<br> LocalAssert.isStringEmpty(token, <span style="color: #98c379;line-height: 26px;">"token为空,鉴权失败!"</span>);<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">//验证,并获取token内部信息</span><br> String userToken = JwtTokenUtil.verifyToken(token);<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">//将token放入本地缓存</span><br> WebContextUtil.setUserToken(userToken);<br> <span style="color: #c678dd;line-height: 26px;">return</span> <span style="color: #c678dd;line-height: 26px;">true</span>;<br> }<br> <span style="color: #61aeee;line-height: 26px;">@Override</span><br> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">void</span> <span style="color: #61aeee;line-height: 26px;">afterCompletion</span><span style="line-height: 26px;">(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)</span> <span style="color: #c678dd;line-height: 26px;">throws</span> Exception </span>{<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">//方法结束后,移除缓存的token</span><br> WebContextUtil.removeUserToken();<br> }<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">在生成token的时候,我们可以将一些基本的用户信息,例如用户ID、用户姓名,存入token中,这样当token鉴权通过之后,我们只需要通过解析里面的信息,即可获取对应的用户ID,可以省下去数据库查询一些基本信息的操作。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">同时,使用的过程中,尽量不要存放敏感信息,因为很容易被黑客解析!</p> <h4 data-tool="mdnice编辑器" style="margin-bottom: 15px;font-weight: bold;color: black;font-size: 18px;margin-top: 30px;"><span style="display: none;"></span>2.2、接口签名<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">同样的思路,站在服务端验证的角度,我们可以先编写一个签名拦截器,验证客户端传入的参数是否合法,只要有一项不合法,就提示错误。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">具体代码实践如下:</p> <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("https://mmbiz.qpic.cn/mmbiz_svg/3Lqm1xHojtYV02xvhcJIbKuG495Kussib6UcCKRR6Hd9gcvlsJSEzTcaXGek3BzeuqNI0qZu3CtREubY7GGHYbSMKTzAfC0E8/640?wx_fmt=svg") 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> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span> <span style="color: #e6c07b;line-height: 26px;">SignInterceptor</span> <span style="color: #c678dd;line-height: 26px;">implements</span> <span style="color: #e6c07b;line-height: 26px;">HandlerInterceptor</span> </span>{<br><br> <span style="color: #61aeee;line-height: 26px;">@Autowired</span><br> <span style="color: #c678dd;line-height: 26px;">private</span> AppSecretService appSecretService;<br><br> <span style="color: #61aeee;line-height: 26px;">@Autowired</span><br> <span style="color: #c678dd;line-height: 26px;">private</span> RedisUtil redisUtil;<br><br> <span style="color: #61aeee;line-height: 26px;">@Override</span><br> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">boolean</span> <span style="color: #61aeee;line-height: 26px;">preHandle</span><span style="line-height: 26px;">(HttpServletRequest request, HttpServletResponse response, Object handler)</span><br> <span style="color: #c678dd;line-height: 26px;">throws</span> Exception </span>{<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">//appId验证</span><br> <span style="color: #c678dd;line-height: 26px;">final</span> String appId = request.getHeader(<span style="color: #98c379;line-height: 26px;">"appid"</span>);<br> <span style="color: #c678dd;line-height: 26px;">if</span>(StringUtils.isEmpty(appId)){<br> <span style="color: #c678dd;line-height: 26px;">throw</span> <span style="color: #c678dd;line-height: 26px;">new</span> CommonException(<span style="color: #98c379;line-height: 26px;">"appid不能为空"</span>);<br> }<br> String appSecret = appSecretService.getAppSecretByAppId(appId);<br> <span style="color: #c678dd;line-height: 26px;">if</span>(StringUtils.isEmpty(appSecret)){<br> <span style="color: #c678dd;line-height: 26px;">throw</span> <span style="color: #c678dd;line-height: 26px;">new</span> CommonException(<span style="color: #98c379;line-height: 26px;">"appid不合法"</span>);<br> }<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">//时间戳验证</span><br> <span style="color: #c678dd;line-height: 26px;">final</span> String timestamp = request.getHeader(<span style="color: #98c379;line-height: 26px;">"timestamp"</span>);<br> <span style="color: #c678dd;line-height: 26px;">if</span>(StringUtils.isEmpty(timestamp)){<br> <span style="color: #c678dd;line-height: 26px;">throw</span> <span style="color: #c678dd;line-height: 26px;">new</span> CommonException(<span style="color: #98c379;line-height: 26px;">"timestamp不能为空"</span>);<br> }<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">//大于5分钟,非法请求</span><br> <span style="color: #c678dd;line-height: 26px;">long</span> diff = System.currentTimeMillis() - Long.parseLong(timestamp);<br> <span style="color: #c678dd;line-height: 26px;">if</span>(Math.abs(diff) > <span style="color: #d19a66;line-height: 26px;">1000</span> * <span style="color: #d19a66;line-height: 26px;">60</span> * <span style="color: #d19a66;line-height: 26px;">5</span>){<br> <span style="color: #c678dd;line-height: 26px;">throw</span> <span style="color: #c678dd;line-height: 26px;">new</span> CommonException(<span style="color: #98c379;line-height: 26px;">"timestamp已过期"</span>);<br> }<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">//临时流水号,防止重复提交</span><br> <span style="color: #c678dd;line-height: 26px;">final</span> String nonce = request.getHeader(<span style="color: #98c379;line-height: 26px;">"nonce"</span>);<br> <span style="color: #c678dd;line-height: 26px;">if</span>(StringUtils.isEmpty(nonce)){<br> <span style="color: #c678dd;line-height: 26px;">throw</span> <span style="color: #c678dd;line-height: 26px;">new</span> CommonException(<span style="color: #98c379;line-height: 26px;">"nonce不能为空"</span>);<br> }<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">//验证签名</span><br> <span style="color: #c678dd;line-height: 26px;">final</span> String signature = request.getHeader(<span style="color: #98c379;line-height: 26px;">"signature"</span>);<br> <span style="color: #c678dd;line-height: 26px;">if</span>(StringUtils.isEmpty(nonce)){<br> <span style="color: #c678dd;line-height: 26px;">throw</span> <span style="color: #c678dd;line-height: 26px;">new</span> CommonException(<span style="color: #98c379;line-height: 26px;">"signature不能为空"</span>);<br> }<br> <span style="color: #c678dd;line-height: 26px;">final</span> String method = request.getMethod();<br> <span style="color: #c678dd;line-height: 26px;">final</span> String url = request.getRequestURI();<br> <span style="color: #c678dd;line-height: 26px;">final</span> String body = StreamUtils.copyToString(request.getInputStream(), Charset.forName(<span style="color: #98c379;line-height: 26px;">"UTF-8"</span>));<br> String signResult = SignUtil.getSignature(method, url, body, timestamp, nonce, appSecret);<br> <span style="color: #c678dd;line-height: 26px;">if</span>(!signature.equals(signResult)){<br> <span style="color: #c678dd;line-height: 26px;">throw</span> <span style="color: #c678dd;line-height: 26px;">new</span> CommonException(<span style="color: #98c379;line-height: 26px;">"签名验证失败"</span>);<br> }<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">//检查是否重复请求</span><br> String key = appId + <span style="color: #98c379;line-height: 26px;">"_"</span> + timestamp + <span style="color: #98c379;line-height: 26px;">"_"</span> + nonce;<br> <span style="color: #c678dd;line-height: 26px;">if</span>(redisUtil.exist(key)){<br> <span style="color: #c678dd;line-height: 26px;">throw</span> <span style="color: #c678dd;line-height: 26px;">new</span> CommonException(<span style="color: #98c379;line-height: 26px;">"当前请求正在处理,请不要重复提交"</span>);<br> }<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">//设置5分钟</span><br> redisUtil.save(key, signResult, <span style="color: #d19a66;line-height: 26px;">5</span>*<span style="color: #d19a66;line-height: 26px;">60</span>);<br> request.setAttribute(<span style="color: #98c379;line-height: 26px;">"reidsKey"</span>,key);<br> }<br><br> <span style="color: #61aeee;line-height: 26px;">@Override</span><br> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">void</span> <span style="color: #61aeee;line-height: 26px;">afterCompletion</span><span style="line-height: 26px;">(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)</span><br> <span style="color: #c678dd;line-height: 26px;">throws</span> Exception </span>{<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">//请求处理完毕之后,移除缓存</span><br> String value = request.getAttribute(<span style="color: #98c379;line-height: 26px;">"reidsKey"</span>);<br> <span style="color: #c678dd;line-height: 26px;">if</span>(!StringUtils.isEmpty(value)){<br> redisUtil.remove(value);<br> }<br> }<br><br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">签名工具类<code style="">SignUtil</code>:</p> <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("https://mmbiz.qpic.cn/mmbiz_svg/3Lqm1xHojtYV02xvhcJIbKuG495Kussib6UcCKRR6Hd9gcvlsJSEzTcaXGek3BzeuqNI0qZu3CtREubY7GGHYbSMKTzAfC0E8/640?wx_fmt=svg") 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> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span> <span style="color: #e6c07b;line-height: 26px;">SignUtil</span> </span>{<br><br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">/**<br> * 签名计算<br> * <span style="color: #c678dd;line-height: 26px;">@param</span> method<br> * <span style="color: #c678dd;line-height: 26px;">@param</span> url<br> * <span style="color: #c678dd;line-height: 26px;">@param</span> body<br> * <span style="color: #c678dd;line-height: 26px;">@param</span> timestamp<br> * <span style="color: #c678dd;line-height: 26px;">@param</span> nonce<br> * <span style="color: #c678dd;line-height: 26px;">@param</span> appSecret<br> * <span style="color: #c678dd;line-height: 26px;">@return</span><br> */</span><br> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">static</span> String <span style="color: #61aeee;line-height: 26px;">getSignature</span><span style="line-height: 26px;">(String method, String url, String body, String timestamp, String nonce, String appSecret)</span></span>{<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">//第一层签名</span><br> String requestStr1 = method + url + body + appSecret;<br> String signResult1 = DigestUtils.md5Hex(requestStr1);<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">//第二层签名</span><br> String requestStr2 = appSecret + timestamp + nonce + signResult1;<br> String signResult2 = DigestUtils.md5Hex(requestStr2);<br> <span style="color: #c678dd;line-height: 26px;">return</span> signResult2;<br> }<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">签名计算,可以换成<code style="">hamc</code>方式进行计算,思路大致一样。</p> <h3 data-tool="mdnice编辑器" style="margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;margin-top: 1.2em;"><span style="background-image: url("https://mmbiz.qpic.cn/mmbiz_png/tWOhQMr1wdBpCrR8MBf6XIzvFtITWOicRMhodHMFes9k2EMNlELr74czI6kvGhAOL94cZpMbxFxMLJFOFbib74Iw/640?wx_fmt=png");background-size: 100% 100%;background-repeat: no-repeat;display: inline-block;width: 16px;height: 15px;line-height: 15px;margin-bottom: -1px;"></span><span style="display: none;"></span><span style="font-size: 17px;display: inline-block;margin-left: 8px;color: rgb(72, 179, 120);">三、小结</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">上面介绍的token和接口签名方案,对外都可以对提供的接口起到保护作用,防止别人篡改请求,或者模拟请求。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">但是缺少对数据自身的安全保护,即请求的参数和返回的数据都是有可能被别人拦截获取的,而这些数据又是明文的,所以只要被拦截,就能获得相应的业务数据。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">对于这种情况,推荐大家对请求参数和返回参数进行加密处理,例如RSA、AES等加密工具。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">同时,在生产环境,采用<code style="">https</code>方式进行传输,可以起到很好的安全保护作用!</p> </section> <section style=""> <span style="max-width: 100%;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">喜欢就</strong></span><span style="max-width: 100%;background-color: rgb(32, 180, 154);color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">分享</strong></span></span> </section> <section style=""> <span style="max-width: 100%;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">认同就</strong></span><span style="max-width: 100%;background-color: rgb(32, 180, 154);color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">点赞</strong></span></span> </section> <p style=""><span style="max-width: 100%;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">支持就</strong></span><span style="max-width: 100%;background-color: rgb(32, 180, 154);color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">在看</strong></span></span></p> <p style=""><span style="max-width: 100%;background-color: rgb(32, 180, 154);color: rgb(255, 255, 255);letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">一键四连,你的offer也四连</strong></span><img class="rich_pages __bg_gif" data-cropselx1="0" data-cropselx2="539" data-cropsely1="0" data-cropsely2="105" data-ratio="0.1949685534591195" data-s="300,640" src="/upload/2b84c832bd920400dcdaabb9411f01f5.png" data-type="gif" data-w="636" style=""></p> <p><br></p> <section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzIxMjE5MTE1Nw==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/NtO5sialJZGrOaned81pMkwib5Voibzes9ibatWlia3ZiceXRbsEWCZbyeOdoQTP1b4licNGR2qbzfaicvstXFztqQJ0wg/0?wx_fmt=png" data-nickname="程序员小灰" data-alias="chengxuyuanxiaohui" data-signature="一群喜爱编程技术和算法的小仓鼠。" data-from="0"></mpprofile> </section>
作者:微信小助手
<p data-lake-id="f47942fff38c686ed626a530b6d84219" style="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;" data-mpa-powered-by="yiban.io"><span data-mce-style="font-size: 10px" style="font-size: 13px;color: rgb(136, 136, 136);">点击上方蓝色“</span><span style="color: rgb(24, 144, 255);font-size: 13px;" data-mce-style="font-size: 10px">后端面试那些事儿</span><span data-mce-style="font-size: 10px" style="font-size: 13px;color: rgb(136, 136, 136);">”,选择“设为星标”</span></p> <p data-lake-id="eca2a1864e13b3e1b84aafe9cb4abdff" style="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(140, 140, 140);font-size: 13px;" data-mce-style="font-size: 10px">学最好的别人,做最好的自己</span></p> <p data-lake-id="b4f10076adf2228ecaccd921f627ed69" style="text-align: right;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(140, 140, 140);font-size: 13px;" data-mce-style="font-size: 10px">来源:</span><span style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);color: rgb(140, 140, 140);font-size: 13px;" data-mce-style="font-size: 10px">juejin.im/post/5e927e27f265da47c8012ed9</span></p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">Spring如何解决的循环依赖,是近两年流行起来的一道Java面试题。</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">其实笔者本人对这类框架源码题还是持一定的怀疑态度的。</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">如果笔者作为面试官,可能会问一些诸如“如果注入的属性为null,你会从哪几个方向去排查”这些场景题。</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">那么既然写了这篇文章,闲话少说,发车看看Spring是如何解决的循环依赖,以及带大家看清循环依赖的本质是什么。</p> <h3 style="margin-top: 1.2em;margin-bottom: 1em;color: rgb(53, 179, 120);font-weight: bold;font-size: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">正文</h3> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">通常来说,如果问Spring内部如何解决循环依赖,一定是单默认的单例Bean中,属性互相引用的场景。比如几个Bean之间的互相引用:</p> <p style="text-align: center;"><img class="rich_pages" data-backh="692" data-backw="579" data-galleryid="" data-ratio="1.196875" data-s="300,640" src="/upload/e58d06899f986959fe34f52caf6de1f9.png" data-type="png" data-w="640" style="width: 100%;height: auto;"></p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">甚至自己“循环”依赖自己:</p> <p style="text-align: center;"><img class="rich_pages" data-backh="458" data-backw="579" data-galleryid="" data-ratio="0.7921875" data-s="300,640" src="/upload/c2154172e3bd98f64a89579c1fec650d.png" data-type="png" data-w="640" style="width: 100%;height: auto;"></p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">先说明前提:原型(Prototype)的场景是不支持循环依赖的,通常会走到AbstractBeanFactory类中下面的判断,抛出异常。</p> <pre style="font-size: 15px;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;margin-top: 10px;margin-bottom: 10px;overflow: auto;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;color: rgb(89, 89, 89);letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><code style="font-size: 12px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;display: -webkit-box;overflow-x: auto;padding: 15px 16px 16px;color: rgb(171, 178, 191);background: rgb(40, 44, 52);border-radius: 5px;"><span style="color: rgb(198, 120, 221);line-height: 26px;">if</span> (isPrototypeCurrentlyInCreation(beanName)) {<br> <span style="color: rgb(198, 120, 221);line-height: 26px;">throw</span> <span style="color: rgb(198, 120, 221);line-height: 26px;">new</span> BeanCurrentlyInCreationException(beanName);<br>}<br></code></pre> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">原因很好理解,创建新的A时,发现要注入原型字段B,又创建新的B发现要注入原型字段A...</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">这就套娃了, 你猜是先StackOverflow还是OutOfMemory?</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">Spring怕你不好猜,就先抛出了BeanCurrentlyInCreationException</p> <p style="text-align: center;"><img class="rich_pages" data-backh="572" data-backw="504" data-galleryid="" data-ratio="1.1349206349206349" data-s="300,640" src="/upload/73a8d72836684b4ad5f9ee1d96913daa.png" data-type="png" data-w="504" style="width: 100%;height: auto;"></p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"><br></p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">基于构造器的循环依赖,就更不用说了,官方文档都摊牌了,你想让构造器注入支持循环依赖,是不存在的,不如把代码改了。</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">那么默认单例的属性注入场景,Spring是如何支持循环依赖的?</p> <h3 style="margin-top: 1.2em;margin-bottom: 1em;color: rgb(53, 179, 120);font-weight: bold;font-size: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">Spring解决循环依赖</h3> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">首先,Spring内部维护了三个Map,也就是我们通常说的三级缓存。</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">笔者翻阅Spring文档倒是没有找到三级缓存的概念,可能也是本土为了方便理解的词汇。</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">在Spring的DefaultSingletonBeanRegistry类中,你会赫然发现类上方挂着这三个Map:</p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> singletonObjects 它是我们最熟悉的朋友,俗称“单例池”“容器”,缓存创建完成单例Bean的地方。 </section></li> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> singletonFactories 映射创建Bean的原始工厂 </section></li> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> earlySingletonObjects 映射Bean的早期引用,也就是说在这个Map里的Bean不是完整的,甚至还不能称之为“Bean”,只是一个Instance. </section></li> </ul> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">后两个Map其实是“垫脚石”级别的,只是创建Bean的时候,用来借助了一下,创建完成就清掉了。</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">所以笔者前文对“三级缓存”这个词有些迷惑,可能是因为注释都是以Cache of开头吧。</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">为什么成为后两个Map为垫脚石,假设最终放在singletonObjects的Bean是你想要的一杯“凉白开”。</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">那么Spring准备了两个杯子,即singletonFactories和earlySingletonObjects来回“倒腾”几番,把热水晾成“凉白开”放到singletonObjects中。</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">闲话不说,都浓缩在图里。</p> <p style="text-align: center;"><img class="rich_pages" data-backh="332" data-backw="579" data-galleryid="" data-ratio="0.5743348982785602" data-s="300,640" src="/upload/60dcda421e07d747490d7c9a9a827990.png" data-type="png" data-w="639" style="width: 100%;height: auto;"></p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">上面的是一张GIF,如果你没看到可能还没加载出来。三秒一帧,不是你电脑卡。</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">笔者画了17张图简化表述了Spring的主要步骤,GIF上方即是刚才提到的三级缓存,下方展示是主要的几个方法。</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">当然了,这个地步你肯定要结合Spring源码来看,要不肯定看不懂。</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">如果你只是想大概了解,或者面试,可以先记住笔者上文提到的“三级缓存”,以及下文即将要说的本质。</p> <h3 style="margin-top: 1.2em;margin-bottom: 1em;color: rgb(53, 179, 120);font-weight: bold;font-size: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">循环依赖的本质</h3> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">上文了解完Spring如何处理循环依赖之后,让我们跳出“阅读源码”的思维,假设让你实现一个有以下特点的功能,你会怎么做?</p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 将指定的一些类实例为单例 </section></li> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 类中的字段也都实例为单例 </section></li> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 支持循环依赖 </section></li> </ul> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">举个例子,假设有类A:</p> <pre style="font-size: 15px;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;margin-top: 10px;margin-bottom: 10px;overflow: auto;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;color: rgb(89, 89, 89);letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><code style="font-size: 12px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;display: -webkit-box;overflow-x: auto;padding: 15px 16px 16px;color: rgb(171, 178, 191);background: rgb(40, 44, 52);border-radius: 5px;"><span style="color: rgb(198, 120, 221);line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: rgb(198, 120, 221);line-height: 26px;">class</span> <span style="color: rgb(230, 192, 123);line-height: 26px;">A</span> </span>{<br> <span style="color: rgb(198, 120, 221);line-height: 26px;">private</span> B b;<br>}<br><span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;">// 类B:</span><br><span style="color: rgb(198, 120, 221);line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: rgb(198, 120, 221);line-height: 26px;">class</span> <span style="color: rgb(230, 192, 123);line-height: 26px;">B</span> </span>{<br> <span style="color: rgb(198, 120, 221);line-height: 26px;">private</span> A a;<br>}<br></code></pre> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">说白了让你模仿Spring:假装A和B是被@Component修饰, 并且类中的字段假装是@Autowired修饰的,处理完放到Map中。其实非常简单,笔者写了一份粗糙的代码,可供参考:</p> <pre style="font-size: 15px;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;margin-top: 10px;margin-bottom: 10px;overflow: auto;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;color: rgb(89, 89, 89);letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><code style="font-size: 12px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;display: -webkit-box;overflow-x: auto;padding: 15px 16px 16px;color: rgb(171, 178, 191);background: rgb(40, 44, 52);border-radius: 5px;"> <span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;">/**<br> * 放置创建好的bean Map<br> */</span><br> <span style="color: rgb(198, 120, 221);line-height: 26px;">private</span> <span style="color: rgb(198, 120, 221);line-height: 26px;">static</span> Map<String, Object> cacheMap = <span style="color: rgb(198, 120, 221);line-height: 26px;">new</span> HashMap<>(<span style="color: rgb(209, 154, 102);line-height: 26px;">2</span>);<br><br> <span style="line-height: 26px;"><span style="color: rgb(198, 120, 221);line-height: 26px;">public</span> <span style="color: rgb(198, 120, 221);line-height: 26px;">static</span> <span style="color: rgb(198, 120, 221);line-height: 26px;">void</span> <span style="color: rgb(97, 174, 238);line-height: 26px;">main</span><span style="line-height: 26px;">(String[] args)</span> </span>{<br> <span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;">// 假装扫描出来的对象</span><br> Class[] classes = {A<span style="line-height: 26px;">.<span style="color: rgb(198, 120, 221);line-height: 26px;">class</span>, <span style="color: rgb(230, 192, 123);line-height: 26px;">B</span>.<span style="color: rgb(230, 192, 123);line-height: 26px;">class</span>}</span>;<br> <span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;">// 假装项目初始化实例化所有bean</span><br> <span style="color: rgb(198, 120, 221);line-height: 26px;">for</span> (Class aClass : classes) {<br> getBean(aClass);<br> }<br> <span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;">// check</span><br> System.out.println(getBean(B<span style="line-height: 26px;">.<span style="color: rgb(198, 120, 221);line-height: 26px;">class</span>).<span style="color: rgb(230, 192, 123);line-height: 26px;">getA</span>() </span>== getBean(A<span style="line-height: 26px;">.<span style="color: rgb(198, 120, 221);line-height: 26px;">class</span>))</span>;<br> System.out.println(getBean(A<span style="line-height: 26px;">.<span style="color: rgb(198, 120, 221);line-height: 26px;">class</span>).<span style="color: rgb(230, 192, 123);line-height: 26px;">getB</span>() </span>== getBean(B<span style="line-height: 26px;">.<span style="color: rgb(198, 120, 221);line-height: 26px;">class</span>))</span>;<br> }<br><br> <span style="color: rgb(97, 174, 238);line-height: 26px;">@SneakyThrows</span><br> <span style="color: rgb(198, 120, 221);line-height: 26px;">private</span> <span style="color: rgb(198, 120, 221);line-height: 26px;">static</span> <T> <span style="line-height: 26px;">T <span style="color: rgb(97, 174, 238);line-height: 26px;">getBean</span><span style="line-height: 26px;">(Class<T> beanClass)</span> </span>{<br> <span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;">// 本文用类名小写 简单代替bean的命名规则</span><br> String beanName = beanClass.getSimpleName().toLowerCase();<br> <span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;">// 如果已经是一个bean,则直接返回</span><br> <span style="color: rgb(198, 120, 221);line-height: 26px;">if</span> (cacheMap.containsKey(beanName)) {<br> <span style="color: rgb(198, 120, 221);line-height: 26px;">return</span> (T) cacheMap.get(beanName);<br> }<br> <span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;">// 将对象本身实例化</span><br> Object object = beanClass.getDeclaredConstructor().newInstance();<br> <span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;">// 放入缓存</span><br> cacheMap.put(beanName, object);<br> <span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;">// 把所有字段当成需要注入的bean,创建并注入到当前bean中</span><br> Field[] fields = object.getClass().getDeclaredFields();<br> <span style="color: rgb(198, 120, 221);line-height: 26px;">for</span> (Field field : fields) {<br> field.setAccessible(<span style="color: rgb(198, 120, 221);line-height: 26px;">true</span>);<br> <span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;">// 获取需要注入字段的class</span><br> Class<?> fieldClass = field.getType();<br> String fieldBeanName = fieldClass.getSimpleName().toLowerCase();<br> <span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;">// 如果需要注入的bean,已经在缓存Map中,那么把缓存Map中的值注入到该field即可</span><br> <span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;">// 如果缓存没有 继续创建</span><br> field.set(object, cacheMap.containsKey(fieldBeanName)<br> ? cacheMap.get(fieldBeanName) : getBean(fieldClass));<br> }<br> <span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;">// 属性填充完成,返回</span><br> <span style="color: rgb(198, 120, 221);line-height: 26px;">return</span> (T) object;<br> }<br></code></pre> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">这段代码的效果,其实就是处理了循环依赖,并且处理完成后,cacheMap中放的就是完整的“Bean”了</p> <p style="text-align: center;"><img class="rich_pages" data-backh="424" data-backw="579" data-galleryid="" data-ratio="0.734375" data-s="300,640" src="/upload/7258bfea9a78ea267ea7d44ce0893b48.png" data-type="png" data-w="640" style="width: 100%;height: auto;"></p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">这就是“循环依赖”的本质,而不是“Spring如何解决循环依赖”。</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">之所以要举这个例子,是发现一小部分盆友陷入了“阅读源码的泥潭”,而忘记了问题的本质。</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">为了看源码而看源码,结果一直看不懂,却忘了本质是什么。如果真看不懂,不如先写出基础版本,逆推Spring为什么要这么实现,可能效果会更好。</p> <h3 style="margin-top: 1.2em;margin-bottom: 1em;color: rgb(53, 179, 120);font-weight: bold;font-size: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">what?问题的本质居然是two sum!</h3> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">看完笔者刚才的代码有没有似曾相识?没错,和two sum的解题是类似的。不知道two sum是什么梗的,笔者和你介绍一下:two sum是刷题网站leetcode序号为1的题,也就是大多人的算法入门的第一题。常常被人调侃,有算法面的公司,被面试官钦定了,合的来。那就来一道two sum走走过场。问题内容是:给定一个数组,给定一个数字。返回数组中可以相加得到指定数字的两个索引。比如:给定nums = [2, 7, 11, 15], target = 9 那么要返回 [0, 1],因为2 + 7 = 9这道题的优解是,一次遍历+HashMap:</p> <pre style="font-size: 15px;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;margin-top: 10px;margin-bottom: 10px;overflow: auto;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;color: rgb(89, 89, 89);letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><code style="font-size: 12px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;display: -webkit-box;overflow-x: auto;padding: 15px 16px 16px;color: rgb(171, 178, 191);background: rgb(40, 44, 52);border-radius: 5px;"><span style="line-height: 26px;"><span style="color: rgb(198, 120, 221);line-height: 26px;">class</span> <span style="color: rgb(230, 192, 123);line-height: 26px;">Solution</span> </span>{<br> <span style="color: rgb(198, 120, 221);line-height: 26px;">public</span> <span style="color: rgb(198, 120, 221);line-height: 26px;">int</span>[] twoSum(<span style="color: rgb(198, 120, 221);line-height: 26px;">int</span>[] nums, <span style="color: rgb(198, 120, 221);line-height: 26px;">int</span> target) {<br> Map<Integer, Integer> map = <span style="color: rgb(198, 120, 221);line-height: 26px;">new</span> HashMap<>();<br> <span style="color: rgb(198, 120, 221);line-height: 26px;">for</span> (<span style="color: rgb(198, 120, 221);line-height: 26px;">int</span> i = <span style="color: rgb(209, 154, 102);line-height: 26px;">0</span>; i < nums.length; i++) {<br> <span style="color: rgb(198, 120, 221);line-height: 26px;">int</span> complement = target - nums[i];<br> <span style="color: rgb(198, 120, 221);line-height: 26px;">if</span> (map.containsKey(complement)) {<br> <span style="color: rgb(198, 120, 221);line-height: 26px;">return</span> <span style="color: rgb(198, 120, 221);line-height: 26px;">new</span> <span style="color: rgb(198, 120, 221);line-height: 26px;">int</span>[] { map.get(complement), i };<br> }<br> map.put(nums[i], i);<br> }<br> <span style="color: rgb(198, 120, 221);line-height: 26px;">throw</span> <span style="color: rgb(198, 120, 221);line-height: 26px;">new</span> IllegalArgumentException(<span style="color: rgb(152, 195, 121);line-height: 26px;">"No two sum solution"</span>);<br> }<br>}<br></code></pre> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">先去Map中找需要的数字,没有就将当前的数字保存在Map中,如果找到需要的数字,则一起返回。</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">和笔者上面的代码是不是一样?</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">先去缓存里找Bean,没有则实例化当前的Bean放到Map,如果有需要依赖当前Bean的,就能从Map取到。</p> <h3 style="margin-top: 1.2em;margin-bottom: 1em;color: rgb(53, 179, 120);font-weight: bold;font-size: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">结尾</h3> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">如果你是上文笔者提到的“陷入阅读源码的泥潭”的读者,上文应该可以帮助到你。</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">可能还有盆友有疑问,为什么一道“two-sum”,Spring处理的如此复杂?</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">这个想想Spring支持多少功能就知道了,各种实例方式..各种注入方式..各种Bean的加载,校验..各种callback,aop处理等等..</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">Spring可不只有依赖注入,同样Java也不仅是Spring。如果我们陷入了某个“牛角尖”,不妨跳出来看看,可能会更佳清晰哦。</p> <p data-lake-id="b4f10076adf2228ecaccd921f627ed69" style="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;"><br></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.1875px;"><img data-ratio="0.16666666666666666" src="/upload/89aa6c9fe16e0dfcf56dad1a9f9078ff.png" data-type="gif" data-w="300" style="width: auto;"></p> </section> </section> <p data-lake-id="098b923ca3e65e99528d2c30d6cf4c26" style="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;"><br></p> <section data-recommend-type="list-title" data-recommend-tid="6" data-mpa-template="t" style="width: 100%;display: flex;justify-content: center;align-items: center;" data-mid="" data-from="yb-recommend"> <section style="width: 100%;padding: 14px;background: rgb(255, 255, 255);border-radius: 3px;border-width: 1px;border-style: solid;border-color: rgb(232, 232, 235);" data-mid=""> <section style="width: 100%;display: flex;justify-content: center;align-items: center;align-items: flex-end;" data-mid=""> <section data-mid="" style="height: 28px;padding: 4px 22px;font-size: 14px;font-weight: 500;color: rgb(19, 52, 86);line-height: 20px;background-image: url("https://mmbiz.qpic.cn/mmbiz_png/sUbvrqLicbpzB81mjeBxPuxnYdalGxNnJo30L2Hq3WwGficcq8w5YJkLeXnsNHocN53k55TfN5mBpCdicGRyfDg1g/640?wx_fmt=png");background-repeat: no-repeat;background-size: 100% 100%;margin-bottom: -14px;z-index: 10;"> <p data-mid="">往期推荐</p> </section> </section> <section style="width: 100%;border-width: 1px;border-style: solid;border-color: rgb(198, 226, 255);padding: 17px 16px 9px;" data-mid=""> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247495221_1" data-recommend-article-time="1624165260" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/HmHDU48icAtYwrE9WTgPlYH1gARnY5ImRYw3VeGglnpQ3WQkjqvjNCTqmfh8a8WpzKW2f1mKjhWYicwxleqMmIpw/0?wx_fmt=jpeg" data-recommend-article-title="面试:a==1 && a==2 && a==3 是 true 还是 false?" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&mid=2247495221&idx=1&sn=da4cc23f334c97aeb78733f18fd89857&chksm=97b4702da0c3f93ba531d031494b691ec20b94e654ced5a3b4e5406f97dd1f45b600fe99b0f8#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&mid=2247495221&idx=1&sn=da4cc23f334c97aeb78733f18fd89857&chksm=97b4702da0c3f93ba531d031494b691ec20b94e654ced5a3b4e5406f97dd1f45b600fe99b0f8&scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" data-recommend-content="t" style="width: 100%;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;border-bottom: 1px dashed #c6e2ff;padding: 6px;font-size: 13px;font-weight: 400;color: #2c5f95;line-height: 18px;" data-mid=""> <p style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 100%;" data-mid="">面试:a==1 && a==2 && a==3 是 true 还是 false?</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247495221_2" data-recommend-article-time="1624165260" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/R3InYSAIZkG2t6Ny3C7bHeGvYDTtvhU4bp1UmVDInDcgAVM4NDckrQibMekic6GKoLlOhUS8ex0x4m9xbCnu7uew/0?wx_fmt=jpeg" data-recommend-article-title="60岁还在写代码的开发者,他的建议或许正是你现在焦虑的根源!尝试改变一下吧!" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&mid=2247495221&idx=2&sn=2cd3ecb50025d3f4a20a0af8c5e1c037&chksm=97b4702da0c3f93bd2b39d593df991e3f47f9974b9287ff63cdae25c9bbf27053cd3edce83f4#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&mid=2247495221&idx=2&sn=2cd3ecb50025d3f4a20a0af8c5e1c037&chksm=97b4702da0c3f93bd2b39d593df991e3f47f9974b9287ff63cdae25c9bbf27053cd3edce83f4&scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" data-recommend-content="t" style="width: 100%;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;border-bottom: 1px dashed #c6e2ff;padding: 6px;font-size: 13px;font-weight: 400;color: #2c5f95;line-height: 18px;" data-mid=""> <p style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 100%;" data-mid="">60岁还在写代码的开发者,他的建议或许正是你现在焦虑的根源!尝试改变一下吧!</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247495221_3" data-recommend-article-time="1624165260" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/Rhiaqbb2uvaIotOkaL1Yf7NkzzlCY4uwHfb5YywKZUuuFeUxFBBuH97jcyU7pH5dwQjLAia6zc62d00icBtSZEJzA/0?wx_fmt=jpeg" data-recommend-article-title="河南“水下洛神”爆火,清华美院被骂上热搜" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&mid=2247495221&idx=3&sn=b9dd941e4fd1ff81fc216af5da3fce71&chksm=97b4702da0c3f93b2608f079937d05d2be7b70b62d80195cf97349196d993aadbcf95df4ce19#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&mid=2247495221&idx=3&sn=b9dd941e4fd1ff81fc216af5da3fce71&chksm=97b4702da0c3f93b2608f079937d05d2be7b70b62d80195cf97349196d993aadbcf95df4ce19&scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" data-recommend-content="t" style="width: 100%;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;border-bottom: 1px dashed #c6e2ff;padding: 6px;font-size: 13px;font-weight: 400;color: #2c5f95;line-height: 18px;" data-mid=""> <p style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 100%;" data-mid="">河南“水下洛神”爆火,清华美院被骂上热搜</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247495209_1" data-recommend-article-time="1624078860" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/HmHDU48icAtZ0ZqxOgkP59spOVNybB2Tp2mGXbPGH5FedWHKibibTsr7Q0Z6MibIEdxQ9RibDibzxLkYFhsicoRmvUNFA/0?wx_fmt=jpeg" data-recommend-article-title="为什么阿里规定需要在事务注解 @Transactional 中指定 rollbackFor?" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&mid=2247495209&idx=1&sn=4cecc00937a4494e562b8a64380c7ae3&chksm=97b47031a0c3f927fbdf9529fcaa6e2a07b1cd77decc6833410241882b10ba529cd38d92155e#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&mid=2247495209&idx=1&sn=4cecc00937a4494e562b8a64380c7ae3&chksm=97b47031a0c3f927fbdf9529fcaa6e2a07b1cd77decc6833410241882b10ba529cd38d92155e&scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" data-recommend-content="t" style="width: 100%;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;border-bottom: 1px dashed #c6e2ff;padding: 6px;font-size: 13px;font-weight: 400;color: #2c5f95;line-height: 18px;" data-mid=""> <p style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 100%;" data-mid="">为什么阿里规定需要在事务注解 @Transactional 中指定 rollbackFor?</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247495209_2" data-recommend-article-time="1624078860" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/R3InYSAIZkE52tUyg9wzRiaAcHDQGWH9gXNjibrGndqsxkTxRTthrJEc3e0uq2dyeWHk50bHgU0o0TYB0j96g4Rw/0?wx_fmt=jpeg" data-recommend-article-title="用低代码平台开发比用IDEA还牛逼吗?" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&mid=2247495209&idx=2&sn=bbe4ea8fde9c9c28fcd67993df1e848b&chksm=97b47031a0c3f9274256d48fc1b16b69a099951035f63918742adc78cd9b8a6d5219c438b07b#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&mid=2247495209&idx=2&sn=bbe4ea8fde9c9c28fcd67993df1e848b&chksm=97b47031a0c3f9274256d48fc1b16b69a099951035f63918742adc78cd9b8a6d5219c438b07b&scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" data-recommend-content="t" style="width: 100%;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;border-bottom: 1px dashed #c6e2ff;padding: 6px;font-size: 13px;font-weight: 400;color: #2c5f95;line-height: 18px;" data-mid=""> <p style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 100%;" data-mid="">用低代码平台开发比用IDEA还牛逼吗?</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247495209_3" data-recommend-article-time="1624078860" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/Rhiaqbb2uvaIGhHIr2ThaQWicQA3QkwVGIf49MTHiaGfNWzG7u2MN5ZRGOtYSDwCpR3svzAk9GnuyODo2LeibPD2rg/0?wx_fmt=jpeg" data-recommend-article-title="印度女警遭受侵犯并被拍视频勒索,结果却是罪犯都没有被逮捕?" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&mid=2247495209&idx=3&sn=b81b971644953cccc4df142b1a6dfd39&chksm=97b47031a0c3f9275c5fa2e979034db9caff3c053ed46dc8241351eeea2ea2242f179c7a6840#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&mid=2247495209&idx=3&sn=b81b971644953cccc4df142b1a6dfd39&chksm=97b47031a0c3f9275c5fa2e979034db9caff3c053ed46dc8241351eeea2ea2242f179c7a6840&scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" data-recommend-content="t" style="width: 100%;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;border-bottom: 1px dashed #c6e2ff;padding: 6px;font-size: 13px;font-weight: 400;color: #2c5f95;line-height: 18px;border-bottom:none !important;" data-mid=""> <p style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 100%;" data-mid="">印度女警遭受侵犯并被拍视频勒索,结果却是罪犯都没有被逮捕?</p> </section></a> </section> </section> </section> </section> <p data-lake-id="098b923ca3e65e99528d2c30d6cf4c26" style="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;"><br></p> <p data-lake-id="098b923ca3e65e99528d2c30d6cf4c26" style="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(140, 140, 140);"><br></span></p> <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;">一起进大厂,每日学干货</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="color: rgb(0, 0, 0);font-size: 14px;">】,加入Java技术交流群</span></strong></span> </section> <section data-mpa-template="t" mpa-from-tpl="t"> <p style="text-align: center;"><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> <p style="text-align: center;"><br></p> </section> <p style="text-align: center;"><br></p> <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;"> <section style="box-sizing: border-box;font-size: 16px;"> <section powered-by="xiumi.us" style="margin-top: 0.5em;box-sizing: border-box;"> <section style="padding: 0.5em;border-width: 1px;border-style: solid;border-color: rgb(249, 110, 87);box-shadow: rgb(226, 226, 226) 0px 16px 1px -13px;box-sizing: border-box;"> <section powered-by="xiumi.us" style="text-align: left;box-sizing: border-box;"> <section style="text-align: justify;color: rgb(64, 84, 115);box-sizing: border-box;"> <p style="box-sizing: border-box;"><img data-ratio="0.33611111111111114" src="/upload/a53e4e397528931045198e4f89d7ba0.png" data-type="png" data-w="1080"></p> <p style="box-sizing: border-box;">点击“阅读原文”,领取 2021 年<strong>最新免费技术资料大全</strong></p> </section> </section> </section> </section> <section powered-by="xiumi.us" style="font-size: 32px;color: rgb(249, 110, 87);box-sizing: border-box;text-align: left;"> ↓↓↓ </section> </section> </section> </section>
作者:微信小助手
<p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.625" data-s="300,640" src="/upload/b5541ce312613800d88efd62c25fb6fb.jpg" data-type="jpeg" data-w="1024" style=""></p> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(255, 106, 0);">一 什么是 Netty? 能做什么?</span></strong> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">Netty 是一个致力于创建高性能网络应用程序的成熟的 IO 框架。</span></p></li> </ul> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">相比较与直接使用底层的 Java IO API,你不需要先成为网络专家就可以基于 Netty 去构建复杂的网络应用。</span></p></li> </ul> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">业界常见的涉及到网络通信的相关中间件大部分基于 Netty 实现网络层。</span></p></li> </ul> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(255, 106, 0);">二 设计一个分布式服务框架</span></strong> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(255, 106, 0);">1 Architecture</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" src="/upload/6efa9f261fa429564b0780b0883794a6.png" data-cropx1="45.2560553633218" data-cropx2="816.1695501730103" data-cropy1="0" data-cropy2="494.69550173010384" data-ratio="0.6407263294422828" data-s="300,640" src="https://mmbiz.qpic.cn/mmbiz_jpg/Z6bicxIx5naIohPtQJfcNCrXMkbmXiaia6LDoz4PxKXAkneiaF6DQllZdavgWmIfL4ibQ8GOicrVfhHia4IEKKIAE7b1A/640?wx_fmt=jpeg" data-type="jpeg" data-w="771" style="width: 494px;height: 317px;"></p> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(255, 106, 0);">2 远程调用的流程</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">启动服务端(服务提供者)并发布服务到注册中心。</span></p></li> </ul> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">启动客户端(服务消费者)并去注册中心订阅感兴趣的服务。</span></p></li> </ul> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">客户端收到注册中心推送的服务地址列表。</span></p></li> </ul> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">调用者发起调用,Proxy从服务地址列表中选择一个地址并将</span><span style="font-size: 15px;color: rgb(62, 62, 62);">请求信息 <group,providerName,version>,methodName,args[] 等信息</span><span style="font-size: 15px;color: rgb(62, 62, 62);">序列化为字节数组并通过网络发送到该地址上。</span></p></li> </ul> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">服务端收到收到并反序列化请求信息,根</span><span style="font-size: 15px;color: rgb(62, 62, 62);">据 <group,providerName,version> 从本地服务</span><span style="font-size: 15px;color: rgb(62, 62, 62);">字典里查找到对应</span><span style="font-size: 15px;color: rgb(62, 62, 62);">provid</span><span style="font-size: 15px;color: rgb(62, 62, 62);">erObject,再根据 <methodName,args[]> 通过反射调用指定</span><span style="font-size: 15px;color: rgb(62, 62, 62);">方法,并将方法返回值序列化为字节数组返回给客户端。</span></p></li> </ul> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">客户端收到响应信息再反序列化为 Java 对象后由 Proxy 返回给方法调用者。</span></p></li> </ul> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">以上流程对方法调用者是透明的,一切看起来就像本地调用一样。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(255, 106, 0);"><span style="color: rgb(255, 106, 0);font-size: 15px;">3 远程调用客户端图解</span></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.46594594594594596" data-s="300,640" src="/upload/296a85f2c07c45a07886c6f09e77db89.png" data-type="png" data-w="925" style=""></p> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">重要概念:RPC三元</span> <span style="font-size: 15px;color: rgb(62, 62, 62);">组 <ID,Request,Response>。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">PS: 若是 netty4.x 的线程模型,IO Thread(worker) —> Map<InvokeId,Future> 代替全局 Map 能更好的避免线程竞争。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(255, 106, 0);">4 远程调用服务端图解</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.41470888661899896" data-s="300,640" src="/upload/73c802527996aeed16dba7cda3592170.png" data-type="png" data-w="979" style=""></p> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(255, 106, 0);"><span style="color: rgb(255, 106, 0);font-size: 15px;">5 远程调用传输层图解</span></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.6078125" data-s="300,640" src="/upload/ecf27f04ca639b2a74ea0585ccf29685.png" data-type="png" data-w="1280" style=""></p> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(255, 106, 0);"><span style="color: rgb(255, 106, 0);font-size: 15px;">6 设计传输层协议栈</span></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">协议头</span></strong> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.378125" data-s="300,640" src="/upload/d4f479dc24f8a5e9418cfb253dd32e68.png" data-type="png" data-w="1280" style=""></p> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">协议体</span></strong> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <p><span style="font-size: 15px;color: rgb(62, 62, 62);">1)metadata: <group,providerName,version></span></p> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <p><span style="font-size: 15px;color: rgb(62, 62, 62);">2)methodName</span></p> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">3)parameterTypes[] 真的需要吗?</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">(a)有什么问题?</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">反序列化</span><span style="font-size: 15px;color: rgb(62, 62, 62);">时 ClassLoader.loadClass() 潜在锁</span><span style="font-size: 15px;color: rgb(62, 62, 62);">竞争。</span></p></li> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">协议体码流大小。</span></p></li> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">泛化调用多了参数类型。</span></p></li> </ul> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><span style="color: rgb(62, 62, 62);font-size: 15px;">(</span>b)能解决吗?</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">Java方法静态分派规则参考JLS <Java语言规范> $15.12.2.5 Choosing the Most Specific Method 章节。</span></p></li> </ul> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><span style="color: rgb(62, 62, 62);font-size: 15px;"><span style="color: rgb(62, 62, 62);font-size: 15px;">(</span></span>c)args[]</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><span style="color: rgb(62, 62, 62);font-size: 15px;"><span style="color: rgb(62, 62, 62);font-size: 15px;">(</span></span>d)其他:traceId,appName…</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(255, 106, 0);">三 一些Features&好的实践&压榨性能</span></strong> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(255, 106, 0);"><span style="color: rgb(255, 106, 0);font-size: 15px;">1 创建客户端代理对象</span></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">1)Proxy 做什么?</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">集群容错 —> 负载均衡 —> 网络</span></p></li> </ul> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">2)有哪些创建 Proxy 的方式?</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">jdk proxy/javassist/cglib/asm/bytebuddy</span></p></li> </ul> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">3)要注意的:</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">注意拦截toString,equals,hashCode等方法避免远程调用。</span></p></li> </ul> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">4)推荐的(bytebuddy):</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.39140625" data-s="300,640" src="/upload/be014fd2ffacd10fdbb355575c2897e2.png" data-type="png" data-w="1280" style=""></p> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(255, 106, 0);"><span style="color: rgb(255, 106, 0);font-size: 15px;">2 优雅的同步/异步调用</span></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">先往上翻再看看“<span style="color: rgb(62, 62, 62);font-size: 15px;">远程调用客户端图解</span>”</span></p></li> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">再往下翻翻看看 Failover 如何处理更好</span></p></li> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">思考下如何拿到 future?</span></p></li> </ul> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(255, 106, 0);">3 单播/组播</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">消息派发器</span></p></li> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">FutureGroup</span></p></li> </ul> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(255, 106, 0);"><span style="color: rgb(255, 106, 0);font-size: 15px;">4 泛化调用</span></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">Object $invoke(String methodName,Object... args)</span></p></li> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);text-decoration: none;">parameterTypes[]</span></p></li> </ul> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(255, 106, 0);"><span style="color: rgb(255, 106, 0);font-size: 15px;">5 序列化/反序列化</span></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">协议 header 标记 serializer type,同时支持多种。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(255, 106, 0);">6 可扩展性</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">Java SPI:</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">java.util.ServiceLoader</span></p></li> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">META-INF/services/com.xxx.Xxx</span></p></li> </ul> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(255, 106, 0);"><span style="color: rgb(255, 106, 0);font-size: 15px;">7 服务级别线程池隔离</span></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">要挂你先挂,别拉着我。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(255, 106, 0);"><span style="color: rgb(255, 106, 0);font-size: 15px;">8 责任链模式的拦截器</span></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">太多扩展需要从这里起步。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(255, 106, 0);"><span style="color: rgb(255, 106, 0);font-size: 15px;">9 指标度量(Metrics)</span></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(255, 106, 0);"><span style="color: rgb(255, 106, 0);font-size: 15px;">10 链路追踪</span></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">OpenTracing</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(255, 106, 0);"><span style="color: rgb(255, 106, 0);font-size: 15px;">11 注册中心</span></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(255, 106, 0);"><span style="color: rgb(255, 106, 0);font-size: 15px;">12 流控(应用级别/服务级别)</span></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">要有能方便接入第三方流控中间件的扩展能力。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(255, 106, 0);"><span style="color: rgb(255, 106, 0);font-size: 15px;">13 Provider线程池满了怎么办?</span></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.3784916201117318" data-s="300,640" src="/upload/fd22237f70ceac8f3d98c668253e614c.png" data-type="png" data-w="716" style=""></p> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(255, 106, 0);"><span style="color: rgb(255, 106, 0);font-size: 15px;">14 软负载均衡</span></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">1)加权随机 (二分法,不要遍历)</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.28975265017667845" data-s="300,640" src="/upload/5afbd5d2392d1f931dddbf2145047e7a.png" data-type="png" data-w="1132" style=""></p> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">2)加权轮训(最大公约数)</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.6602316602316602" data-s="300,640" src="/upload/7773fdfd9f55c0b117e4f87f2d08b97a.png" data-type="png" data-w="1036" style=""></p> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">3)最小负载</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section
作者:微信小助手
<p style="margin-right: 8px;margin-bottom: 10px;margin-left: 8px;white-space: normal;font-family: PingFangSC-Regular;font-size: 14px;background-color: rgb(255, 255, 255);line-height: 1.75em;" data-mpa-powered-by="yiban.io"><img class="rich_pages js_insertlocalimg" data-backh="90" data-backw="562" data-cropselx1="0" data-cropselx2="562" data-cropsely1="0" data-cropsely2="90" data-ratio="0.16" data-s="300,640" src="/upload/a340ba59f43fcae32fb772c087332a13.jpg" data-type="jpeg" data-w="1000" style="color: rgb(85, 85, 85);font-family: Optima-Regular, PingFangTC-light;font-size: 15px;caret-color: rgb(0, 0, 0);text-align: center;width: 562px;float: left;"></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;text-align: center;line-height: 1.75em;"><img class="rich_pages" data-backh="562" data-backw="562" data-cropselx1="0" data-cropselx2="562" data-cropsely1="0" data-cropsely2="562" data-ratio="1" data-s="300,640" src="/upload/1fdc326b23d1bc84e0a26a2d3c970ab7.png" data-type="png" data-w="1000" style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;float: left;width: 100%;box-sizing: border-box !important;visibility: visible !important;height: auto;"></p> <section style="white-space: normal;font-size: 16px;visibility: visible;"> <section style="margin: 10px 8px;visibility: visible;line-height: 1.75em;"> <section data-darkmode-bgcolor-15906711670635="rgb(52, 52, 52)" data-darkmode-original-bgcolor-15906711670635="rgb(239, 239, 239)" data-style="padding: 10px; display: inline-block; width: 558px; border-width: 1px; border-style: solid; border-color: transparent; background-color: rgb(239, 239, 239); border-radius: 0px;" class="js_darkmode__0" style="padding: 10px;background-color: rgb(239, 239, 239);display: inline-block;width: 558px;border-width: 1px;border-style: solid;border-color: transparent;border-radius: 0px;visibility: visible;color: rgba(230, 230, 230, 0.9) !important;"> <section powered-by="xiumi.us" data-darkmode-bgcolor-15906711670635="rgb(52, 52, 52)" data-darkmode-original-bgcolor-15906711670635="rgb(239, 239, 239)" style="transform: rotate(0deg);visibility: visible;"> <section data-darkmode-bgcolor-15906711670635="rgb(52, 52, 52)" data-darkmode-original-bgcolor-15906711670635="rgb(239, 239, 239)"> <p data-darkmode-bgcolor-15906711670635="rgb(52, 52, 52)" data-darkmode-original-bgcolor-15906711670635="rgb(239, 239, 239)" style="visibility: visible;"><span style="font-size: 14px;"><strong><span style="text-align: start;color: rgb(85, 85, 85);font-family: Optima-Regular, PingFangTC-light;">桔妹导读:</span></strong></span><span style="color: rgb(85, 85, 85);font-family: Optima-Regular, PingFangTC-light;font-size: 14px;text-align: start;">大数据是这个时代赋予我们的强大引擎,在数字化大潮中 ,借助数据驱动的方法推动业务乘风破浪,几乎是每家公司的核心战略。数据驱动的落脚点是数据,能否将组织或业务运行过程中的信息,进行有效收集并组织成信息流,是数据驱动的基石所在。本文分享了滴滴数据体系建设过程中,MySQL这一类数据源的采集架构和应用实践。 </span></p> </section> </section> </section> </section> </section> <section style="margin: 10px 8px;white-space: normal;visibility: visible;transform: rotate(0deg);line-height: 1.75em;font-size: 16px;"> <p line="init" style="margin: 10px 8px;visibility: visible;transform: rotate(0deg);line-height: 1.75em;"><br></p> </section> <section style="margin: 10px 8px;white-space: normal;visibility: visible;transform: rotate(0deg);line-height: 1.75em;font-size: 16px;"> <p style="margin: 5px 8px;line-height: 1.75em;"><br></p> </section> <p style="margin-top: 5px;margin-right: 8px;margin-left: 8px;white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-family: Optima-Regular, PingFangTC-light;"><em style="color: rgb(255, 125, 65);font-size: 36px;"><strong>1. </strong></em><br></span></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 24px;font-family: Optima-Regular, PingFangTC-light;"><strong><span style="color: rgb(54, 54, 54);letter-spacing: 0.544px;text-indent: 29.3333px;background-color: rgb(255, 255, 255);">背景</span></strong></span></p> <p style="margin: 5px 8px;white-space: normal;line-height: 1.75em;"><img class="rich_pages" data-backh="41" data-backw="562" data-ratio="0.0734375" data-s="300,640" src="/upload/6e14b7885b38ee3ce6513298fb72174a.png" data-type="png" data-w="1280" style="width: 562px;"></p> <p style="margin: 5px 8px;white-space: normal;line-height: 1.75em;"><span style="background-color: rgb(255, 255, 255);color: rgb(85, 85, 85);font-family: PingFangSC-Light;font-size: 15px;letter-spacing: 0.544px;text-indent: 29.3333px;">关系模型构建起整个数据分析的基石,关系型数据库作为具体实现、采集MySQL数据接入Hive是很多企业进行数据分析的前提。</span><span style="background-color: rgb(255, 255, 255);color: rgb(85, 85, 85);font-family: PingFangSC-Light;font-size: 15px;letter-spacing: 0.544px;text-indent: 29.3333px;">如何及时、准确的把MySQL数据同步到Hive呢?</span><br></p> <p style="margin: 5px 8px;white-space: normal;line-height: 1.75em;"><br></p> <p style="margin: 5px 8px;white-space: normal;line-height: 1.75em;"><span style="background-color: rgb(255, 255, 255);color: rgb(85, 85, 85);font-family: PingFangSC-Light;font-size: 15px;letter-spacing: 0.544px;text-indent: 29.3333px;">一般解决方案是使用类似Sqoop的工具,直连MySQL去Select数据存储到HDFS,然后把HDFS数据Load到Hive中。这种方法简单易操作,但随着业务规模扩大,不足之处也逐步暴露出来:</span></p> <p style="margin: 5px 8px;white-space: normal;line-height: 1.75em;"><br></p> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p style="margin: 5px 8px;white-space: normal;line-height: 1.75em;"><span style="background-color: rgb(255, 255, 255);color: rgb(85, 85, 85);font-family: PingFangSC-Light;font-size: 15px;letter-spacing: 0.544px;text-indent: 29.3333px;">直连MySQL查询,对于数据库压力较大(如订单表、支付表等),可能直接影响在线业务</span></p></li> <li><p style="margin: 5px 8px;white-space: normal;line-height: 1.75em;"><span style="background-color: rgb(255, 255, 255);color: rgb(85, 85, 85);font-family: PingFangSC-Light;font-size: 15px;letter-spacing: 0.544px;text-indent: 29.3333px;">数据整体就位时间(尤其大表)不满足下游生产需求</span></p></li> <li><p style="margin: 5px 8px;white-space: normal;line-height: 1.75em;"><span style="background-color: rgb(255, 255, 255);color: rgb(85, 85, 85);font-family: PingFangSC-Light;font-size: 15px;letter-spacing: 0.544px;text-indent: 29.3333px;">扩展性较差,对于分表、字段增减、变更等的支持较弱</span></p></li> <li><p style="margin: 5px 8px;white-space: normal;line-height: 1.75em;"><span style="background-color: rgb(255, 255, 255);color: rgb(85, 85, 85);font-family: PingFangSC-Light;font-size: 15px;letter-spacing: 0.544px;text-indent: 29.3333px;">拉取的数据是该时刻的镜像,无法获取中间变化情况</span></p><p style="margin: 5px 8px;white-space: normal;line-height: 1.75em;"><br></p></li> </ul> <p style="margin: 5px 8px;white-space: normal;line-height: 1.75em;"><span style="background-color: rgb(255, 255, 255);color: rgb(85, 85, 85);font-family: PingFangSC-Light;font-size: 15px;letter-spacing: 0.544px;text-indent: 29.3333px;">为解决上述问题,我们引入Binlog实时采集 + 离线还原的解决方案,本文将从这两个方面介绍整个数据的接入流程。</span></p> <section style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"> <span style="font-family: Optima-Regular, PingFangTC-light;font-size: 15px;color: rgb(73, 73, 73);"><p line="8jEZ" style="margin-right: 8px;margin-left: 8px;line-height: 1.75em;"><span style="color: rgb(85, 85, 85);"> </span></p></span> </section> <section style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"> <br> </section> <section style="margin-top: 5px;margin-right: 8px;margin-left: 8px;white-space: normal;text-align: left;line-height: 1.75em;"> <span style="font-family: Optima-Regular, PingFangTC-light;"><em style="color: rgb(255, 125, 65);font-size: 36px;"><strong>2. </strong></em><br></span> </section> <section style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"> <span style="font-size: 24px;font-family: Optima-Regular, PingFangTC-light;"><strong><span style="color: rgb(54, 54, 54);letter-spacing: 0.544px;text-indent: 29.3333px;background-color: rgb(255, 255, 255);">整体数据流程</span></strong></span> </section> <section style="margin: 5px 8px;white-space: normal;line-height: 1.75em;"> <img class="rich_pages" data-backh="41" data-backw="562" data-ratio="0.0734375" data-s="300,640" src="/upload/6e14b7885b38ee3ce6513298fb72174a.png" data-type="png" data-w="1280" style="width: 562px;"> </section> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="1.2560975609756098" data-s="300,640" src="/upload/41f38f27ef80d1bbe277929126248c54.png" data-type="png" data-w="410" style=""></p> <p style="text-align: center;"><br></p> <section style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"> <span style="background-color: rgb(255, 255, 255);color: rgb(85, 85, 85);font-family: PingFangSC-Light;font-size: 15px;letter-spacing: 0.544px;text-indent: 29.3333px;">整体数据流程如上图所示,数据收集部分使用定制化Canal组件(基于阿里开源项目)收集binlog日志并做格式转换,然后通过消息队列传输并落地到HDFS,最后对HDFS上的binlog进行清洗还原入库。</span> </section> <section style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"> <span style="background-color: rgb(255, 255, 255);color: rgb(85, 85, 85);font-family: PingFangSC-Light;font-size: 15px;letter-spacing: 0.544px;text-indent: 29.3333px;"><br></span> </section> <section style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"> <span style="background-color: rgb(255, 255, 255);color: rgb(85, 85, 85);font-family: PingFangSC-Light;font-size: 15px;letter-spacing: 0.544px;text-indent: 29.3333px;">如果是增量接入,上述操作就完成了一次入库流程。</span> <span style="background-color: rgb(255, 255, 255);color: rgb(85, 85, 85);font-family: PingFangSC-Light;font-size: 15px;letter-spacing: 0.544px;text-indent: 29.3333px;">针对全量接入或者回溯历史数据,因为缺少历史binlog日志(发起采集时才开始收集)无法还原历史数据,此时需要借助离线一次性拉取,流程如下:</span> </section> <section style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"> <span style="background-color: rgb(255, 255, 255);color: rgb(85, 85, 85);font-family: PingFangSC-Light;font-size: 15px;letter-spacing: 0.544px;text-indent: 29.3333px;"><br></span> </section> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="background-color: rgb(255, 255, 255);color: rgb(85, 85, 85);font-family: PingFangSC-Light;font-size: 15px;letter-spacing: 0.544px;text-indent: 29.3333px;">按照上述流程采集binlog日志增量入HDFS</span></p></li> <li><p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="background-color: rgb(255, 255, 255);color: rgb(85, 85, 85);font-family: PingFangSC-Light;font-size: 15px;letter-spacing: 0.544px;text-indent: 29.3333px;">使用离线一次性拉取一份历史全量数据,按字段还原到Hive作为基点(即第一个接入周期的数据)</span></p></li> <li><p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="background-color: rgb(255, 255, 255);color: rgb(85, 85, 85);font-family: PingFangSC-Light;font-size: 15px;letter-spacing: 0.544px;text-indent: 29.3333px;">使用前一个接入周期的全量数据和本周期的增量binlog做merge形成该周期内的数据。</span></p></li> </ul> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="background-color: rgb(255, 255, 255);color: rgb(85, 85, 85);font-family: PingFangSC-Light;font-size: 15px;letter-spacing: 0.544px;text-indent: 29.3333px;">相比一般解决方案,其优点比较明显,主要表现在:</span></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="background-color: rgb(255, 255, 255);color: rgb(85, 85, 85);font-family: PingFangSC-Light;font-size: 15px;letter-spacing: 0.544px;text-indent: 29.3333px;"><br></span></p> <ul class="list-paddi