文章列表

面试:BigDecimal一定不会丢失精度吗?

作者:微信小助手

<p style="white-space: normal;text-align: center;" data-mpa-powered-by="yiban.io"><span style="font-size: 13px;color: rgb(136, 136, 136);font-family: Georgia, &quot;Times New Roman&quot;, Times, &quot;Songti SC&quot;, serif;letter-spacing: 0.544px;">点击上方蓝色“</span><span style="font-size: 13px;font-family: Georgia, &quot;Times New Roman&quot;, Times, &quot;Songti SC&quot;, serif;letter-spacing: 0.544px;color: rgb(0, 128, 255);">程序猿DD</span><span style="font-size: 13px;color: rgb(136, 136, 136);font-family: Georgia, &quot;Times New Roman&quot;, Times, &quot;Songti SC&quot;, serif;letter-spacing: 0.544px;">”,选择“设为星标”</span><strong style="letter-spacing: 0.544px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;font-size: 16px;white-space: pre-line;background-color: rgb(255, 255, 255);text-align: right;"></strong></p> <p style="white-space: normal;text-align: center;"><span style="font-size: 13px;"><span style="color: rgb(136, 136, 136);font-family: Georgia, &quot;Times New Roman&quot;, Times, &quot;Songti SC&quot;, serif;letter-spacing: 0.544px;">回复“</span><span style="font-family: Georgia, &quot;Times New Roman&quot;, Times, &quot;Songti SC&quot;, serif;letter-spacing: 0.544px;color: rgb(0, 128, 255);">资源</span><span style="color: rgb(136, 136, 136);font-family: Georgia, &quot;Times New Roman&quot;, Times, &quot;Songti SC&quot;, serif;letter-spacing: 0.544px;">”获取独家整理的学习资料!</span></span></p> <p style="margin-top: 10px;margin-bottom: 10px;white-space: normal;text-align: center;"><span style="color: rgb(136, 136, 136);font-family: Georgia, &quot;Times New Roman&quot;, Times, &quot;Songti SC&quot;, serif;font-size: 14px;letter-spacing: 0.544px;"><img data-backh="34" data-backw="540" data-ratio="0.0625" data-s="300,640" data-type="jpeg" data-w="640" width="100%" src="/upload/8c292e55ba5a23cb6ebc11f2a2c4fece.jpg" style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;box-sizing: border-box !important;visibility: visible !important;width: 654px !important;"></span></p> <section style="margin-bottom: 15px;white-space: normal;text-align: left;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);"> <span style="letter-spacing: 0.544px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(178, 178, 178);font-size: 13px;">来源 |<span style="font-size: 13px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(178, 178, 178);letter-spacing: 0.544px;white-space: pre-line;">&nbsp;<span style="font-size: 13px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(178, 178, 178);letter-spacing: 0.544px;text-align: right;white-space: pre-line;background-color: rgb(255, 255, 255);">urlify.cn/ZVN7Nb</span></span></span> </section> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">我们基本已经形成了常识,需要用到金钱的地方要用BigDecimal而不是其他,而我们也都知道浮点型变量在进行计算的时候会出现丢失精度的问题。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">那么,你知道其实BigDecimal也会丢失精度吗?而使用BigDecimal的背后又有什么值得去探究的地方吗?今天,告诉你,知其然,也知其所以然。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">如下一段代码:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-size: 16px;text-align: left;background-color: rgb(255, 255, 255);border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="margin-bottom: -7px;display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/8Jeic82Or04nxpedJEEn6DshtgKy6piajx1cQFSKhXlXPEs1HdZmyyl4iaGnNlPzR1fAapofos5M7DYiczzLricFUcw/640?wx_fmt=png&quot;) 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 675px;border-radius: 5px;"></span><code style="padding: 15px 16px 16px;overflow-x: auto;color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(39, 40, 34);border-radius: 5px;">System.out.println(<span style="line-height: 26px;">0.05</span>&nbsp;+&nbsp;<span style="line-height: 26px;">0.01</span>);&nbsp;&nbsp;<br>System.out.println(<span style="line-height: 26px;">1.0</span>&nbsp;-&nbsp;<span style="line-height: 26px;">0.42</span>);&nbsp;&nbsp;<br>System.out.println(<span style="line-height: 26px;">4.015</span>&nbsp;*&nbsp;<span style="line-height: 26px;">100</span>);&nbsp;&nbsp;<br>System.out.println(<span style="line-height: 26px;">123.3</span>&nbsp;/&nbsp;<span style="line-height: 26px;">100</span>);&nbsp;&nbsp;<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">输出:<br>0.060000000000000005<br>0.5800000000000001<br>401.49999999999994<br>1.2329999999999999</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">可以看到在Java中进行浮点数运算的时候,会出现丢失精度的问题。那么我们如果在进行商品价格计算的时候,就会出现问题。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">很有可能造成我们手中有0.06元,却无法购买一个0.05元和一个0.01元的商品。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">因为如上所示,他们两个的总和为0.060000000000000005。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">这无疑是一个很严重的问题,尤其是当电商网站的并发量上去的时候,出现的问题将是巨大的。可能会导致无法下单,或者对账出现问题。所以接下来我们就可以使用Java中的BigDecimal类来解决这类问题。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;"><strong style="color: rgb(14, 136, 235);">普及一下:</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">Java中float的精度为6-7位有效数字。double的精度为15-16位。</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: rgb(0, 0, 0);font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">API</h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">构造器:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-size: 16px;text-align: left;background-color: rgb(255, 255, 255);border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="margin-bottom: -7px;display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/8Jeic82Or04nxpedJEEn6DshtgKy6piajx1cQFSKhXlXPEs1HdZmyyl4iaGnNlPzR1fAapofos5M7DYiczzLricFUcw/640?wx_fmt=png&quot;) 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 675px;border-radius: 5px;"></span><code style="padding: 15px 16px 16px;overflow-x: auto;color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(39, 40, 34);border-radius: 5px;">构造器 描述<br>BigDecimal(int) 创建一个具有参数所指定整数值的对象。<br>BigDecimal(double) 创建一个具有参数所指定双精度值的对象。<br>BigDecimal(long) 创建一个具有参数所指定长整数值的对象。<br>BigDecimal(String) 创建一个具有参数所指定以字符串表示的数值的对象。<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">函数:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-size: 16px;text-align: left;background-color: rgb(255, 255, 255);border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="margin-bottom: -7px;display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/8Jeic82Or04nxpedJEEn6DshtgKy6piajx1cQFSKhXlXPEs1HdZmyyl4iaGnNlPzR1fAapofos5M7DYiczzLricFUcw/640?wx_fmt=png&quot;) 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 675px;border-radius: 5px;"></span><code style="padding: 15px 16px 16px;overflow-x: auto;color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(39, 40, 34);border-radius: 5px;">方法 描述<br>add(BigDecimal) BigDecimal对象中的值相加,然后返回这个对象。<br>subtract(BigDecimal) BigDecimal对象中的值相减,然后返回这个对象。<br>multiply(BigDecimal) BigDecimal对象中的值相乘,然后返回这个对象。<br>divide(BigDecimal) BigDecimal对象中的值相除,然后返回这个对象。<br>toString() 将BigDecimal对象的数值转换成字符串。<br>doubleValue() 将BigDecimal对象中的值以双精度数返回。<br>floatValue() 将BigDecimal对象中的值以单精度数返回。<br>longValue() 将BigDecimal对象中的值以长整数返回。<br>intValue() 将BigDecimal对象中的值以整数返回。<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">由于一般的数值类型,例如double不能准确的表示16位以上的数字。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(14, 136, 235);">BigDecimal精度也丢失</h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">我们在使用BigDecimal时,使用它的BigDecimal(String)构造器创建对象才有意义。其他的如BigDecimal b = new BigDecimal(1)这种,还是会发生精度丢失的问题。如下代码:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-size: 16px;text-align: left;background-color: rgb(255, 255, 255);border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="margin-bottom: -7px;display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/8Jeic82Or04nxpedJEEn6DshtgKy6piajx1cQFSKhXlXPEs1HdZmyyl4iaGnNlPzR1fAapofos5M7DYiczzLricFUcw/640?wx_fmt=png&quot;) 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 675px;border-radius: 5px;"></span><code style="padding: 15px 16px 16px;overflow-x: auto;color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(39, 40, 34);border-radius: 5px;">BigDecimal a = new BigDecimal(1.01);<br>BigDecimal b = new BigDecimal(1.02);<br>BigDecimal c = new BigDecimal("1.01");<br>BigDecimal d = new BigDecimal("1.02");<br>System.out.println(a.add(b));<br>System.out.println(c.add(d));<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">输出:<br>2.0300000000000000266453525910037569701671600341796875<br>2.03</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">可见论丢失精度BigDecimal显的更为过分。但是使用Bigdecimal的BigDecimal(String)构造器的变量在进行运算的时候却没有出现这种问题。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">究其原因计算机组成原理里面都有,它们的编码决定了这样的结果。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">long可以准确存储19位数字,而double只能准备存储16位数字。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">double由于有exp位,可以存16位以上的数字,但是需要以低位的不精确作为代价。如果需要高于19位数字的精确存储,则必须用BigInteger来保存,当然会牺牲一些性能。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">所以我们一般使用BigDecimal来解决商业运算上丢失精度的问题的时候,声明BigDecimal对象的时候一定要使用它构造参数为String的类型的构造器。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">同时这个原则Effective Java和MySQL 必知必会中也都有提及。float和double只能用来做科学计算和工程计算。商业运算中我们要使用BigDecimal。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">而且我们从源码的注释中官方也给出了说明,如下是BigDecimal类的double类型参数的构造器上的一部分注释说明:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-size: 16px;text-align: left;background-color: rgb(255, 255, 255);border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="margin-bottom: -7px;display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/8Jeic82Or04nxpedJEEn6DshtgKy6piajx1cQFSKhXlXPEs1HdZmyyl4iaGnNlPzR1fAapofos5M7DYiczzLricFUcw/640?wx_fmt=png&quot;) 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 675px;border-radius: 5px;"></span><code style="padding: 15px 16px 16px;overflow-x: auto;color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(39, 40, 34);border-radius: 5px;">*&nbsp;The&nbsp;results&nbsp;of&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">this</span>&nbsp;constructor&nbsp;can&nbsp;be&nbsp;somewhat&nbsp;unpredictable.&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;One&nbsp;might&nbsp;assume&nbsp;that&nbsp;writing&nbsp;{<span style="color: rgb(117, 113, 94);line-height: 26px;">@codenew</span>&nbsp;BigDecimal(<span style="line-height: 26px;">0.1</span>)}&nbsp;in&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Java&nbsp;creates&nbsp;a&nbsp;{<span style="color: rgb(117, 113, 94);line-height: 26px;">@code</span>&nbsp;BigDecimal}&nbsp;which&nbsp;is&nbsp;exactly&nbsp;equal&nbsp;to&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;<span style="line-height: 26px;">0.1</span>&nbsp;(an&nbsp;unscaled&nbsp;value&nbsp;of&nbsp;<span style="line-height: 26px;">1</span>,&nbsp;with&nbsp;a&nbsp;scale&nbsp;of&nbsp;<span style="line-height: 26px;">1</span>),&nbsp;but&nbsp;it&nbsp;is&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;actually&nbsp;equal&nbsp;to&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;<span style="line-height: 26px;">0.1000000000000000055511151231257827021181583404541015625</span>.&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;This&nbsp;is&nbsp;because&nbsp;<span style="line-height: 26px;">0.1</span>&nbsp;cannot&nbsp;be&nbsp;represented&nbsp;exactly&nbsp;as&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;{<span style="color: rgb(117, 113, 94);line-height: 26px;">@codedouble</span>}&nbsp;(or,&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">for</span>&nbsp;that&nbsp;matter,&nbsp;as&nbsp;a&nbsp;binary&nbsp;fraction&nbsp;of&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;any&nbsp;finite&nbsp;length).&nbsp;&nbsp;Thus,&nbsp;the&nbsp;value&nbsp;that&nbsp;is&nbsp;being&nbsp;passed&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&lt;i&gt;in&lt;/i&gt;&nbsp;to&nbsp;the&nbsp;constructor&nbsp;is&nbsp;not&nbsp;exactly&nbsp;equal&nbsp;to&nbsp;<span style="line-height: 26px;">0.1</span>,&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;appearances&nbsp;notwithstanding.&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;……&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;When&nbsp;a&nbsp;{<span style="color: rgb(117, 113, 94);line-height: 26px;">@codedouble</span>}&nbsp;must&nbsp;be&nbsp;used&nbsp;as&nbsp;a&nbsp;source&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">for</span>&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;{<span style="color: rgb(117, 113, 94);line-height: 26px;">@code</span>&nbsp;BigDecimal},&nbsp;note&nbsp;that&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">this</span>&nbsp;constructor&nbsp;provides&nbsp;an&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;exact&nbsp;conversion;&nbsp;it&nbsp;does&nbsp;not&nbsp;give&nbsp;the&nbsp;same&nbsp;result&nbsp;as&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;converting&nbsp;the&nbsp;{<span style="color: rgb(117, 113, 94);line-height: 26px;">@codedouble</span>}&nbsp;to&nbsp;a&nbsp;{<span style="color: rgb(117, 113, 94);line-height: 26px;">@code</span>&nbsp;String}&nbsp;using&nbsp;the&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;{<span style="color: rgb(117, 113, 94);line-height: 26px;">@link</span>&nbsp;Double#toString(<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">double</span>)}&nbsp;method&nbsp;and&nbsp;then&nbsp;using&nbsp;the&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;{<span style="color: rgb(117, 113, 94);line-height: 26px;">@link</span>&nbsp;#BigDecimal(String)}&nbsp;constructor.&nbsp;&nbsp;To&nbsp;get&nbsp;that&nbsp;result,&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;use&nbsp;the&nbsp;{<span style="color: rgb(117, 113, 94);line-height: 26px;">@codestatic</span>}&nbsp;{<span style="color: rgb(117, 113, 94);line-height: 26px;">@link</span>&nbsp;#valueOf(<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">double</span>)}&nbsp;method.&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&lt;/ol&gt;&nbsp;&nbsp;<br><span style="line-height: 26px;"><span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="color: rgb(166, 226, 46);font-weight: bold;line-height: 26px;">BigDecimal</span><span style="line-height: 26px;">(<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">double</span>&nbsp;val)</span>&nbsp;</span>{&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">this</span>(val,MathContext.UNLIMITED);&nbsp;&nbsp;<br>}&nbsp;&nbsp;<br><br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">第一段也说的很清楚它只能计算的无限接近这个数,但是无法精确到这个数。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">第二段则说,如果要想准确计算这个值,那么需要把double类型的参数转化为String类型的。并且使用BigDecimal(String)这个构造方法进行构造。去获取结果。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(14, 136, 235);">正确运用BigDecimal</h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">另外,BigDecimal所创建的是对象,我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象,由刚才我们所罗列的API也可看出。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">在一般开发过程中,我们数据库中存储的数据都是float和double类型的。在进行拿来拿去运算的时候还需要不断的转化,这样十分的不方便。这里我写了一个工具类:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-size: 16px;text-align: left;background-color: rgb(255, 255, 255);border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="margin-bottom: -7px;display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/8Jeic82Or04nxpedJEEn6DshtgKy6piajx1cQFSKhXlXPEs1HdZmyyl4iaGnNlPzR1fAapofos5M7DYiczzLricFUcw/640?wx_fmt=png&quot;) 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 675px;border-radius: 5px;"></span><code style="padding: 15px 16px 16px;overflow-x: auto;color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(39, 40, 34);border-radius: 5px;"><span style="color: rgb(117, 113, 94);line-height: 26px;">/**&nbsp;&nbsp;<br>&nbsp;*&nbsp;<span style="font-weight: bold;line-height: 26px;">@author</span>:&nbsp;Ji&nbsp;YongGuang.&nbsp;&nbsp;<br>&nbsp;*&nbsp;<span style="font-weight: bold;line-height: 26px;">@date</span>:&nbsp;19:50&nbsp;2017/12/14.&nbsp;&nbsp;<br>&nbsp;*/</span>&nbsp;&nbsp;<br>publicclass&nbsp;BigDecimalUtil&nbsp;{&nbsp;&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">private</span>&nbsp;<span style="color: rgb(166, 226, 46);font-weight: bold;line-height: 26px;">BigDecimalUtil</span><span style="line-height: 26px;">()</span>&nbsp;</span>{&nbsp;&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">static</span>&nbsp;BigDecimal&nbsp;<span style="color: rgb(166, 226, 46);font-weight: bold;line-height: 26px;">add</span><span style="line-height: 26px;">(<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">double</span>&nbsp;v1,&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">double</span>&nbsp;v2)</span>&nbsp;</span>{<span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;v1&nbsp;+&nbsp;v2&nbsp;&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BigDecimal&nbsp;b1&nbsp;=&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">new</span>&nbsp;BigDecimal(Double.toString(v1));&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BigDecimal&nbsp;b2&nbsp;=&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">new</span>&nbsp;BigDecimal(Double.toString(v2));&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">return</span>&nbsp;b1.add(b2);&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">static</span>&nbsp;BigDecimal&nbsp;<span style="color: rgb(166, 226, 46);font-weight: bold;line-height: 26px;">sub</span><span style="line-height: 26px;">(<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">double</span>&nbsp;v1,&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">double</span>&nbsp;v2)</span>&nbsp;</span>{&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BigDecimal&nbsp;b1&nbsp;=&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">new</span>&nbsp;BigDecimal(Double.toString(v1));&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BigDecimal&nbsp;b2&nbsp;=&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">new</span>&nbsp;BigDecimal(Double.toString(v2));&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">return</span>&nbsp;b1.subtract(b2);&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">static</span>&nbsp;BigDecimal&nbsp;<span style="color: rgb(166, 226, 46);font-weight: bold;line-height: 26px;">mul</span><span style="line-height: 26px;">(<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">double</span>&nbsp;v1,&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">double</span>&nbsp;v2)</span>&nbsp;</span>{&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BigDecimal&nbsp;b1&nbsp;=&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">new</span>&nbsp;BigDecimal(Double.toString(v1));&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BigDecimal&nbsp;b2&nbsp;=&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">new</span>&nbsp;BigDecimal(Double.toString(v2));&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">return</span>&nbsp;b1.multiply(b2);&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">static</span>&nbsp;BigDecimal&nbsp;<span style="color: rgb(166, 226, 46);font-weight: bold;line-height: 26px;">div</span><span style="line-height: 26px;">(<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">double</span>&nbsp;v1,&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">double</span>&nbsp;v2)</span>&nbsp;</span>{&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BigDecimal&nbsp;b1&nbsp;=&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">new</span>&nbsp;BigDecimal(Double.toString(v1));&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BigDecimal&nbsp;b2&nbsp;=&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">new</span>&nbsp;BigDecimal(Double.toString(v2));&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;2&nbsp;=&nbsp;保留小数点后两位&nbsp;&nbsp;&nbsp;ROUND_HALF_UP&nbsp;=&nbsp;四舍五入&nbsp;&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">return</span>&nbsp;b1.divide(b2,&nbsp;<span style="line-height: 26px;">2</span>,&nbsp;BigDecimal.ROUND_HALF_UP);<span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;应对除不尽的情况&nbsp;&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br>}&nbsp;&nbsp;<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">该工具类提供了double类型的基本的加减乘除运算。直接调用即可。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;"><br></p> <section data-recommend-type="list-title" data-mpa-template="t" data-mid="" data-from="yb-recommend" style="white-space: normal;width: 578px;display: flex;justify-content: center;align-items: center;"> <section data-mid="" style="padding: 14px;width: 578px;background: rgb(255, 255, 255);border-radius: 3px;border-width: 1px;border-style: solid;border-color: rgb(232, 232, 235);"> <section data-mid="" style="width: 548px;display: flex;justify-content: center;align-items: flex-end;"> <section data-mid="" style="margin-bottom: -14px;padding: 4px 22px;height: 28px;font-size: 14px;color: rgb(19, 52, 86);line-height: 20px;background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/sUbvrqLicbpzB81mjeBxPuxnYdalGxNnJo30L2Hq3WwGficcq8w5YJkLeXnsNHocN53k55TfN5mBpCdicGRyfDg1g/640?wx_fmt=png&quot;);background-repeat: no-repeat;background-size: 100% 100%;z-index: 10;"> <p data-mid="">往期推荐</p> </section> </section> <section data-mid="" style="padding: 17px 16px 9px;width: 548px;border-width: 1px;border-style: solid;border-color: rgb(198, 226, 255);"> <a href="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&amp;mid=2247495185&amp;idx=2&amp;sn=d751a11856c65e6c3a8ce1570fde95db&amp;chksm=9bd34389aca4ca9f6ebbc106c7ebb85c38d212e0bee91f93597e20109ea788bc9ed43f007465&amp;scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" data-recommend-content="t" data-mid="" style="padding: 6px;width: 514px;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;border-bottom: 1px dashed rgb(198, 226, 255);font-size: 13px;color: rgb(44, 95, 149);line-height: 18px;"> <p data-mid="" style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;">聊一聊 Spring 中的线程安全性</p> </section></a> <a href="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&amp;mid=2247495138&amp;idx=1&amp;sn=63c48cef017d8976c085874e07a63728&amp;chksm=9bd3407aaca4c96ca084144229a285f5b9052b1f59019a2f1ed98f253085998030fdafe7c84f&amp;scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" data-recommend-content="t" data-mid="" style="padding: 6px;width: 514px;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;border-bottom: 1px dashed rgb(198, 226, 255);font-size: 13px;color: rgb(44, 95, 149);line-height: 18px;"> <p data-mid="" style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;">给 Spring Boot 项目减减肥!18.18M 到 0.18M 是如何做到的?</p> </section></a> <a href="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&amp;mid=2247495138&amp;idx=3&amp;sn=b6488204c8dafd74d43f8295fa59b217&amp;chksm=9bd3407aaca4c96c024b9ab3a2c6afd51b25bcdc335822985f23e8a831d0683769cc8da776bc&amp;scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" data-recommend-content="t" data-mid="" style="padding: 6px;width: 514px;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;border-bottom: 1px dashed rgb(198, 226, 255);font-size: 13px;color: rgb(44, 95, 149);line-height: 18px;"> <p data-mid="" style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;">全球最大同性交友网站必备的五大神器!</p> </section></a> <a href="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&amp;mid=2247495040&amp;idx=3&amp;sn=7aa682d2e3052c336cbb546a066a4ada&amp;chksm=9bd34018aca4c90ed4692b76a438d0f072f6e11c837c41e29bd1c106fb1c8ec45116c92c7843&amp;scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" data-recommend-content="t" data-mid="" style="padding: 6px;width: 514px;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;border-bottom: 1px dashed rgb(198, 226, 255);font-size: 13px;color: rgb(44, 95, 149);line-height: 18px;"> <p data-mid="" style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;">最华丽的 Kubernetes 桌面客户端:Lens</p> </section></a> <a href="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&amp;mid=2247494975&amp;idx=1&amp;sn=54f1c1b8856b8a7aa8a195cab315ec8b&amp;chksm=9bd340a7aca4c9b13bdc9ffc5f13fd16ceb1a017e5c62c1ec95625205a8c94ace8fa321b42cd&amp;scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" data-recommend-content="t" data-mid="" style="padding: 6px;width: 514px;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;border-bottom: 1px dashed rgb(198, 226, 255);font-size: 13px;color: rgb(44, 95, 149);line-height: 18px;"> <p data-mid="" style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;">那些实用与颜值齐飞的桌面!</p> </section></a> <a href="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&amp;mid=2247494975&amp;idx=2&amp;sn=0a259e33a34cd6be27365104b47067d3&amp;chksm=9bd340a7aca4c9b1bf594f3d15b8eb929a0bb596f86e7930d1da92958d49e173ec1a6081fe6b&amp;scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" data-recommend-content="t" data-mid="" style="padding: 6px;width: 514px;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;font-size: 13px;color: rgb(44, 95, 149);line-height: 18px;border-bottom: none !important;"> <p data-mid="" style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;">Spring Boot 2.x基础教程:MyBatis的多数据源配置</p> </section></a> </section> </section> </section> <p style="white-space: normal;"><br></p> <p data-lake-id="a20d224c568e48b9d67847a2c66a8c01_p_0" style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;font-size: 14px;color: rgb(38, 38, 38);line-height: 1.74;letter-spacing: 0.05em;outline-style: none;"><span style="color: rgb(64, 118, 0);"><strong><span style="color: rgb(64, 118, 0);font-size: 18px;">推荐关注</span></strong></span></p> <p data-lake-id="a20d224c568e48b9d67847a2c66a8c01_p_0" style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;font-size: 14px;color: rgb(38, 38, 38);line-height: 1.74;letter-spacing: 0.05em;outline-style: none;"><span style="color: rgb(140, 140, 140);"><img data-ratio="1" data-type="png" data-w="258" src="/upload/7b57b8ce8a74c4aebec729d708bae61d.png" style="color: rgb(38, 38, 38);font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 14px;letter-spacing: 0.7px;text-align: center;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;visibility: visible !important;width: 258px !important;"></span></p> <section style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;font-size: 14px;color: rgb(38, 38, 38);line-height: 1.74;letter-spacing: 0.05em;outline-style: none;margin-bottom: 10px;"> <span style="color: rgb(140, 140, 140);">一个专注分享后端面试的干货号!</span> </section> <section style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;font-size: 14px;color: rgb(38, 38, 38);line-height: 1.74;letter-spacing: 0.05em;outline-style: none;margin-bottom: 10px;"> <span style="color: rgb(140, 140, 140);">关注它,不迷路</span> </section> <section style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;font-size: 14px;color: rgb(38, 38, 38);line-height: 1.74;letter-spacing: 0.05em;outline-style: none;margin-bottom: 10px;"> <span style="color: rgb(140, 140, 140);"><span style="color: rgb(140, 140, 140);font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 14px;letter-spacing: 0.7px;text-align: center;background-color: rgb(255, 255, 255);">每日学干货,<span style="color: rgb(140, 140, 140);font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 14px;letter-spacing: 0.7px;text-align: center;background-color: rgb(255, 255, 255);">一起进大厂</span></span></span> </section>

因为一条SQL,我差点被祭天......

作者:微信小助手

<section style="box-sizing: border-box;font-size: 16px;"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;" powered-by="xiumi.us"> <section style="padding-top: 10px;padding-right: 10px;padding-left: 10px;background-color: rgb(239, 239, 239);box-sizing: border-box;"> <span style="display: inline-block;width: 5%;line-height: 0.8;font-weight: bolder;font-size: 48px;box-sizing: border-box;" title="" opera-tn-ra-cell="_$.pages:0.layers:0.comps:0.txt1"> <section style="box-sizing: border-box;"> “ </section></span> <section style="display: inline-block;vertical-align: top;float: right;width: 90%;line-height: 1.5;font-size: 15px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;"><span style="letter-spacing: 1px;">上周四午休时分,我正在工位上小憩,睡梦中仿佛看到了自己拿着李白在荣耀峡谷里大杀四方的情景,就在我刚拿完五杀准备带领队友推对面水晶的时候,一句慌乱急促的“糟了”把我从睡梦中惊醒......</span></p> </section> <section style="clear: both;box-sizing: border-box;line-height: 0;"> <section style="line-height: 0;width: 0px;"> <svg viewbox="0 0 1 1" style="vertical-align:top;"></svg> </section> </section> </section> </section> </section> <h4 style="line-height: 1.75em;"><br></h4> <section style="text-align: center;margin-left: 8px;margin-right: 8px;"> <img class="rich_pages" data-ratio="0.6361474435196195" data-s="300,640" src="/upload/ebc9948e558d27f4196325606e9183b1.png" data-type="png" data-w="841" style=""> </section> <p style="text-align: center;"><span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 1px;"></span><em style="max-width: 100%;color: rgb(89, 89, 89);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 14px;letter-spacing: 1px;text-align: center;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;">图片来自 Pexels</em></p> <section style="line-height: normal;"> <br> </section> <section style="box-sizing: border-box;font-size: 16px;"> <section style="border-bottom: 1px solid black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;border-bottom: 6px solid rgb(89, 89, 89);margin-bottom: -1px;border-top-color: rgb(89, 89, 89);border-right-color: rgb(89, 89, 89);border-left-color: rgb(89, 89, 89);font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">反常的 SQL 语句</p> </section> </section> </section> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">我眯开朦胧的双眼,才发现刚才的发声来源于我的组长庄哥,看到他在紧张的点开日志系统查看日志,我预感到有什么不妙的事情发生。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">仔细一问才知道,原来就在我眯眼的期间,线上数据库服务器的 CPU 被打满,同时触发了生产数据库只读延迟的限定时间并且发出告警,而且告警的过程持续了半个小时。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">这让我倒吸了一口凉气,因为我们组做的系统很多都用的是同一个数据库服务器,日用户活跃量有好几十万,如果服务器崩溃了将会使所有的系统服务都不可用。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">于是我们赶紧通过 SQL 日志进行问题查找,最后排查出来是因为一张 SQL 的高量查询没有走索引导致。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">日志列表显示,这条 SQL 语句的扫描行数达到了上百万,基本就是全表扫描的情况,而且半个小时的时间查询了达上万次,每条 SQL 查询的耗时都在 3000ms 以上。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">我的天啊,难怪服务器会 CPU 打满,这么一条耗时的 SQL 语句查询量这么大,数据库的资源当然是直接就崩溃了。</span></p> <section style="line-height: normal;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">这是当时那条 SQL 的查询情况:</span> </section> <section style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"> <img class="rich_pages" data-ratio="0.13199348180336773" data-s="300,640" src="/upload/ed8e04571f6d9e05c9ceadaf314d9f58.png" data-type="png" data-w="1841" style=""> </section> <section style="box-sizing: border-box;font-size: 16px;"> <section style="border-bottom: 1px solid black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;border-bottom: 6px solid rgb(89, 89, 89);margin-bottom: -1px;border-top-color: rgb(89, 89, 89);border-right-color: rgb(89, 89, 89);border-left-color: rgb(89, 89, 89);font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">临时处理</p> </section> </section> </section> <p style="line-height: normal;"><br></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">看了这条语句,我又倒吸一口凉气,这不就是我写的系统调用的 SQL 语句吗?完了,这回逃不掉了,真是人在睡梦里,锅从天上来。<br></span> </section> <section style="text-align: center;margin-bottom: 5px;"> <img class="rich_pages" data-ratio="1.255" data-s="300,640" src="/upload/eea2acf27d2dde1d301cafa305e1ba89.jpg" data-type="jpeg" data-w="200" style=""> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">当然,因为是我自己写的 SQL,所以我一看就知道这条语句是有问题的。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">根据我的代码处理,这条 SQL 的调用还少了个重要的参数 user_fruit_id,这个参数没有传的话是不应该走这条 SQL 查询的。</span></p> <section style="line-height: normal;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">在我的设计里,该参数是数据表里一个联合索引的最左侧字段,如果该字段没有传值的话,那么索引就不会生效了。</span> </section> <section style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;word-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;">KEY&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">`idx_userfruitid_type`</span>&nbsp;(<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">`user_fruit_id`</span>,<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">`task_type`</span>,<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">`receive_start_time`</span>,<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">`receive_end_time`</span>)&nbsp;USING&nbsp;BTREE<br></code></pre> </section> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">虽然定位到了 SQL 语句,但是线上的问题刻不容缓,总不可能找出 Bug 改完再上线吧。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">所以,我们只能做了一个临时处理,就是在原来的表上多加了一个联合索引,其实就是去掉了 user_fruit_id 字段,让这些高量的查询都能走新的索引。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">就像下面这样:</span></p> <section style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;word-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;">KEY&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">`idx_task_type_receive_start_time`</span>&nbsp;(<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">`task_type`</span>,<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">`receive_start_time`</span>,<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">`receive_end_time`</span>,<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">`created_time`</span>)&nbsp;USING&nbsp;BTREE<br></code></pre> </section> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">加上索引后,SQL 的扫描行数就大幅度的降低了,重启实例后就又能正常运行了。</span></p> <section style="line-height: normal;"> <br> </section> <section style="box-sizing: border-box;font-size: 16px;"> <section style="border-bottom: 1px solid black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;border-bottom: 6px solid rgb(89, 89, 89);margin-bottom: -1px;border-top-color: rgb(89, 89, 89);border-right-color: rgb(89, 89, 89);border-left-color: rgb(89, 89, 89);font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">最左匹配原则</p> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">那么为什么最左侧的字段没传索引就不生效了,这是因为 MySQL 的联合索引是基于“最左匹配原则”匹配的。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">我们都知道,索引的底层是 B+ 树结构,联合索引的结构也是 B+ 树,只不过键值数量不是一个,而是多个,构建一颗 B+ 树只能根据一个值来构建,因此数据库依据联合索引最左的字段来构建 B+ 树。</span></p> <section style="line-height: normal;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">例如我们用两个字段(name,age)这个联合索引来分析:</span> </section> <p style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="rich_pages" data-ratio="0.716" data-s="300,640" src="/upload/a6c4b0bffbf9075cfa44db44ea276a24.jpg" data-type="jpeg" data-w="500" style=""></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 14px;"><em><span style="color: rgb(89, 89, 89);letter-spacing: 1px;">图片来源于林晓斌老师的《MySQL 实战 45 讲》课程</span></em></span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">当我们在 where 条件中查找 name 为“张三”的所有记录的时候,可以快速定位到 ID4,并且查出所有包含“张三”的记录。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">而如果要查找“张三,10”这一条特定的数据,就可以用 name = "张三" and age = 10&nbsp;获取。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">因为联合索引的键值对是两个,所以只要前面的 name 确定的情况下就可以进一步定位到具体的 age 记录。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">但是如果你的查询条件只有 age 的话,那么索引就不会生效,因为没有匹配最左边的字段,后面所有的索引字段都不会生效。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">所以我之前写的 SQL 语句才会因为少了最左边的 user_fruit_id 字段而走了全表扫描的查询方式。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">正常来说,假设一个联合索引设计成(a,b)这样的结构的话,那么用 a and b 作为条件,或者 a 单独作为查询条件都会走索引,这种情况下我们就不要再为 a 字段单独设计索引了。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">但如果查询条件里面只有 b 的语句,是无法使用(a,b)这个联合索引的,这时候你不得不维护另外一个索引,也就是说你需要同时维护(a,b)、(b) 这两个索引。</span></p> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="border-bottom: 1px solid black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;border-bottom: 6px solid rgb(89, 89, 89);margin-bottom: -1px;border-top-color: rgb(89, 89, 89);border-right-color: rgb(89, 89, 89);border-left-color: rgb(89, 89, 89);font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">找出 Bug</p> </section> </section> </section> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">虽然临时做了处理,但问题并不算解决,很明显是系统出现了 Bug 才会有走这样的查询条件。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">因为是我自己写的代码,所以知道是哪条 SQL 后我就马上定位到了代码里的具体方法,后来才发现是因为我对 user_fruit_id 字段的判空处理不生效所致。</span></p> <p style="line-height: normal;"><br></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">因为该字段是从调用方传过来的,所以我在方法参数里对该字段做了非空限制的注解,也就是 javax 包下的 @NotNull:</span> </section> <section style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;word-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">public</span>&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;word-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">class</span>&nbsp;<span style="line-height: inherit;color: rgb(165, 218, 45);word-wrap: inherit !important;word-break: inherit !important;">GardenUserTaskListReq</span>&nbsp;<span style="line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">implements</span>&nbsp;<span style="line-height: inherit;color: rgb(165, 218, 45);word-wrap: inherit !important;word-break: inherit !important;">Serializable</span>&nbsp;</span>{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">private</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">static</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">final</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">long</span>&nbsp;serialVersionUID&nbsp;=&nbsp;-<span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);word-wrap: inherit !important;word-break: inherit !important;">9161295541482297498L</span>;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(91, 218, 237);word-wrap: inherit !important;word-break: inherit !important;">@ApiModelProperty</span>(notes&nbsp;=&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"水果id"</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(91, 218, 237);word-wrap: inherit !important;word-break: inherit !important;">@NotNull</span>(message&nbsp;=&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"水果id不能为空"</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">private</span>&nbsp;Long&nbsp;userFruitId;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);word-wrap: inherit !important;word-break: inherit !important;">/**以下省略*/</span><br>&nbsp;&nbsp;&nbsp;&nbsp;.....................<br>}<br></code></pre> </section> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">虽然加上该注解来做非空校验,但我却没有在参数加上另一个注解 @Validated。</span></p> <section style="line-height: normal;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">该注解如果没加上的话,那么调用 javax 包下的校验规则就都不生效,正确的写法是在 controller 层方法的参数前面加上注解:<br></span> </section> <p style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="rich_pages" data-ratio="0.16596931659693165" data-s="300,640" src="/upload/2d3d1723f3860526a1f18055b7c401fc.png" data-type="png" data-w="717" style=""></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">除此之外,因为 user_fruit_id 这个字段是另一张表的主键,我在代码里也没有对这张表是否存在这个 id 做查询判断。</span></p> <section style="line-height: normal;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">这样一来,无论调用方传什么值过来都会直接触发 SQL 查询,并且在不跑索引的情况下直接走全表扫描。</span> </section> <section style="text-align: center;margin-bottom: 5px;"> <img class="rich_pages" data-ratio="0.6139705882352942" src="/upload/f7043b85b24236eea6a21e47addef2ab.gif" data-type="gif" data-w="272" style=""> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">不得不说,这真是个低级错误,说真的,我对这个原因真是感到嘀笑皆非,再怎么说也工作几年了,怎么还犯一些新手级别的错误呢,这脸打得真是让我相当惭愧。</span><br></p> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="border-bottom: 1px solid black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;border-bottom: 6px solid rgb(89, 89, 89);margin-bottom: -1px;border-top-color: rgb(89, 89, 89);border-right-color: rgb(89, 89, 89);border-left-color: rgb(89, 89, 89);font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">总结</p> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">虽然是低级错误,但造成的后果也算挺严重了,这次事件也让我更加的警醒,在以后的开发工作中必须要遵守该有的原则,</span><span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 1px;">大概有这么几点:</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">①不能相信调用端。</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">重要的参数都要先做验证,即使是非空值也需要做验证,不符合条件的就要直接返回或抛异常,不能参与业务 SQL 的查询,否则频繁的访问也会对服务造成负担。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">②SQL 语句要先做性能查询。</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">对于数据量大的表,建好索引后,所有的 SQL 查询语句要用 explain 检测性能,并且根据结果来进一步优化索引。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">③代码必须要 Review。</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">之前我没有放太大的精力在代码的 Review 上,虽说跟迭代排期的紧凑也有关系,但不管怎么说,Bug 确实是我的疏忽造成的,尤其是像空值这种细小的错误在 Java 里可以说家常便饭。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">千里之堤毁于蚁穴,有时一个小 Bug 很容易就引发整个系统的崩盘,这一次的问题也让我更加深刻的认识到了 Review 代码的重要性,不管业务开发的工作量有多麻烦,这一步操作绝对不能忽视。</span></p> <section style="line-height: normal;"> <br> </section> <p style="white-space: normal;line-height: 1.75em;"><span style="color: rgb(89, 89, 89);letter-spacing: 1px;"><em><span style="font-size: 14px;">作者:鄙人薛某</span></em></span></p> <p style="white-space: normal;line-height: 1.75em;"><span style="color: rgb(89, 89, 89);letter-spacing: 1px;"><em><span style="font-size: 14px;">编辑:<em>陶家龙</em></span></em></span></p> <p style="white-space: normal;line-height: 27.2px;text-align: start;"><em><span style="line-height: 1.75em;font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">出处:</span><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 0.544px;line-height: 20px;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">https://www.cnblogs.com/yeya/p/13200655.html</span></em></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.39375" src="/upload/eccf90ae5f48405df149baa3056d4bf3.gif" data-type="gif" data-w="640" style=""></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="margin-top: 0.5em;margin-bottom: 0.5em;box-sizing: border-box;" powered-by="xiumi.us"> <section style="font-size: 15px;border-style: solid;border-width: 0px 0px 1px;color: rgb(89, 89, 89);border-bottom-color: rgba(215, 215, 215, 0.960784);box-sizing: border-box;"> <p style="box-sizing: border-box;"><span style="letter-spacing: 1px;"><strong>精彩文章推荐:</strong></span></p> </section> </section> </section> <section style="line-height: 2em;"> <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5ODI5Njc2MA==&amp;mid=2655832838&amp;idx=1&amp;sn=ca92f3405972f035a6849658c487bbce&amp;chksm=bd7486d18a030fc7953df2f45447cb0cb30e572b8dd9abd0c0b0653b2b1342d6ddcf2e0045aa&amp;scene=21#wechat_redirect" data-itemshowtype="11" tab="innerlink" style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;" data-linktype="2"><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">1行代码的“拍一拍”,网友们已经玩上瘾了!</span></a> <br> </section> <section style="line-height: 2em;"> <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5ODI5Njc2MA==&amp;mid=2655832752&amp;idx=1&amp;sn=f645aadfdd4cb7d41c765f1b66ee0879&amp;chksm=bd7487678a030e714e778cfe3cea07cb046f211f0a3be0ac1521c0a94e1c240d651321ec63cf&amp;scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;" data-linktype="2"><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">可算是有文章,把Linux零拷贝讲透彻了!</span></a> <br> </section> <section style="line-height: 2em;"> <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5ODI5Njc2MA==&amp;mid=2655832596&amp;idx=1&amp;sn=612f510df7020ea44f54e79e7691a044&amp;chksm=bd7487c38a030ed5739575fcb9eb6897546e7eea7201ab68bfaacd80f9a1057f82c22477ae30&amp;scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;" data-linktype="2"><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">面试问Redis集群,被虐的不行了......</span></a> <br> </section>

我们的系统需要什么样的分布式锁?

作者:微信小助手

<p style="text-align: center;"><img class="rich_pages js_insertlocalimg" src="/upload/8367bd89daa7881c411b998f6b8f5b33.jpg" data-cropx1="0" data-cropx2="1024" data-cropy1="0" data-cropy2="643.1003460207613" data-ratio="0.6279296875" data-s="300,640" src="https://mmbiz.qpic.cn/mmbiz_jpg/Z6bicxIx5naIaK30vyCRcG8O6yRqfGyhVVWI4BSUZ3GSeWVwp2DJKcibCI0VP39RbR2uk4MJvX8BoI2QQibkN1qzA/640?wx_fmt=jpeg" data-type="jpeg" data-w="1024" style="width: 578px;height: 363px;"></p> <section powered-by="xiumi.us" style="max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;line-height: 27.2px;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section powered-by="xiumi.us" style="max-width: 100%;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section label="Copyright Reserved by PLAYHUDONG." donone="shifuMouseDownCard('shifu_c_008')" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section powered-by="xiumi.us" style="max-width: 100%;letter-spacing: 0.612px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section label="Copyright Reserved by PLAYHUDONG." donone="shifuMouseDownCard('shifu_c_008')" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section label="Copyright Reserved by PLAYHUDONG." donone="shifuMouseDownCard('shifu_c_008')" style="margin-right: 0em;margin-left: 0em;padding: 0.5em 1em;max-width: 100%;border-style: none;background-color: rgb(245, 245, 245);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="max-width: 100%;min-height: 1em;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(136, 136, 136);font-size: 15px;letter-spacing: 0.612px;box-sizing: border-box !important;overflow-wrap: break-word !important;">阿里妹导读:</span><span style="max-width: 100%;color: rgb(136, 136, 136);font-size: 15px;letter-spacing: 0.612px;box-sizing: border-box !important;overflow-wrap: break-word !important;">针对共享资源的互斥访问历来是很多业务系统需要解决的问题。在分布式系统中,通常会采用分布式锁这一通用型解决方案。本文将就分布式锁的实现原理、技术选型以及阿里云存储的具体实践进行论述。</span></p> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> <section style="line-height: 1.75em;"> <br> </section> <h2 style="max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;color: rgb(255, 106, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">一&nbsp; 从单机锁到分布式锁</span></strong></h2> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">在单机环境中,当共享资源自身无法提供互斥能力的时候,为了防止多线程/多进程对共享资源的同时读写访问造成的数据破坏,就需要一个第三方提供的互斥的能力,这里往往是内核或者提供互斥能力的类库,如下图所示,进程首先从内核/类库获取一把互斥锁,拿到锁的进程就可以排他性的访问共享资源。演化到分布式环境,我们就需要一个提供同样功能的分布式服务,不同的机器通过该服务获取一把锁,获取到锁的机器就可以排他性的访问共享资源,这样的服务我们统称为分布式锁服务,锁也就叫分布式锁。</span> </section> <p style="text-align: center;"><br></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.3404050144648023" data-s="300,640" src="/upload/3feaa6c1ed44f858f6c69abca301c44f.png" data-type="png" data-w="1037"></p> <section style="line-height: 1.75em;text-align: center;"> <span style="font-size: 14px;color: rgb(153, 153, 153);">单机锁到分布式锁</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">由此抽象一下分布式锁的概念,首先分布式锁需要是一个资源,这个资源能够提供并发控制,并输出一个排他性的状态,也就是:</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">&nbsp;&nbsp;</span> </section> <section style="line-height: 1.75em;text-align: center;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">锁 = 资源 + 并发控制 + 所有权展示</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">以常见的单机锁为例:</span> </section> <section style="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);">Spinlock = BOOL +CAS(乐观锁)</span></p></li> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">Mutex = BOOL + CAS + 通知(悲观锁)</span></p></li> </ul> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">Spinlock 和 Mutex 都是一个 Bool 资源,通过原子的 CAS 指令:当现在为 0 设置为 1,成功的话持有锁,失败的话不持有锁,如果不提供所有权的展示,例如 AtomicInteger,也是通过资源(Interger)+ CAS,但是不会明确的提示所有权,因此不会被视为一种锁,当然,可以将“所有权展示”这个更多地视为某种服务提供形式的包装。&nbsp; &nbsp;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">单机环境下,内核具备“上帝视角”,能够知道进程的存活,当进程挂掉的时候可以将该进程持有的锁资源释放,但发展到分布式环境,这就变成了一个挑战,为了应对各种机器故障、宕机等,就需要给锁提供了一个新的特性:可用性。&nbsp; &nbsp;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">如下图所示,任何提供三个特性的服务都可以提供分布式锁的能力,资源可以是文件、KV 等,通过创建文件、KV 等原子操作,通过创建成功的结果来表明所有权的归属,同时通过 TTL 或者会话来保证锁的可用性。</span> </section> <p><br></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.625170998632011" data-s="300,640" src="/upload/5ee676ae7e2bb33787e39a32102e6612.png" data-type="png" data-w="731" style=""></p> <section style="line-height: 1.75em;text-align: center;"> <span style="font-size: 14px;color: rgb(153, 153, 153);">分布式锁的特性和实现</span> </section> <h2 style="line-height: 1.75em;"><br></h2> <h2 style="line-height: 1.75em;"><span style="color: rgb(255, 106, 0);"><strong><span style="color: rgb(255, 106, 0);font-size: 15px;">二&nbsp; 分布式锁的系统分类&nbsp;&nbsp;</span></strong></span></h2> <p><span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span></p> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">根据锁资源本身的安全性,我们将分布式锁分为两个阵营:&nbsp;&nbsp; &nbsp; &nbsp;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">基于异步复制的分布式系统,例如 mysql,tair,redis 等。&nbsp; &nbsp;</span></p></li> </ul> <section style="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);">基于 paxos 协议的分布式一致性系统,例如 zookeeper,etcd,consul 等。</span></p></li> </ul> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">基于异步复制的分布式系统,存在数据丢失(丢锁)的风险,不够安全,往往通过 TTL 的机制承担细粒度的锁服务,该系统接入简单,适用于对时间很敏感,期望设置一个较短的有效期,执行短期任务,丢锁对业务影响相对可控的服务。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">基于 paxos 协议的分布式系统,通过一致性协议保证数据的多副本,数据安全性高,往往通过租约(会话)的机制承担粗粒度的锁服务,该系统需要一定的门槛,适用于对安全性很敏感,希望长期持有锁,不期望发生丢锁现象的服务。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <h2 style="line-height: 1.75em;"><span style="color: rgb(255, 106, 0);"><strong><span style="color: rgb(255, 106, 0);font-size: 15px;">三&nbsp; 阿里云存储分布式锁</span></strong></span></h2> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">阿里云存储在长期的实践过程中,在如何提升分布式锁使用时的正确性、保证锁的可用性以及提升锁的切换效率方面积累比较多的经验。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <h3 style="line-height: 1.75em;"><span style="font-size: 15px;color: rgb(255, 106, 0);">1&nbsp; 严格互斥性&nbsp;&nbsp;</span></h3> <p><span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span></p> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">互斥性作为分布式锁最基本的要求,对用户而言就是不能出现“一锁多占”,那么存储分布式锁是如何避免该情况的呢?</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">答案是,服务端每把锁都和唯一的会话绑定,客户端通过定期发送心跳来保证会话的有效性,也就保证了锁的拥有权。当心跳不能维持时,会话连同关联的锁节点都会被释放,锁节点就可以被重新抢占。这里有一个关键的地方,就是如何保证客户端和服务端的同步,在服务端会话过期的时候,客户端也能感知。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">如下图所示,在客户端和服务端都维护了会话的有效期的时间,客户端从心跳发送时刻(S0)开始计时,服务端从收到请求(S1)开始计时,这样就能保证客户端会先于服务端过期。&nbsp;用户在创建锁之后,核心工作线程在进行核心操作之前可以判断是否有足够的有效期,同时我们不再依赖墙上时间,而是基于系统时钟来对时间进行判断,系统时钟更加精确,且不会向前或者向后移动(秒级别误差毫秒级,同时在 NTP 跳变的场景,最多会修改时钟的速率)。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">&nbsp;</span> </section> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.5428571428571428" data-s="300,640" src="/upload/7a571abd5003e1dbfcaec637f50f4451.png" data-type="png" data-w="700" style=""></p> <section style="line-height: 1.75em;text-align: center;"> <span style="font-size: 14px;color: rgb(153, 153, 153);">存储场景的使用方式</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">在分布式锁互斥性上,我们是不是做到完美了?并非如此,还是存在一种情况,业务基于分布式锁服务的访问互斥会被破坏。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">我们来看下面的例子:如下图所示,客户端在时间点<span style="color: rgb(62, 62, 62);">(S0)</span>尝试去抢锁,在时间点(S1)在后端抢锁成功,因此也产生了一个分布式锁的有效期窗口。在有效期内,时间点(S2)做了一个访问存储的操作,很快完成,然后在时间点(S3)判断锁的有效期依旧成立,继续执行访问存储操作,结果这个操作耗时良久,超过了分布式锁的过期时间,那么可能这个时候,分布式锁已经被其他客户端抢占成功,进而出现两个客户端同时操作同一批数据的可能性,这种可能性是存在的,虽然概率很小。</span> </section> <p><br></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.6002865329512894" data-s="300,640" src="/upload/8ec3a710ae725188c3c0fe067e45e277.png" data-type="png" data-w="698" style=""></p> <section style="line-height: 1.75em;text-align: center;"> <span style="font-size: 14px;color: rgb(153, 153, 153);">越界场景</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">针对这个场景,具体的应对方案是在操作数据的时候确保有足够的锁有效期窗口,当然如果业务本身提供回滚机制的话,那么方案就更加完备,该方案也在存储产品使用分布式锁的过程中被采用。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">还有一个更佳的方案,即,存储系统本身引入 IOFence 能力。这里就不得不提 Martin Kleppmann 和 redis 的作者 antirez 之间的讨论了。redis 为了防止异步复制导致的锁丢失的问题,引入了 redlock,该方案引入了多数派的机制,需要获得多数派的锁,最大程度的保证了可用性和正确性,但仍然有两个问题:</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">墙上时间的不可靠(NTP 时间)</span></p></li> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">异构系统的无法做到严格正确性</span></p></li> </ul> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">墙上时间可以通过非墙上时间 MonoticTime 来解决(redis 目前仍然依赖墙上时间),但是异构系统只有一个系统并没有办法保证完全正确。如下图所示,Client1 获取了锁,在操作数据的时候发生了 GC,在 GC 完成时候丢失了锁的所有权,造成了数据不一致。</span> </section> <p><br></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.3535253227408143" data-s="300,640" src="/upload/dea651018291ec7806faf8154bcabbaf.png" data-type="png" data-w="1007" style=""></p> <section style="line-height: 1.75em;text-align: center;"> <span style="font-size: 14px;color: rgb(153, 153, 153);">异构系统无法做到完全正确性</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">因此需要两个系统同时协作来完成一个完全正确的互斥访问,在存储系统引入 IOFence能力,如下图所示,全局锁服务提供全局自增的 token,Client 1 拿到锁返回的 token 是 33,并带入存储系统,发生 GC,当 Client 2 抢锁成功返回 34,带入存储系统,存储系统会拒绝 token 较小的请求,那么经过了长时间 full gc 重新恢复后的 Client 1 再次写入数据的时候,因为存储层记录的 <span style="color: rgb(62, 62, 62);">t</span>oken 已经更新,携带 token 值为 33 的请求将被直接拒绝,从而达到了数据保护的效果(chubby 的论文中有讲述,也是 Martin Kleppmann 提出的解决方案)。&nbsp; &nbsp; &nbsp; &nbsp;</span> </section> <p><br></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.35810205908683973" data-s="300,640" src="/upload/735246747a25b0ec567b4f34a47af016.png" data-type="png" data-w="1117" style=""></p> <section style="line-height: 1.75em;text-align: center;"> <span style="font-size: 14px;color: rgb(153, 153, 153);">引入IOFence能力</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">这与阿里云分布式存储平台盘古的设计思路不谋而合,盘古支持了类似 IO Fence 的写保护能力,引入 Inline File 的文件类型,配合 SealFile 操作,这就有着类似 IO Fence 的写保护能力。首先,SealFile 操作用来关闭已经打开的 cs 上面的文件,防止旧的 Owner 继续写数据;其次,InlineFile 可以防止旧的 Owner 打开新的文件。这两个功能事实上也是提供了存储系统中的 Token 支持。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">&nbsp;</span> </section> <h3 style="line-height: 1.75em;"><span style="font-size: 15px;color: rgb(255, 106, 0);">2&nbsp; 可用性</span></h3> <p><span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span></p> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">存储分布式锁通过持续心跳来保证锁的健壮性,让用户不用投入很多精力关注可用性,但也有可能异常的用户进程持续占据锁。针对该场景,为了保证锁最终可以被调度,提供了可以安全释放锁的会话加黑机制。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">当用户需要将发生假死的进程持有的锁释放时,可以通过查询会话信息,并将会话加黑,此后,心跳将不能正常维护,最终导致会话过期,锁节点被安全释放。这里我们不是强制删除锁,而是选用禁用心跳的原因如下:</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </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="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </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> <h3 style="line-height: 1.75em;"><br></h3> <h3 style="line-height: 1.75em;"><span style="font-size: 15px;color: rgb(255, 106, 0);">3&nbsp; 切换效率&nbsp;&nbsp;</span></h3> <p><span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span></p> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">当进程持有的锁需要被重新调度时,持有者可以主动删除锁节点,但当持有者发生异常(如进程重启,机器宕机等),新的进程要重新抢占,就需要等待原先的会话过期后,才有机会抢占成功。默认情况下,分布式锁使用的会话生命期为数十秒,当持有锁的进程意外退出后(未主动释放锁),最长需要经过很长时间锁节点才可以被再次抢占。</span> </section> <p><br></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.505464480874317" data-s="300,640" src="/upload/5aa1d27367199fbb95e664cf89346291.png" data-type="png" data-w="732" style=""></p> <section style="line-height: 1.75em;text-align: center;"> <span style="font-size: 14px;color: rgb(153, 153, 153);">客户端和服务各自维护过期时间</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">要提升切换精度,本质上要压缩会话生命周期,同时也意味着更快的心跳频率,对后端更大的访问压力。我们通过对进行优化,使得会话周期可以进一步压缩。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">同时结合具体的业务场景,例如守护进程发现锁持有进程挂掉的场景,提供锁的 CAS 释放操作,使得进程可以零等待进行抢锁。比如利用在锁节点中存放进程的唯一标识,强制释放已经不再使用的锁,并重新争抢,该方式可以彻底避免进程升级或意外重启后抢锁需要的等待时间。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">&nbsp;</span> </section> <h2 style="line-height: 1.75em;"><span style="color: rgb(255, 106, 0);"><strong><span style="color: rgb(255, 106, 0);font-size: 15px;">四&nbsp; 结语</span></strong></span></h2> <p><br></p> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">分布式锁提供了分布式环境下共享资源的互斥访问,业务或者依赖分布式锁追求效率提升,或者依赖分布式锁追求访问的绝对互斥。同时,在接入分布式锁服务过程中,要考虑接入成本、服务可靠性、分布式锁切换精度以及正确性等问题,正确和合理的使用分布式锁,是需要持续思考并予以优化的。&nbsp;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">&nbsp;</span> </section> <blockquote style="margin-top: 0px;margin-bottom: 16px;padding-top: 0px;padding-right: 1em;padding-left: 1em;border-left-width: 0.25em;border-left-color: rgb(223, 226, 229);color: rgb(106, 115, 125);font-size: 17.5px;max-width: 100%;box-sizing: border-box;letter-spacing: 0.544px;white-space: normal;font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;;text-align: start;background-color: rgb(255, 255, 255);overflow-wrap: break-word !important;"> <h3 style="white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(153, 153, 153);">参考文章</span></h3> <p><span style="font-size: 15px;color: rgb(153, 153, 153);"><br></span></p> <section style="white-space: normal;line-height: 1.75em;"> <span style="color: rgb(153, 153, 153);font-size: 15px;">How to do distributed locking&nbsp;&nbsp; - Martin Kleppmann</span> </section> <section style="white-space: normal;line-height: 1.75em;"> <span style="color: rgb(153, 153, 153);font-size: 15px;">Is Redlock safe?&nbsp;- antirez</span> </section> <section style="white-space: normal;line-height: 1.75em;"> <span style="color: rgb(153, 153, 153);font-size: 15px;">chubby 论文&nbsp;- google</span> </section> </blockquote> <section style="max-width: 100%;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br style="max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"> </section> <hr style="border-style: solid;border-width: 1px 0px 0px;border-color: rgba(0, 0, 0, 0.1);transform-origin: 0px 0px;transform: scale(1, 0.5);"> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;text-align: center;"> <span style="font-size: 14px;color: rgb(255, 106, 0);"><strong><span style="font-size: 14px;">Flink&nbsp;</span><span style="font-size: 14px;">极客训练营</span></strong></span> </section> <section style="line-height: 1.75em;text-align: center;"> <span style="font-size: 14px;color: rgb(255, 106, 0);"><span style="font-size: 14px;">限时免费报名中</span></span> </section> <section style="line-height: 1.75em;"> <br> </section> <p style="line-height: 1.75em;"><span style="font-size: 14px;">Flink 社区联合阿里云开发者社区倾力打造,</span><span style="font-size: 14px;">Apache Flink PMC 及 Committer <span style="font-size: 14px;">大佬们</span><span style="font-size: 14px;">手把手实操演示</span>,带你&nbsp;<span style="font-size: 14px;">7 天&nbsp;</span><span style="font-size: 14px;">ge</span><span style="font-size: 14px;">t&nbsp;</span><span style="font-size: 14px;">Flink 灵活自如的基础开发技能,</span></span><span style="font-size: 14px;">完成</span><span style="font-size: 14px;">全部作</span><span style="font-size: 14px;">业与打</span><span style="font-size: 14px;">卡</span><span style="font-size: 14px;">的</span><span style="font-size: 14px;">优秀学员还</span><span style="font-size: 14px;">有机会获得 Flink T 恤等社区周边奖品哦~</span></p> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 14px;">点击&nbsp;“阅读原文”,立即报</span> <span style="font-size: 14px;">名打卡吧~</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="max-width: 100%;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;color: rgb(53, 53, 53);line-height: 1.75em;letter-spacing: 0.54px;font-family: &quot;Helvetica Neue&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, 黑体, Arial, sans-serif;font-size: 14px;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="1" data-type="jpeg" data-w="430" data-s="300,640" data-copyright="0" data-cropsely2="182" data-cropsely1="0" data-cropselx2="180" data-cropselx1="0" src="/upload/7de99e1a0d789cef8820d7628d4ad41b.jpg" style="background-color: rgb(238, 237, 235);border-width: 1px;border-style: solid;border-color: rgb(238, 237, 235);background-size: 22px;background-position: 50% 50%;background-repeat: no-repeat;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 182px !important;"> </section> <section style="margin-bottom: 0.1px;max-width: 100%;text-indent: 0em;background-color: rgb(255, 255, 255);white-space: pre-wrap;text-align: center;color: rgb(53, 53, 53);line-height: 1.75em;letter-spacing: 0.54px;font-family: monospace;font-size: 11.9px;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: 15px;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%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: 宋体;color: rgb(136, 136, 136);">关注</span><span style="max-width: 100%;font-family: 宋体;color: rgb(255, 76, 65);">「阿里技术」</span></span></strong><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></strong></span> </section> <section style="margin-bottom: 0.1px;max-width: 100%;text-indent: 0em;background-color: rgb(255, 255, 255);white-space: pre-wrap;text-align: center;color: rgb(53, 53, 53);line-height: 1.75em;letter-spacing: 0.54px;font-family: monospace;font-size: 11.9px;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: 15px;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-family: 宋体;color: rgb(136, 136, 136);box-sizing: border-box !important;overflow-wrap: break-word !important;">把握前沿技术脉搏</span></strong></span> </section> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;line-height: 1.75em;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> <section style="max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;text-align: left;width: 30px;color: rgb(62, 62, 62);letter-spacing: 0.54px;font-size: 15px;display: inline-block;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img class="__bg_gif" data-ratio="1" data-type="gif" data-w="400" src="/upload/d94385547ddd1e4f466f4de3618da7f9.gif" style="display: inline-block;vertical-align: middle;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 400px !important;"> </section> <section data-brushtype="text" style="margin-left: 5px;max-width: 100%;text-align: left;color: rgb(62, 62, 62);letter-spacing: 0.54px;font-size: 12px;vertical-align: middle;display: inline-block;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-family: &quot;Microsoft YaHei&quot;, &quot;Segoe UI&quot;, system-ui, Roboto, &quot;Droid Sans&quot;, &quot;Helvetica Neue&quot;, sans-serif, Tahoma, &quot;Segoe UI SymbolMyanmar Text&quot;, 微软雅黑;letter-spacing: 0.544px;white-space: pre-wrap;box-sizing: border-box !important;overflow-wrap: break-word !important;">戳我,报名 Flink 训练营。</span> </section> </section>

漫画:设计模式中的 “观察者模式”

作者:微信小助手

<p style="text-align: center;" data-mpa-powered-by="yiban.io"><img class="rich_pages" data-ratio="0.5722713864306784" data-s="300,640" src="/upload/bb6b83e297d6d338d15072ac809e37e8.png" data-type="png" data-w="678" style=""></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.5722713864306784" data-s="300,640" src="/upload/96ca325b7aa38749e8c453b7c01d7048.png" data-type="png" data-w="678" style=""></p> <p style="font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;"><br></p> <p style="font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Mi

用户中心,1亿数据,架构如何设计?

作者:微信小助手

<section style="line-height: 1.75em;" data-mpa-powered-by="yiban.io"> <span style="font-size: 15px;letter-spacing: 1px;">本文较长,可提前收藏。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;letter-spacing: 1px;">用户中心</span></strong> <span style="font-size: 15px;letter-spacing: 1px;">,几乎是所有互联网公司,必备的子系统。随着数据量不断增加,吞吐量不断增大,用户中心的架构,该如何演进呢。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"></span> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;letter-spacing: 1px;">什么是用户中心业务?</span></strong> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">用户中心是一个通用业务,主要</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">提供用户注册、登录、信息查询与修改的服务</span> <span style="font-size: 15px;letter-spacing: 1px;">。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;letter-spacing: 1px;">用户中心的数据结构是怎么样的?</span></strong> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">用户中心的核心数据结构为:<br></span> </section> <section style="line-height: 1.75em;"> <span style="letter-spacing: 1px;font-size: 12px;">User(uid, login_name, passwd, sex, age, nickname, …)</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">其中:</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)</span> <span style="letter-spacing: 1px;font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;">为用户ID,为主键;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)</span> <span style="letter-spacing: 1px;font-size: 12px;">login_name, passwd, sex&nbsp;</span> <span style="font-size: 15px;letter-spacing: 1px;">等是用户属性;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;letter-spacing: 1px;">其系统架构又是怎么样的呢?</span></strong> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">在业务初期,</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">单库单表</span> <span style="font-size: 15px;letter-spacing: 1px;">,配合</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">用户中心微服务</span> <span style="font-size: 15px;letter-spacing: 1px;">,就能满足绝大部分业务需求,其典型的架构为:</span> </section> <section style="line-height: 1.75em;"> <img data-ratio="1.1444444444444444" data-type="png" data-w="90" src="/upload/d9a8320945b8bb3e885742db7e118b03.png" data-s="300,640"> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)</span> <span style="letter-spacing: 1px;font-size: 12px;">user-center</span> <span style="font-size: 15px;letter-spacing: 1px;">:用户中心服务,对调用者提供友好的RPC接口;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)</span> <span style="letter-spacing: 1px;font-size: 12px;">user-db</span> <span style="font-size: 15px;letter-spacing: 1px;">:对用户进行数据存储;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"></span> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;letter-spacing: 1px;">当数据量越来越大,例如达到1亿注册量时,会出现什么问题呢?</span></strong> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">随着数据量越来越大,单库无法承载所有的数据,</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">此时需要对数据库进行水平切分。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">常见的水平切分算法有“</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">范围法</span> <span style="font-size: 15px;letter-spacing: 1px;">”和“</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">哈希法</span> <span style="font-size: 15px;letter-spacing: 1px;">”。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;letter-spacing: 1px;">水平切分,什么是范围法?</span></strong> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">范围法,以用户中心的业务主键</span> <span style="letter-spacing: 1px;font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;">为划分依据,</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">采用区间的方式</span> <span style="font-size: 15px;letter-spacing: 1px;">,将数据水平切分到两个数据库实例上去:</span> </section> <section style="line-height: 1.75em;"> <img data-ratio="0.4928909952606635" data-type="png" data-w="211" src="/upload/e765d44002f70fb50bb0ad8b30e9e750.png" data-s="300,640"> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)</span> <span style="letter-spacing: 1px;font-size: 12px;">user-db1</span> <span style="font-size: 15px;letter-spacing: 1px;">:存储0到1千万的</span> <span style="letter-spacing: 1px;font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;">数据;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)</span> <span style="letter-spacing: 1px;font-size: 12px;">user-db2</span> <span style="font-size: 15px;letter-spacing: 1px;">:存储1千万到2千万的</span> <span style="letter-spacing: 1px;font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;">数据;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;letter-spacing: 1px;">范围法有什么优点?</span></strong> <span style="font-size: 15px;letter-spacing: 1px;"></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">切分策略简单</span> <span style="font-size: 15px;letter-spacing: 1px;">,根据</span> <span style="letter-spacing: 1px;font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;">,按照范围,</span> <span style="letter-spacing: 1px;font-size: 12px;">user-center</span> <span style="font-size: 15px;letter-spacing: 1px;">很快能够定位到数据在哪个库上;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">扩容简单</span> <span style="font-size: 15px;letter-spacing: 1px;">,如果容量不够,只要增加</span> <span style="letter-spacing: 1px;font-size: 12px;">user-db3</span> <span style="font-size: 15px;letter-spacing: 1px;">,拓展2千万到3千万的</span> <span style="letter-spacing: 1px;font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;">即可;</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;letter-spacing: 1px;">范围法有什么缺点?</span></strong> <span style="font-size: 15px;letter-spacing: 1px;"></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)</span> <span style="letter-spacing: 1px;color: rgb(255, 76, 0);font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">必须要满足递增的特性</span> <span style="font-size: 15px;letter-spacing: 1px;">;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">数据量不均</span> <span style="font-size: 15px;letter-spacing: 1px;">,新增的</span> <span style="letter-spacing: 1px;font-size: 12px;">user-db3</span> <span style="font-size: 15px;letter-spacing: 1px;">,在初期的数据会比较少;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(3)</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">请求量不均</span> <span style="font-size: 15px;letter-spacing: 1px;">,一般来说,新注册的用户活跃度会比较高,故</span> <span style="letter-spacing: 1px;font-size: 12px;">user-db2</span> <span style="font-size: 15px;letter-spacing: 1px;">往往会比</span> <span style="letter-spacing: 1px;font-size: 12px;">user-db1</span> <span style="font-size: 15px;letter-spacing: 1px;">负载要高,导致服务器利用率不平衡;</span> </section> <section style="line-height: 1.75em;"> <em><span style="font-size: 15px;letter-spacing: 1px;color: rgb(0, 128, 255);">画外音:数据库层面的负载均衡,既要考虑数据量的均衡,又要考虑负载的均衡。</span></em> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong style="white-space: normal;"><span style="font-size: 15px;letter-spacing: 1px;">水平切分,什么是哈希法?</span></strong></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">哈希法,也是以用户中心的业务主键</span> <span style="letter-spacing: 1px;font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;">为划分依据,</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">采用哈希的方式</span> <span style="font-size: 15px;letter-spacing: 1px;"><span style="font-size: 15px;letter-spacing: 1px;">,</span>将数据水平切分到两个数据库实例上去:</span> </section> <section style="line-height: 1.75em;"> <img data-ratio="0.4953271028037383" data-type="png" data-w="214" src="/upload/1bbbb1d5cc8819c8feb6e5a06f1dbbbc.png" data-s="300,640"> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)</span> <span style="letter-spacing: 1px;font-size: 12px;">user-db1</span> <span style="font-size: 15px;letter-spacing: 1px;">:存储奇数的</span> <span style="letter-spacing: 1px;font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;">数据;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)</span> <span style="letter-spacing: 1px;font-size: 12px;">user-db2</span> <span style="font-size: 15px;letter-spacing: 1px;">:存储偶数的</span> <span style="letter-spacing: 1px;font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;">数据;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;letter-spacing: 1px;">哈希法有什么优点?</span></strong> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">切分策略简单</span> <span style="font-size: 15px;letter-spacing: 1px;">,根据</span> <span style="letter-spacing: 1px;font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;">,按照hash,</span> <span style="letter-spacing: 1px;font-size: 12px;">user-center</span> <span style="font-size: 15px;letter-spacing: 1px;">很快能够定位到数据在哪个库上;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">数据量均衡</span> <span style="font-size: 15px;letter-spacing: 1px;">,只要</span> <span style="letter-spacing: 1px;font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;">是随机的,数据在各个库上的分布一定是均衡的;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(3)</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">请求量均衡</span> <span style="font-size: 15px;letter-spacing: 1px;">,只要</span> <span style="letter-spacing: 1px;font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;">是<span style="font-size: 15px;letter-spacing: 1px;">随机</span>的,负载在各个库上的分布一定是均衡的;</span> </section> <section style="line-height: 1.75em;"> <span style="color: rgb(0, 128, 255);"><em><span style="color: rgb(0, 128, 255);font-size: 15px;letter-spacing: 1px;">画外音:如果采用分布式id生成器,id的生成,一般都是随机的。</span></em></span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong style="white-space: normal;"><span style="font-size: 15px;letter-spacing: 1px;">哈希法有什么缺点?</span></strong></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">扩容麻烦</span> <span style="font-size: 15px;letter-spacing: 1px;">,如果容量不够,要增加一个库,重新hash可能会导致数据迁移;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;letter-spacing: 1px;">用户中心架构,实施了水平切分之后,会带来什么新的问题呢?</span></strong> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">使用</span> <span style="letter-spacing: 1px;font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;">来进行水平切分之后,</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">对于</span> <span style="letter-spacing: 1px;color: rgb(255, 76, 0);font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">属性上的查询,可以直接路由到库</span> <span style="font-size: 15px;letter-spacing: 1px;">,假设访问</span> <span style="letter-spacing: 1px;font-size: 12px;">uid=124</span> <span style="font-size: 15px;letter-spacing: 1px;">的数据,取模后能够直接定位</span> <span style="letter-spacing: 1px;font-size: 12px;">db-user1</span> <span style="font-size: 15px;letter-spacing: 1px;">:</span> </section> <section style="line-height: 1.75em;"> <img data-ratio="0.5652173913043478" data-type="png" data-w="299" src="/upload/ac17a7b9103939af05984c33f35c507d.png" data-s="300,640"> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">但</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">对于非</span> <span style="letter-spacing: 1px;color: rgb(255, 76, 0);font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">属性上的查询,就悲剧了</span> <span style="font-size: 15px;letter-spacing: 1px;">,例如</span> <span style="letter-spacing: 1px;font-size: 12px;">login_name</span> <span style="font-size: 15px;letter-spacing: 1px;"><span style="font-size: 15px;letter-spacing: 1px;">属性上的查询</span>:</span> </section> <section style="line-height: 1.75em;"> <img data-ratio="0.5782312925170068" data-type="png" data-w="294" src="/upload/4db9cf6d423c2279167a385c9edefcac.png" data-s="300,640"> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">假设访问</span> <span style="letter-spacing: 1px;font-size: 12px;">login_name=shenjian</span> <span style="font-size: 15px;letter-spacing: 1px;">的数据,由于不知道数据落在哪个库上,</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">往往需要遍历所有库</span> <span style="font-size: 15px;letter-spacing: 1px;">,当分库数量多起来,性能会显著降低。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"></span> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;letter-spacing: 1px;">用户中心,非</span></strong> <span style="font-size: 12px;"><strong><span style="letter-spacing: 1px;">uid</span></strong></span> <strong><span style="font-size: 15px;letter-spacing: 1px;">属性查询,有哪些业务场景?</span></strong> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;letter-spacing: 1px;">任何脱离业务的架构设计都是耍流氓。</span></strong> <span style="font-size: 15px;letter-spacing: 1px;"></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">在进行架构讨论之前,先来对业务进行简要分析,用户中心非</span> <span style="letter-spacing: 1px;font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;">属性上,有<strong>两类典型的业务需求</strong>。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;letter-spacing: 1px;">第一大类,用户侧,前台访问</span></strong> <span style="font-size: 15px;letter-spacing: 1px;">,最典型的有两类需求:</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)<strong>用户登录</strong>:通过登录名</span> <span style="letter-spacing: 1px;font-size: 12px;">login_name</span> <span style="font-size: 15px;letter-spacing: 1px;">查询用户的实体,1%请求属于这种类型;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)<strong>用户信息查询</strong>:登录之后,通过</span> <span style="letter-spacing: 1px;font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;">来查询用户的实例,99%请求属这种类型;</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">用户侧的查询,基本上是</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">单条记录的查询,访问量较大,服务需要高可用,并且对一致性的要求较高</span> <span style="font-size: 15px;letter-spacing: 1px;">。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;letter-spacing: 1px;">第二大类,运营侧,后台访问</span></strong> <span style="font-size: 15px;letter-spacing: 1px;">,根据产品、运营需求,访问模式各异,按照年龄、性别、头像、登陆时间、注册时间来进行查询。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">运营侧的查询,基本上是</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">批量分页</span> <span style="font-size: 15px;letter-spacing: 1px;">的查询,由于是内部系统,</span> <span style="color: rgb(255, 76, 0);font-size: 15px;letter-spacing: 1px;">访问量很低,对可用性的要求不高,对一致性的要求也没这么严格</span> <span style="font-size: 15px;letter-spacing: 1px;">。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;letter-spacing: 1px;">对于这两类不同的业务需求,应该使用什么样的架构方案来解决呢?</span></strong> <span style="font-size: 15px;letter-spacing: 1px;"></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">总的来说,针对这两类业务需求,架构设计的核心思路为:</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)<strong>用户侧</strong>,采用“</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">建立非</span> <span style="letter-spacing: 1px;color: rgb(255, 76, 0);font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">属性到</span> <span style="letter-spacing: 1px;color: rgb(255, 76, 0);font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">的映射关系</span> <span style="font-size: 15px;letter-spacing: 1px;">”的架构方案;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)<strong>运营侧</strong>,采用“</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">前台与后台分离</span> <span style="font-size: 15px;letter-spacing: 1px;">”的架构方案;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;letter-spacing: 1px;">用户侧,如何实施“<span style="letter-spacing: 1px;">建立非</span></span></strong> <span style="font-size: 12px;"><strong><span style="letter-spacing: 1px;">uid</span></strong></span> <strong><span style="font-size: 15px;letter-spacing: 1px;">属性到</span></strong> <span style="font-size: 12px;"><strong><span style="letter-spacing: 1px;">uid</span></strong></span> <strong><span style="font-size: 15px;letter-spacing: 1px;"><span style="font-size: 15px;letter-spacing: 1px;">的映射关系</span>”呢?</span></strong> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">常见的方法有<strong>四种</strong>:<br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">索引表法</span> <span style="font-size: 15px;letter-spacing: 1px;">;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">缓存映射法</span> <span style="font-size: 15px;letter-spacing: 1px;">;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(3)</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">生成</span> <span style="letter-spacing: 1px;color: rgb(255, 76, 0);font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">法</span> <span style="font-size: 15px;letter-spacing: 1px;">;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(4)</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">基因法</span> <span style="font-size: 15px;letter-spacing: 1px;">;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">接下来,咱们一一介绍。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;letter-spacing: 1px;">什么是,索引表法?</span></strong> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">索引表法的思路是:</span> <span style="letter-spacing: 1px;font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;">能直接定位到库,</span> <span style="letter-spacing: 1px;font-size: 12px;">login_name</span> <span style="font-size: 15px;letter-spacing: 1px;">不能直接定位到库,如果</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">通过</span> <span style="letter-spacing: 1px;color: rgb(255, 76, 0);font-size: 12px;">login_name</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">能查询到</span> <span style="letter-spacing: 1px;color: rgb(255, 76, 0);font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;">,问题便能得到解决。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">具体的解决方案如下:</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)建立一个索引表记录</span> <span style="letter-spacing: 1px;font-size: 12px;">login_name</span> <span style="font-size: 15px;letter-spacing: 1px;">与</span> <span style="letter-spacing: 1px;font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;">的映射关系;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)用</span> <span style="letter-spacing: 1px;font-size: 12px;">login_name</span> <span style="font-size: 15px;letter-spacing: 1px;">来访问时,</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">先通过索引表查询到</span> <span style="letter-spacing: 1px;color: rgb(255, 76, 0);font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">,再通过</span> <span style="letter-spacing: 1px;color: rgb(255, 76, 0);font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">定位相应的库</span> <span style="font-size: 15px;letter-spacing: 1px;">;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(3)索引表属性较少,可以容纳非常多数据,一般不需要分库;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(4)如果数据量过大,可以通过</span> <span style="letter-spacing: 1px;font-size: 12px;">login_name</span> <span style="font-size: 15px;letter-spacing: 1px;">来分库;</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;letter-spacing: 1px;">索引表法,有什么缺点呢?</span></strong> <span style="font-size: 15px;letter-spacing: 1px;"></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">数据访问,</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">会增加一次数据库查询</span> <span style="font-size: 15px;letter-spacing: 1px;">,性能会有所下降。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong style="white-space: normal;"><span style="font-size: 15px;letter-spacing: 1px;">什么是,缓存映射法?</span></strong></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">缓存映射法的思路是:访问索引表性能较低,</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">把映射关系放在缓存里</span> <span style="font-size: 15px;letter-spacing: 1px;">,能够提升性能。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><span style="font-size: 15px;letter-spacing: 1px;">具体的</span><span style="font-size: 15px;letter-spacing: 1px;">解</span><span style="font-size: 15px;letter-spacing: 1px;">决方案如下:</span></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)</span> <span style="letter-spacing: 1px;font-size: 12px;">login_name</span> <span style="font-size: 15px;letter-spacing: 1px;">查询先到</span> <span style="letter-spacing: 1px;font-size: 12px;">cache</span> <span style="font-size: 15px;letter-spacing: 1px;">中查询</span> <span style="letter-spacing: 1px;font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;">,再根据</span> <span style="letter-spacing: 1px;font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;">定位数据库;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)假设</span> <span style="letter-spacing: 1px;font-size: 12px;">cache miss</span> <span style="font-size: 15px;letter-spacing: 1px;">,扫描所有分库,获取</span> <span style="letter-spacing: 1px;font-size: 12px;">login_name</span> <span style="font-size: 15px;letter-spacing: 1px;">对应的</span> <span style="letter-spacing: 1px;font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;">,放入</span> <span style="letter-spacing: 1px;font-size: 12px;">cache</span> <span style="font-size: 15px;letter-spacing: 1px;">;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(3)</span> <span style="color: rgb(255, 76, 0);"><span style="letter-spacing: 1px;font-size: 12px;">login_name</span><span style="font-size: 15px;letter-spacing: 1px;">到</span><span style="letter-spacing: 1px;font-size: 12px;">uid</span><span style="font-size: 15px;letter-spacing: 1px;">的映射关系不会变化,映射关系一旦放入缓存,不会更改,无需淘汰,缓存命中率超高</span></span> <span style="font-size: 15px;letter-spacing: 1px;">;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(4)如果数据量过大,可以通过</span> <span style="letter-spacing: 1px;font-size: 12px;">login_name</span> <span style="font-size: 15px;letter-spacing: 1px;">进行</span> <span style="letter-spacing: 1px;font-size: 12px;">cache</span> <span style="font-size: 15px;letter-spacing: 1px;">水平切分;</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong style="white-space: normal;"><span style="font-size: 15px;letter-spacing: 1px;">缓存映射法,有什么缺点呢?</span></strong></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">仍然多了一次网络交互</span> <span style="font-size: 15px;letter-spacing: 1px;">,即一次</span> <span style="letter-spacing: 1px;font-size: 12px;">cache</span> <span style="font-size: 15px;letter-spacing: 1px;">查询。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong style="white-space: normal;"><span style="letter-spacing: 1px;">什么是,生成</span></strong></span> <span style="letter-spacing: 1px;font-size: 12px;"><strong style="white-space: normal;">uid</strong></span> <span style="font-size: 15px;letter-spacing: 1px;"><strong style="white-space: normal;"><span style="font-size: 15px;letter-spacing: 1px;">法?</span></strong></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">生成</span> <span style="letter-spacing: 1px;font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;">法的思路是:</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">不进行远程查询,由</span> <span style="letter-spacing: 1px;color: rgb(255, 76, 0);font-size: 12px;">login_name</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">直接得到</span> <span style="letter-spacing: 1px;color: rgb(255, 76, 0);font-size: 12px;">uid</span> <span style="font-size: 15px;letter-spacing: 1px;">。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><span style="font-size: 15px;letter-spacing: 1px;">具体的</span><span style="font-size: 15px;letter-spacing: 1px;">解</span><span style="font-size: 15px;letter-spacing: 1px;">决方案如下:</span></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)在用户注册时,</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">设计函数</span> <span style="letter-spacing: 1px;color: rgb(255, 76, 0);font-size: 12px;">login_name</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">生成<span style="font-size: 12px;letter-spacing: 1px;">uid</span></span> <span style="font-size: 15px;letter-spacing: 1px;">,</span> <span style="letter-spacing: 1px;font-size: 12px;">uid=f(login_name)</span> <span style="font-size: 15px;letter-spacing: 1px;">,按<span style="font-size: 12px;letter-spacing: 1px;">uid</span>分库插入数据;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)用</span> <span style="letter-spacing: 1px;font-size: 12px;">login_name</span> <span style="font-size: 15px;letter-spacing: 1px;">来访问时,先通过函数计算出<span style="font-size: 12px;letter-spacing: 1px;">uid</span>,即</span> <span style="letter-spacing: 1px;font-size: 12px;">uid=f(login_name)</span> <span style="font-size: 15px;letter-spacing: 1px;">再来一遍,由<span style="font-size: 12px;letter-spacing: 1px;">uid</span>路由到对应库;</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong style="font-size: 15px;letter-spacing: 1px;white-space: normal;">生成<span style="font-size: 12px;letter-spacing: 1px;">uid</span>法,有什么缺点呢?</strong></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">该函数设计需要非常讲究技巧,且</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">有<span style="font-size: 12px;letter-spacing: 1px;">uid</span>生成冲突风险</span> <span style="font-size: 15px;letter-spacing: 1px;">。</span> </section> <section style="line-height: 1.75em;"> <span style="color: rgb(0, 128, 255);"><em><span style="color: rgb(0, 128, 255);font-size: 15px;letter-spacing: 1px;">画外音:<span style="font-size: 12px;letter-spacing: 1px;">uid</span>冲突,是业务无法接受的,故生产环境中,一般不使用这个方法。</span></em></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong style="font-size: 15px;letter-spacing: 1px;white-space: normal;">什么是,基因法?</strong></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">基因法的思路是:不能用</span> <span style="letter-spacing: 1px;font-size: 12px;">login_name</span> <span style="font-size: 15px;letter-spacing: 1px;">生成<span style="font-size: 12px;letter-spacing: 1px;">uid</span>,但可以</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">从</span> <span style="letter-spacing: 1px;color: rgb(255, 76, 0);font-size: 12px;">login_name</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">抽取“基因”,融入<span style="font-size: 12px;letter-spacing: 1px;">uid</span>中</span> <span style="font-size: 15px;letter-spacing: 1px;">。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">假设分8库,采用<span style="font-size: 12px;letter-spacing: 1px;">uid</span>%8路由,潜台词是,<span style="font-size: 12px;letter-spacing: 1px;">uid</span>的最后3个bit决定这条数据落在哪个库上,这3个bit就是所谓的“基因”。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><span style="font-size: 15px;letter-spacing: 1px;">具体的</span><span style="font-size: 15px;letter-spacing: 1px;">解</span><span style="font-size: 15px;letter-spacing: 1px;">决方案如下:</span></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><span style="font-size: 15px;letter-spacing: 1px;"><img style="white-space: normal;" data-ratio="0.28385899814471244" data-type="png" data-w="539" src="/upload/7f4875adffbf9da18834cd6444570db3.png" data-s="300,640"></span></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)在用户注册时,</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">设计函数</span> <span style="letter-spacing: 1px;color: rgb(255, 76, 0);font-size: 12px;">login_name</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">生成3bit基因,</span> <span style="letter-spacing: 1px;color: rgb(255, 76, 0);font-size: 12px;">login_name_gene = f(login_name)</span> <span style="font-size: 15px;letter-spacing: 1px;">,如上图<strong>粉色</strong>部分;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)同时,生成61bit的全局唯一id,作为用户的标识,如上图<strong>绿色</strong>部分;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(3)接着</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">把3bit的</span> <span style="letter-spacing: 1px;color: rgb(255, 76, 0);font-size: 12px;">login_name_gene</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">也作为<span style="font-size: 12px;letter-spacing: 1px;">uid</span>的一部分</span> <span style="font-size: 15px;letter-spacing: 1px;">,如上图<strong>屎黄色</strong>部分;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(4)生成64bit的<span style="font-size: 12px;letter-spacing: 1px;">uid</span>,由id和</span> <span style="letter-spacing: 1px;font-size: 12px;">login_name_gene</span> <span style="font-size: 15px;letter-spacing: 1px;">拼装而成,并按照<span style="font-size: 12px;letter-spacing: 1px;">uid</span>分库插入数据;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(5)用</span> <span style="letter-spacing: 1px;font-size: 12px;">login_name</span> <span style="font-size: 15px;letter-spacing: 1px;">来访问时,先通过函数由</span> <span style="letter-spacing: 1px;font-size: 12px;">login_name</span> <span style="font-size: 15px;letter-spacing: 1px;">再次复原3bit基因,</span> <span style="letter-spacing: 1px;font-size: 12px;">login_name_gene = f(login_name)</span> <span style="font-size: 15px;letter-spacing: 1px;">,通过</span> <span style="letter-spacing: 1px;font-size: 12px;">login_name_gene</span> <span style="font-size: 15px;letter-spacing: 1px;">%8直接定位到库;</span> </section> <section style="line-height: 1.75em;"> <span style="color: rgb(0, 128, 255);"><em><span style="color: rgb(0, 128, 255);font-size: 15px;letter-spacing: 1px;">画外音:基因法,有点意思,在分库时经常使用。</span></em></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong style="white-space: normal;"><span style="font-size: 15px;letter-spacing: 1px;">用户侧,如何实施“前台与后台分离”的架构方案呢?</span></strong></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">前台用户侧,业务需求基本都是</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">单行记录的访问</span> <span style="font-size: 15px;letter-spacing: 1px;">,只要建立非<span style="font-size: 12px;letter-spacing: 1px;">uid</span>属性</span> <span style="letter-spacing: 1px;font-size: 12px;">login_name</span> <span style="font-size: 15px;letter-spacing: 1px;">到<span style="font-size: 12px;letter-spacing: 1px;">uid</span>的映射关系,就能解决问题。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">后台运营侧,业务需求各异,基本是</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">批量分页的访问</span> <span style="font-size: 15px;letter-spacing: 1px;">,这类访问计算量较大,返回数据量较大,比较消耗数据库性能。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;letter-spacing: 1px;">此时的架构,存在什么问题?</span></strong> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">此时,前台业务和后台业务共用一批服务和一个数据库,有可能导致,由于后台的“少数几个请求”的“批量查询”的“低效”访问,导致数据库的cpu偶尔瞬时100%,影响前台正常用户的访问(例如,登录超时)。</span> </section> <section style="line-height: 1.75em;"> <span style="color: rgb(0, 128, 255);"><em><span style="color: rgb(0, 128, 255);font-size: 15px;letter-spacing: 1px;">画外音:本质上,是系统的耦合。</span></em></span> </section> <section style="line-height: 1.75em;"> <img data-ratio="0.5083056478405316" data-type="png" data-w="301" src="/upload/edf00d122804122341e07c716303979b.png" data-s="300,640"> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">而且,为了满足后台业务各类“奇形怪状”的需求,往往会在数据库上建立各种索引,这些索引占用大量内存,会使得用户侧前台业务<span style="font-size: 12px;letter-spacing: 1px;">uid</span>/</span> <span style="letter-spacing: 1px;font-size: 12px;">login_name</span> <span style="font-size: 15px;letter-spacing: 1px;">上的查询性能与写入性能大幅度降低,处理时间增长。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">对于这一类业务,应该采用“前台与后台分离”的架构方案。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;letter-spacing: 1px;">什么是,前台与后台分离的架构方案?</span></strong> </section> <section style="line-height: 1.75em;"> <img data-ratio="0.3558951965065502" data-type="png" data-w="458" src="/upload/ae685c8c6028ffb54d7d9b9cbad7b57c.png" data-s="300,640"> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">用户侧前台业务需求架构依然不变,产品运营侧后台业务需求则抽取</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">独立的</span> <span style="letter-spacing: 1px;color: rgb(255, 76, 0);font-size: 12px;"> web / service / db </span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">来支持</span> <span style="font-size: 15px;letter-spacing: 1px;">,解除系统之间的耦合,对于“业务复杂”“并发量低”“无需高可用”“能接受一定延时”的后台业务:</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)可以去掉</span> <span style="letter-spacing: 1px;font-size: 12px;">service</span> <span style="font-size: 15px;letter-spacing: 1px;">层,在运营后台</span> <span style="letter-spacing: 1px;font-size: 12px;">web</span> <span style="font-size: 15px;letter-spacing: 1px;">层通过</span> <span style="letter-spacing: 1px;font-size: 12px;">dao</span> <span style="font-size: 15px;letter-spacing: 1px;">直接访问</span> <span style="letter-spacing: 1px;font-size: 12px;">db</span> <span style="font-size: 15px;letter-spacing: 1px;">;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)不需要反向代理,不需要集群冗余;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(3)不需要访问实时库,可以通过</span> <span style="letter-spacing: 1px;font-size: 12px;">MQ</span> <span style="font-size: 15px;letter-spacing: 1px;">或者线下异步同步数据;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(4)在数据库非常大的情况下,可以使用更契合大量数据允许接受更高延时的“索引外置”或者“</span> <span style="letter-spacing: 1px;font-size: 12px;">HIVE</span> <span style="font-size: 15px;letter-spacing: 1px;">”的设计方案;</span> </section> <section style="line-height: 1.75em;"> <img data-ratio="0.34966592427616927" data-type="png" data-w="449" src="/upload/52d8a7a4088b37abe184659f2c704156.png" data-s="300,640"> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;letter-spacing: 1px;">总结</span></strong> <span style="font-size: 15px;letter-spacing: 1px;"></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">用户中心,是<strong>典型的“单KEY”类业务</strong>,这一类业务,</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">都可以使用上述架构方案</span> <span style="font-size: 15px;letter-spacing: 1px;">。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">常见的数据库<strong>水平切分方式有两种</strong>:</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">范围法</span> <span style="font-size: 15px;letter-spacing: 1px;">;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">哈希法</span> <span style="font-size: 15px;letter-spacing: 1px;">;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;letter-spacing: 1px;">水平切分后碰到的问题</span></strong> <span style="font-size: 15px;letter-spacing: 1px;">是:</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)通过<span style="font-size: 12px;letter-spacing: 1px;">uid</span>属性查询能直接定位到库,</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">通过非<span style="font-size: 12px;letter-spacing: 1px;">uid</span>属性查询不能定位到库</span> <span style="font-size: 15px;letter-spacing: 1px;">;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;letter-spacing: 1px;">非<span style="font-size: 12px;letter-spacing: 1px;">uid</span>属性查询,有两类</span><span style="font-size: 15px;letter-spacing: 1px;">典型的业务</span></strong> <span style="font-size: 15px;letter-spacing: 1px;">:</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)<strong>用户侧,前台访问</strong>,单条记录的查询,访问量较大,服务需要高可用,并且对一致性的要求较高;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)<strong>运营侧,后台访问</strong>,根据产品、运营需求,访问模式各异,基本上是批量分页的查询,由于是内部系统,访问量很低,对可用性的要求不高,对一致性的要求也没这么严格;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">针对这两类业务,<strong>架构设计的思路是</strong>:</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)用户侧,采用“</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">建立非<span style="font-size: 12px;letter-spacing: 1px;">uid</span>属性到<span style="font-size: 12px;letter-spacing: 1px;">uid</span>的映射关系</span> <span style="font-size: 15px;letter-spacing: 1px;">”的架构方案;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)运营侧,采用“</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">前台与后台分离</span> <span style="font-size: 15px;letter-spacing: 1px;">”的架构方案;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><span style="font-size: 15px;letter-spacing: 1px;">前台</span>用户侧,<strong>“建立非<span style="font-size: 12px;letter-spacing: 1px;">uid</span>属性到<span style="font-size: 12px;letter-spacing: 1px;">uid</span>的映射关系”,有四种常见的实践</strong>:</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)<strong>索引表法</strong>:数据库中记录</span> <span style="letter-spacing: 1px;font-size: 12px;">login_name</span> <span style="font-size: 15px;letter-spacing: 1px;">与<span style="font-size: 12px;letter-spacing: 1px;">uid</span>的映射关系;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)<strong>缓存映射法</strong>:缓存中记录</span> <span style="letter-spacing: 1px;font-size: 12px;">login_name</span> <span style="font-size: 15px;letter-spacing: 1px;">与<span style="font-size: 12px;letter-spacing: 1px;">uid</span>的映射关系;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(3)<strong>生成<span style="font-size: 12px;letter-spacing: 1px;">uid</span>法</strong>:</span> <span style="letter-spacing: 1px;font-size: 12px;">login_name</span> <span style="font-size: 15px;letter-spacing: 1px;">生成<span style="font-size: 12px;letter-spacing: 1px;">uid</span>;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(4)<strong>基因法</strong>:</span> <span style="letter-spacing: 1px;font-size: 12px;">login_name</span> <span style="font-size: 15px;letter-spacing: 1px;">基因融入<span style="font-size: 12px;letter-spacing: 1px;">uid</span>;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><span style="font-size: 15px;letter-spacing: 1px;">后台</span>运营侧,<strong>“前台与后台分离”的最佳实践是</strong>:</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)前台、后台系统</span> <span style="letter-spacing: 1px;font-size: 12px;"> web/service/db </span> <span style="font-size: 15px;letter-spacing: 1px;">分离解耦,避免后台低效查询引发前台查询抖动;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)可以采用数据冗余的设计方式;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(3)可以采用“外置索引”(例如ES搜索系统)或者“大数据处理”(例如</span> <span style="letter-spacing: 1px;font-size: 12px;">HIVE</span> <span style="font-size: 15px;letter-spacing: 1px;">)来满足后台变态的查询需求;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br></span> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;letter-spacing: 1px;">任何脱离业务的架构设计都是耍流氓。</span></strong> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">成为架构师,</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">关注架构师之路</span> <span style="font-size: 15px;letter-spacing: 1px;">。</span> </section> <section style="text-align: center;line-height: normal;letter-spacing: 0.54px;font-family: -apple-system-font,BlinkMacSystemFont,&quot;Helvetica Neue&quot;,&quot;PingFang SC&quot;,&quot;Hiragino Sans GB&quot;,&quot;Microsoft YaHei UI&quot;,&quot;Microsoft YaHei&quot;,Arial,sans-serif;white-space: normal;background-color: rgb(255, 255, 255);"> <span style="letter-spacing: 1px;font-size: 15px;"><strong><img width="auto" style="max-width: 677px;box-sizing: border-box;visibility: visible !important;width: 130px !important;" data-ratio="1" data-type="jpeg" data-w="250" src="/upload/7ddc9700032e2c5cee163f1f1a37b46c.jpg" data-s="300,640"></strong></span> </section> <section style="text-align: center;line-height: normal;letter-spacing: 0.54px;font-family: -apple-system-font,BlinkMacSystemFont,&quot;Helvetica Neue&quot;,&quot;PingFang SC&quot;,&quot;Hiragino Sans GB&quot;,&quot;Microsoft YaHei UI&quot;,&quot;Microsoft YaHei&quot;,Arial,sans-serif;white-space: normal;background-color: rgb(255, 255, 255);"> <span style="letter-spacing: 1px;font-size: 12px;"><strong><strong>架构师之路</strong>-分享架构思路</strong></span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">码字不易,<strong>转发,点赞,再看</strong>三连,谢谢。</span> </section>

8.6M超轻量中英文OCR模型开源,训练部署一条龙

作者:微信小助手

<section style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;text-align: left;margin-left: 8px;margin-right: 8px;margin-top: 20px !important;margin-bottom: 20px !important;letter-spacing: 1px !important;word-spacing: 1px !important;line-height: 1.7 !important;" data-mpa-powered-by="yiban.io"> <span style="font-size: 15px;"><img src="/upload/f1fa30da07c074053c07cfdbc381a319.gif" data-type="gif" data-ratio="0.40062597809076683" data-w="639"></span> </section> <section style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;text-align: left;margin-left: 8px;margin-right: 8px;margin-top: 20px !important;margin-bottom: 20px !important;letter-spacing: 1px !important;word-spacing: 1px !important;line-height: 1.7 !important;"> <span style="font-size: 15px;">要说生活里最常见、最便民的AI应用技术,OCR<span style="color: rgb(143, 143, 143);">(光学字符识别)</span>当属其中之一。</span> </section> <section style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;text-align: left;margin-left: 8px;margin-right: 8px;margin-top: 20px !important;margin-bottom: 20px !important;letter-spacing: 1px !important;word-spacing: 1px !important;line-height: 1.7 !important;"> <span style="font-size: 15px;">寻常到日常办理各种业务时的身份证识别,前沿到自动驾驶车辆的路牌识别,都少不了它的加持。</span> </section> <section style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;text-align: left;margin-left: 8px;margin-right: 8px;margin-top: 20px !important;margin-bottom: 20px !important;letter-spacing: 1px !important;word-spacing: 1px !important;line-height: 1.7 !important;"> <span style="font-size: 15px;">作为一名开发者,各种OCR相关的需求自然也少不了:卡证识别、票据识别、汽车场景、教育场景文字识别……</span> </section> <section style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;text-align: left;margin-left: 8px;margin-right: 8px;margin-top: 20px !important;margin-bottom: 20px !important;letter-spacing: 1px !important;word-spacing: 1px !important;line-height: 1.7 !important;"> <span style="font-size: 15px;">那么,这个模型大小仅</span> <strong><span style="font-size: 15px;color: rgb(0, 128, 255);">8.6M</span></strong> <span style="font-size: 15px;">,没有GPU也能跑得动,还提供自定义训练到多硬件部署的全套开发套件的</span> <span style="font-size: 15px;color: rgb(0, 128, 255);"><strong>开源</strong></span> <span style="font-size: 15px;">通用OCR项目,了解一下?</span> </section> <section style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;text-align: left;margin-left: 8px;margin-right: 8px;margin-top: 20px !important;margin-bottom: 20px !important;letter-spacing: 1px !important;word-spacing: 1px !important;line-height: 1.7 !important;"> <span style="font-size: 15px;">话不多说,先来看效果。</span> </section> <section style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;margin-left: 8px;margin-right: 8px;line-height: 2em;"> <img class="rich_pages" data-ratio="0.4987951807228916" data-s="300,640" data-type="png" data-w="830" src="/upload/e15226534564f9dfb30cfc3663f4ca56.png" style="box-sizing: border-box !important;width: 677px !important;visibility: visible !important;"> </section> <section style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;text-align: left;margin-left: 8px;margin-right: 8px;margin-top: 20px !important;margin-bottom: 20px !important;letter-spacing: 1px !important;word-spacing: 1px !important;line-height: 1.7 !important;"> <img data-ratio="0.6147540983606558" data-type="jpeg" data-w="976" src="/upload/ce36d6d7bda174b2ed44423f32a445e7.jpg" style="box-sizing: border-box !important;width: 677px !important;visibility: visible !important;"> <span style="font-size: 15px;"><br></span> </section> <section style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;text-align: left;margin-left: 8px;margin-right: 8px;margin-top: 20px !important;margin-bottom: 20px !important;letter-spacing: 1px !important;word-spacing: 1px !important;line-height: 1.7 !important;"> <span style="font-size: 15px;">可以看到,无论文字是横排、还是竖排,这个超轻量模型都有不错的识别效果。</span> </section> <section style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;text-align: left;margin-left: 8px;margin-rig

H5分享截图方案优化

作者:微信小助手

<section style="box-sizing: border-box;margin: 15px 8px;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <span style="font-size: 15px;"><strong><span style="color: rgb(255, 41, 65);">背景</span></strong></span> </section> <section style="box-sizing: border-box;margin: 15px 8px;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <span style="font-size: 15px;">分享是传播活动,吸引用户最重要的一环。现有分享手段多是题目配合单张图片,利用点击的方式跳转到目标页面。在信息越来越丰富的今天,单个题目和图片对用户的吸引力是有限的。而在对推广要求更高的营销场景和裂变过程中,我们往往需要将页面内容一部分作为图片整体分享出去。直接利用手机原生的截屏功能会有几个问题:</span> </section> <ul class="list-paddingleft-2" style="list-style-type: square;margin-left: 8px;margin-right: 8px;"> <li style="font-size: 14px;"><p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"><span style="font-size: 14px;">内容格式无法自定义。</span></p></li> <li style="font-size: 14px;"><p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"><span style="font-size: 14px;">翻页情况无法处理。</span></p></li> <li style="font-size: 14px;"><p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"><span style="font-size: 14px;">视窗区域不可控。</span></p></li> </ul> <section style="box-sizing: border-box;margin: 15px 8px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <span style="font-size: 15px;">本文通过讨论现有截屏的方案和闲鱼内部截屏方案,介绍如何利用web实现移动端高还原度富图文分享。</span> </section> <section style="box-sizing: border-box;margin: 15px 8px;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <span style="font-size: 15px;"><strong><span style="color: rgb(255, 41, 65);">现有方案:Html2Canvas</span></strong></span> </section> <section style="box-sizing: border-box;margin: 15px 8px;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <span style="font-size: 15px;"><strong>介绍</strong></span> </section> <section style="box-sizing: border-box;margin: 15px 8px;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <span style="font-size: 15px;">html2canvas是一种基于canvas,将DOM结构绘制在canvas上面产生图片的第三方库。通过如下的方式可以将对应的DOM结构绘制成图片保存出来。优势在于上手简单,使用方便。</span> </section> <section style="box-sizing: border-box;margin: 15px 8px;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <img data-ratio="0.08283002588438308" src="/upload/18630a2b7f9c853b2b65e96867a7efb2.jpg" data-type="jpeg" data-w="1159" style="box-sizing: border-box;border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"> </section> <section style="box-sizing: border-box;margin: 15px 8px;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <span style="font-size: 15px;"><strong>绘制原理</strong></span> </section> <section style="box-sizing: border-box;margin: 15px 8px;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <span style="font-size: 15px;">原理如下图所示。核心逻辑是克隆对应节点DOM结构,利用parse解析成数据,构建canvas进行内容绘制,返回对应的canvas。</span> </section> <section style="box-sizing: border-box;margin: 15px 8px;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <img data-ratio="0.30649038461538464" src="/upload/a6eb3b549c876970f52152dc9087192.jpg" data-type="jpeg" data-w="832" style="box-sizing: border-box;border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"> </section> <section style="box-sizing: border-box;margin: 15px 8px;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <span style="font-size: 15px;"><strong>实际使用中发现存在如下问题</strong></span> </section> <ul class="list-paddingleft-2" style="list-style-type: square;margin-left: 8px;margin-right: 8px;"> <li style="box-sizing: border-box;"><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);line-height: 22px;font-size: 14px !important;"><strong style="box-sizing: border-box;color: rgb(0, 0, 0);">图片跨域不支持</strong>。生成的图片存在跨域限制问题。</span></p></li> <li style="box-sizing: border-box;"><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);line-height: 22px;font-size: 14px !important;"><strong style="box-sizing: border-box;color: rgb(0, 0, 0);">绘制清晰度低</strong>。即使使用api <code style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, &quot;Microsoft Yahei&quot; !important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span style="box-sizing: border-box;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;line-height: 22px;">scale</span></code>放大后绘制,又会由于生成base64格式图片内容过长导致无法传输。</span></p></li> <li style="box-sizing: border-box;"><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);line-height: 22px;font-size: 14px !important;"><strong style="box-sizing: border-box;color: rgb(0, 0, 0);">圆弧计算精度低</strong>。由于html2canvas是计算像素后绘制到canvas上,而canvas展示又会经过浏览器绘制,导致像素精度降低。</span></p></li> <li style="box-sizing: border-box;"><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);line-height: 22px;font-size: 14px !important;"><strong style="box-sizing: border-box;color: rgb(0, 0, 0);">深度节点出现黑色情况</strong>。由于DOM结构过深,经过像素计算后,会偶尔出现像素丢失情况。</span></p></li> </ul> <section style="margin: 15px 8px;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <span style="font-size: 15px;"><strong><span style="color: rgb(255, 41, 65);">现有方案:SVG</span></strong></span> </section> <section style="margin: 15px 8px;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <span style="font-size: 15px;"><strong><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-align: justify;">介绍</span></strong></span> </section> <h5 style="box-sizing: border-box;margin-top: 1.5rem;margin-bottom: 1rem;color: rgb(21, 153, 87);line-height: 1.35;text-align: start;white-space: normal;font-family: Menlo, Monaco, &quot;Source Code Pro&quot;, Consolas, Inconsolata, &quot;Ubuntu Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Courier New&quot;, &quot;Droid Sans Mono&quot;, &quot;Hiragino Sans GB&quot;, 微软雅黑, monospace !important;"></h5> <section style="box-sizing: border-box;margin: 15px 8px;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <span style="font-size: 15px;">该方案是利用svg可以包裹DOM结构的特性,将对应目标装载进去,之后将svg导出成base64格式的图片。使用方式如下。通过xmlns指定命名空间,防止多集合下元素和属性的冲突。后缀中的 </span> <code style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);line-height: 18px;font-family: consolas, menlo, courier, monospace, &quot;Microsoft Yahei&quot; !important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span style="box-sizing: border-box;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;font-size: 15px;">svg</span></code> <span style="font-size: 15px;">和 </span> <code style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);line-height: 18px;font-family: consolas, menlo, courier, monospace, &quot;Microsoft Yahei&quot; !important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span style="box-sizing: border-box;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;font-size: 15px;">xhtml</span></code> <span style="font-size: 15px;">分别表示解析方式。利用不同的解析方式,实现了svg内部嵌入html的方式。</span> </section> <section style="box-sizing: border-box;margin: 15px 8px;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <img data-ratio="0.48662640207075064" src="/upload/3969466d4e56cc4b02e19cb43d080c99.jpg" data-type="jpeg" data-w="1159" style="box-sizing: border-box;border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"> </section> <section style="box-sizing: border-box;margin: 15px 8px;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <span style="font-size: 15px;">之后只要通过 </span> <code style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);line-height: 18px;font-family: consolas, menlo, courier, monospace, &quot;Microsoft Yahei&quot; !important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span style="box-sizing: border-box;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;font-size: 15px;">encodeURIComponent(svg)</span></code> <span style="font-size: 15px;">将对应的svg转换成base64就可以。优势是容易上手且不依赖第三方库。</span> </section> <section style="margin: 15px 8px;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <span style="font-size: 15px;"><strong>实际使用中发现存在如下问题</strong></span> </section> <ul class="list-paddingleft-2" style="list-style-type: square;margin-left: 8px;margin-right: 8px;"> <li style="box-sizing: border-box;"><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);line-height: 22px;font-size: 14px !important;"><strong style="box-sizing: border-box;color: rgb(0, 0, 0);">SVG无法连接到外部的资源</strong>。比如通过cdn引入的css以及html中的图片连接都会被限制。</span></p></li> <li style="box-sizing: border-box;"><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);line-height: 22px;font-size: 14px !important;"><strong style="box-sizing: border-box;color: rgb(0, 0, 0);">不支持js执行</strong>。现如今SPA页面都需要执行JS后才会渲染对应的DOM节点,而SVG却不支持JS的执行。</span></p></li> <li style="box-sizing: border-box;"><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);line-height: 22px;font-size: 14px !important;"><strong style="box-sizing: border-box;color: rgb(0, 0, 0);">SVG位置和大小不确定</strong>。遇到需要及时展示的情况,需要实时计算位置才行。</span></p></li> </ul> <section style="box-sizing: border-box;margin: 15px 8px;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <span style="font-size: 15px;"><strong><span style="color: rgb(255, 41, 65);">解决方案<br></span></strong></span> </section> <section style="box-sizing: border-box;margin: 15px 8px;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <span style="font-size: 15px;"><strong>思路</strong></span> </section> <section style="box-sizing: border-box;margin: 15px 8px;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <span style="font-size: 15px;">从上面可以看到,现有的两种主流移动端截屏方案都有自己的不足。相比之下,利用canvas绘制的方法更适合SPA应用。那么我们需要解决的是html2canvas对应的几个问题:<strong style="box-sizing: border-box;color: rgb(0, 0, 0);">图片跨域</strong>,<strong style="box-sizing: border-box;color: rgb(0, 0, 0);">清晰度低</strong>,<strong style="box-sizing: border-box;color: rgb(0, 0, 0);">圆弧计算精度差</strong>,<strong style="box-sizing: border-box;color: rgb(0, 0, 0);">深层节点解析</strong>出错。</span> </section> <section style="box-sizing: border-box;margin: 15px 8px;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <span style="font-size: 15px;"><strong>图片跨域</strong></span> </section> <section style="box-sizing: border-box;margin: 15px 8px;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <span style="font-size: 15px;">通过 </span> <code style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);line-height: 18px;font-family: consolas, menlo, courier, monospace, &quot;Microsoft Yahei&quot; !important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span style="box-sizing: border-box;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;font-size: 15px;">newImage()</span></code> <span style="font-size: 15px;">的方式生成图片,在 </span> <code style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);line-height: 18px;font-family: consolas, menlo, courier, monospace, &quot;Microsoft Yahei&quot; !important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span style="box-sizing: border-box;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;font-size: 15px;">image.onload</span></code> <span style="font-size: 15px;">阶段使用canvas绘制图片。此时会产生跨域限制,需要通过 </span> <code style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);line-height: 18px;font-family: consolas, menlo, courier, monospace, &quot;Microsoft Yahei&quot; !important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span style="box-sizing: border-box;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;font-size: 15px;">crossOrigin='Anonymous'</span></code> <span style="font-size: 15px;">设置来解决这个问题。</span> </section> <section style="box-sizing: border-box;margin: 15px 8px;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <img data-ratio="0.42512908777969016" src="/upload/d20bbc2dc811b258328211dfabb290b4.jpg" data-type="jpeg" data-w="1162" style="box-sizing: border-box;border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"> </section> <section style="box-sizing: border-box;margin: 15px 8px;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <span style="font-size: 15px;"><strong>提高清晰度</strong></span> </section> <section style="box-sizing: border-box;margin: 15px 8px;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <span style="font-size: 15px;">在绘制中发现,如果采用宽度375px的canvas将图片导出,会出现图片模糊的情况。一种方案是提高原图片清晰度,但是加载时间会极大延长,用户体验不友好。另一种方式是放大canvas,利用 </span> <code style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);line-height: 18px;font-family: consolas, menlo, courier, monospace, &quot;Microsoft Yahei&quot; !important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span style="box-sizing: border-box;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;font-size: 15px;">drawImage</span></code> <span style="font-size: 15px;">中的参数控制图片坐标和canvas中的绘制坐标。</span> <code style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);line-height: 18px;font-family: consolas, menlo, courier, monospace, &quot;Microsoft Yahei&quot; !important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span style="box-sizing: border-box;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;font-size: 15px;">drawImage</span></code> <span style="font-size: 15px;">中包含几个参数:控制图片的sx, sy, sWidth, sHeight和控制canvas绘制的x, y, width, height。参数具体含义如图中所示。</span> </section> <section style="box-sizing: border-box;margin: 15px 8px;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: center;"> <img data-ratio="0.9666666666666667" src="/upload/a2d46287a1fbc1ca85e6c10eff47985.jpg" data-type="jpeg" data-w="300" style="box-sizing: border-box;border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"> </section> <section style="box-sizing: border-box;margin: 15px 8px;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <span style="font-size: 15px;">将方法中width和height乘上ratio,放大图片,控制绘制坐标,就能在canvas特定位置上绘制出想要的内容。考虑到小canvas在展示阶段清晰度足够,仅保存阶段需要放大三倍绘制的特性,采用第二种方法在几乎没有提高性能开销的前提下,提高清晰度。我们以实际绘制截图来看一下效果。下图左边是一倍结果,右图是三倍结果。</span> </section> <section style="box-sizing: border-box;margin: 15px 8px;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <img data-ratio="0.6306497175141242" src="/upload/8b0202b7b6689ac5fdaea3de248d0603.jpg" data-type="jpeg" data-w="1416" style="box-sizing: border-box;border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"> </section> <section style="box-sizing: border-box;margin: 15px 8px;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <span style="font-size: 15px;"><strong><span style="color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;white-space: pre-line;">圆弧精度低和深层DOM解析</span></strong></span> </section> <section style="box-sizing: border-box;margin: 15px 8px;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <span style="font-size: 15px;">圆弧精度低和深层DOM解析出错问题本质上还是由于DOM结构过于复杂,当采用通用方案处理时,难免无法覆盖。考虑到移动端内容有限,结构简单的特点。决定采用<strong style="box-sizing: border-box;color: rgb(0, 0, 0);">特定DOM节点针对性绘制的方案</strong>解决深层DOM解析出错的问题。好处如下:1)方法原子化,维护简单。2)绘制高度自定义化,自由组织界面结构。3)拓展性强。在同事胖仔的帮助下实现特定DOM节点绘制方案。方案构建过程中主要有如下几个难点:<strong style="box-sizing: border-box;color: rgb(0, 0, 0);">圆角矩形</strong>,<strong style="box-sizing: border-box;color: rgb(0, 0, 0);">文字自动换行</strong>。</span> </section> <ul style="padding-left: 40px;list-style-position: initial;list-style-image: initial;color: rgb(80, 97, 109);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;font-size: 16px;text-align: start;white-space: normal;margin-left: 8px;margin-right: 8px;list-style-type: square !important;" class="list-paddingleft-2"> <li style="box-sizing: border-box;"><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);line-height: 22px;font-size: 14px;">圆角矩形:通过截断的方式绘制特定背景的圆角矩形。原理是通过&nbsp;<code style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, &quot;Microsoft Yahei&quot; !important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span style="color: rgb(74, 74, 74);box-sizing: border-box;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;line-height: 22px;">createPattern</span></code>的方式在canvas上获取图片内容,再利用Path的方式,绘制对应的路线,利用&nbsp;<code style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, &quot;Microsoft Yahei&quot; !important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span style="color: rgb(74, 74, 74);box-sizing: border-box;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;line-height: 22px;">canvas.arc</span></code>绘制圆弧部分,利用&nbsp;<code style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, &quot;Microsoft Yahei&quot; !important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span style="color: rgb(74, 74, 74);box-sizing: border-box;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;line-height: 22px;">canvas.lineTo</span></code>绘制直线部分,截取想要的内容,实现圆角矩形。</span></p></li> <ol style="padding-left: 40px;list-style-position: initial;list-style-image: initial;" class="list-paddingleft-2"> <li style="box-sizing: border-box;"><p><span style="font-size: 14px;">图片内容获取。&nbsp;</span><code style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, &quot;Microsoft Yahei&quot; !important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span style="box-sizing: border-box;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;line-height: 22px;font-size: 14px;">context.createPattern(imgUrl,"no-repeat")</span></code></p></li> <li style="box-sizing: border-box;font-size: 14px;"><p><span style="font-size: 14px;">圆角矩形区域绘制&nbsp;</span></p><p style="text-align: center;"><img data-ratio="0.7841451766953199" src="/upload/9bf90e4b6bed3af5cef57ae31b0adb71.jpg" data-type="jpeg" data-w="1047" style="box-sizing: border-box;border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"></p></li> <li style="box-sizing: border-box;font-size: 14px;"><p><span style="font-size: 14px;">绘制内容&nbsp;</span></p><p style="text-align: center;"><img data-ratio="0.2862632084534102" src="/upload/54cd4da844cc438b8f96beb0006ae7c0.jpg" data-type="jpeg" data-w="1041" style="box-sizing: border-box;border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"></p></li> </ol> <li style="box-sizing: border-box;"><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);line-height: 22px;font-size: 14px;">文本自动换行:思路是通过&nbsp;<code style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, &quot;Microsoft Yahei&quot; !important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span style="color: rgb(74, 74, 74);box-sizing: border-box;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;line-height: 22px;">measureText</span></code>获得当前文本宽度,每次添加一个字,比对此时文本宽度和行宽,超过时候绘制当前行,进行换行,y增加行高,重复这个过程。&nbsp;</span><span style="box-sizing: border-box;color: rgb(74, 74, 74);line-height: 22px;font-size: 14px !important;"><img data-ratio="1.0412844036697249" src="/upload/777ac959d42097ac635d497829732024.jpg" data-type="jpeg" data-w="1090" style="box-sizing: border-box;border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"></span></p></li> </ul> <section style="box-sizing: border-box;margin: 15px 8px;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <span style="font-size: 15px;"><strong><span style="color: rgb(255, 41, 65);">效果</span></strong></span> </section> <ul style="padding-left: 40px;list-style-position: initial;list-style-image: initial;color: rgb(80, 97, 109);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;font-size: 16px;text-align: start;white-space: normal;margin-left: 8px;margin-right: 8px;list-style-type: square !important;" class="list-paddingleft-2"> <li style="box-sizing: border-box;"><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);line-height: 22px;font-size: 14px !important;">实现了一套移动端截屏方法。解决了现有第三方库html2canvas绘制清晰度低,圆弧计算精度低,深层DOM解析出错的问题。</span></p></li> <li style="box-sizing: border-box;"><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);line-height: 22px;font-size: 14px !important;">采用原子化实现方法。支持截屏自定义绘制,而不是如html2canvas和svg只能通过复数次绘制不同DOM节点,来拼凑目标的方式。</span></p></li> </ul> <section style="box-sizing: border-box;margin: 15px 8px;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <span style="font-size: 15px;"><strong><span style="color: rgb(255, 41, 65);">总结</span></strong></span> </section> <section style="box-sizing: border-box;margin: 15px 8px;font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"> <span style="font-size: 15px;">在互联网时代,尤其是5G马上要来临的今天。传统的分享模式,标题+单图片,逐渐难以满足越来越丰富的活动宣传要求。而流量的廉价化和短视频火热的时下,富图文传播无疑能传递更多的信息。目前我们已经实现了基本DOM节点绘制方案,并在站内活动中使用富图文分享。相信在不久的将来,我们能够利用移动端截屏分享功能帮助更多闲鱼用户高效率分享内容,让用户乐在闲鱼,玩在闲鱼。</span> </section> <section style="margin-left: 8px;margin-right: 8px;"> <br> </section> <section style="margin-left: 8px;margin-right: 8px;text-align: center;"> <img class="rich_pages" data-ratio="1" data-s="300,640" data-type="png" data-w="1280" src="/upload/4ab2cbd660faa2d7094db05e19b09076.png" style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-align: center;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 400px !important;"> </section>

面试:一个Java字符串到底有多少个字符?

作者:微信小助手

<section style="display: none;" data-tools="新媒体管家" data-label="powered by xmt.cn" data-mpa-powered-by="yiban.io"> <br> </section> <p style="text-align: center;"><span style="font-size: 13px;color: rgb(136, 136, 136);font-family: Georgia, &quot;Times New Roman&quot;, Times, &quot;Songti SC&quot;, serif;letter-spacing: 0.544px;">点击上方蓝色“</span><span style="font-size: 13px;font-family: Georgia, &quot;Times New Roman&quot;, Times, &quot;Songti SC&quot;, serif;letter-spacing: 0.544px;color: rgb(0, 128, 255);">程序猿DD</span><span style="font-size: 13px;color: rgb(136, 136, 136);font-family: Georgia, &quot;Times New Roman&quot;, Times, &quot;Songti SC&quot;, serif;letter-spacing: 0.544px;">”,选择“设为星标”</span><strong style="max-width: 100%;letter-spacing: 0.544px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;font-size: 16px;white-space: pre-line;background-color: rgb(255, 255, 255);text-align: right;box-sizing: border-box !important;overflow-wrap: break-word !important;"></strong></p> <p style="max-width: 100%;min-height: 1em;white-space: normal;text-align: center;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="max-width: 100%;font-size: 13px;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="max-width: 100%;color: rgb(136, 136, 136);font-family: Georgia, &quot;Times New Roman&quot;, Times, &quot;Songti SC&quot;, serif;letter-spacing: 0.544px;overflow-wrap: break-word !important;box-sizing: border-box !important;">回复“</span><span style="max-width: 100%;font-family: Georgia, &quot;Times New Roman&quot;, Times, &quot;Songti SC&quot;, serif;letter-spacing: 0.544px;color: rgb(0, 128, 255);overflow-wrap: break-word !important;box-sizing: border-box !important;">资源</span><span style="max-width: 100%;color: rgb(136, 136, 136);font-family: Georgia, &quot;Times New Roman&quot;, Times, &quot;Songti SC&quot;, serif;letter-spacing: 0.544px;overflow-wrap: break-word !important;box-sizing: border-box !important;">”获取独家整理的学习资料!</span></span></p> <p style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;min-height: 1em;white-space: normal;text-align: center;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="max-width: 100%;color: rgb(136, 136, 136);font-family: Georgia, &quot;Times New Roman&quot;, Times, &quot;Songti SC&quot;, serif;font-size: 14px;letter-spacing: 0.544px;overflow-wrap: break-word !important;box-sizing: border-box !important;"><img data-backh="34" data-backw="540" data-ratio="0.0625" data-s="300,640" data-type="jpeg" data-w="640" width="100%" src="/upload/8c292e55ba5a23cb6ebc11f2a2c4fece.jpg" style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;overflow-wrap: break-word !important;box-sizing: border-box !important;visibility: visible !important;width: 654px !important;"></span></p> <p style="max-width: 100%;min-height: 1em;white-space: normal;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-align: left;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="color: rgb(178, 178, 178);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;font-size: 12px;letter-spacing: 0.544px;white-space: pre-line;">来源 |&nbsp;https://urlify.cn/qYNR3q</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">依照Java的文档, Java中的字符内部是以UTF-16编码方式表示的,最小值是&nbsp;<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">\u0000</code>&nbsp;(<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">0</code>),最大值是<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">\uffff</code>(<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">65535</code>), 也就是一个字符以2个字节来表示,难道Java最多只能表示 65535个字符?</p> <blockquote data-tool="mdnice编辑器" style="margin-top: 20px;margin-bottom: 20px;padding: 10px 10px 10px 20px;border-left-color: rgb(92, 157, 255);color: rgb(106, 115, 125);font-size: 0.9em;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-align: left;white-space: normal;overflow: auto;background: rgb(249, 249, 249);"> <p style="padding-top: 3px;padding-bottom: 3px;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;line-height: 26px;color: rgb(153, 153, 153);"><strong style="color: rgb(14, 136, 235);">char</strong>: The char data type is a single 16-bit Unicode character. It has a minimum value of '\u0000' (or 0) and a maximum value of '\uffff' (or 65,535 inclusive).</p> <p style="padding-top: 3px;padding-bottom: 3px;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;line-height: 26px;color: rgb(153, 153, 153);">from&nbsp;The Java™ Tutorials</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">首先,让我们先看个例子:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-size: 16px;text-align: left;background-color: rgb(255, 255, 255);border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="margin-bottom: -7px;display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/8Jeic82Or04m7eNlWfLSZhiboQ8Ww0CUfEf1e35AAY5xYwsP1hCiaJmzokPwlQ33grLDcRDyFY6E0JXw5La8z08BQ/640?wx_fmt=png&quot;) 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 675px;border-radius: 5px;"></span><code style="padding: 15px 16px 16px;overflow-x: auto;color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(39, 40, 34);border-radius: 5px;"><span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">class</span>&nbsp;<span style="font-weight: bold;color: white;line-height: 26px;">Main</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">static</span>&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">void</span>&nbsp;<span style="color: rgb(166, 226, 46);font-weight: bold;line-height: 26px;">main</span><span style="line-height: 26px;">(String[]&nbsp;args)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;中文常见字</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;s&nbsp;=&nbsp;<span style="color: rgb(166, 226, 46);line-height: 26px;">"你好"</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: rgb(166, 226, 46);line-height: 26px;">"1.&nbsp;string&nbsp;length&nbsp;="</span>&nbsp;+&nbsp;s.length());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: rgb(166, 226, 46);line-height: 26px;">"1.&nbsp;string&nbsp;bytes&nbsp;length&nbsp;="</span>&nbsp;+&nbsp;s.getBytes().length);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: rgb(166, 226, 46);line-height: 26px;">"1.&nbsp;string&nbsp;char&nbsp;length&nbsp;="</span>&nbsp;+&nbsp;s.toCharArray().length);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;emojis</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s&nbsp;=&nbsp;<span style="color: rgb(166, 226, 46);line-height: 26px;">"👦👩"</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: rgb(166, 226, 46);line-height: 26px;">"2.&nbsp;string&nbsp;length&nbsp;="</span>&nbsp;+&nbsp;s.length());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: rgb(166, 226, 46);line-height: 26px;">"2.&nbsp;string&nbsp;bytes&nbsp;length&nbsp;="</span>&nbsp;+&nbsp;s.getBytes().length);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: rgb(166, 226, 46);line-height: 26px;">"2.&nbsp;string&nbsp;char&nbsp;length&nbsp;="</span>&nbsp;+&nbsp;s.toCharArray().length);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;中文生僻字</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s&nbsp;=&nbsp;<span style="color: rgb(166, 226, 46);line-height: 26px;">"𡃁妹"</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: rgb(166, 226, 46);line-height: 26px;">"3.&nbsp;string&nbsp;length&nbsp;="</span>&nbsp;+&nbsp;s.length());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: rgb(166, 226, 46);line-height: 26px;">"3.&nbsp;string&nbsp;bytes&nbsp;length&nbsp;="</span>&nbsp;+&nbsp;s.getBytes().length);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: rgb(166, 226, 46);line-height: 26px;">"3.&nbsp;string&nbsp;char&nbsp;length&nbsp;="</span>&nbsp;+&nbsp;s.toCharArray().length);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println();<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">运行这个程序,你觉得输出结果是什么?</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;"><strong style="color: rgb(14, 136, 235);">输出结果:</strong></p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-size: 16px;text-align: left;background-color: rgb(255, 255, 255);border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="margin-bottom: -7px;display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/8Jeic82Or04m7eNlWfLSZhiboQ8Ww0CUfEf1e35AAY5xYwsP1hCiaJmzokPwlQ33grLDcRDyFY6E0JXw5La8z08BQ/640?wx_fmt=png&quot;) 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 675px;border-radius: 5px;"></span><code style="padding: 15px 16px 16px;overflow-x: auto;color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(39, 40, 34);border-radius: 5px;">1.&nbsp;string&nbsp;length&nbsp;=2<br>1.&nbsp;string&nbsp;bytes&nbsp;length&nbsp;=6<br>1.&nbsp;string&nbsp;char&nbsp;length&nbsp;=2<br>2.&nbsp;string&nbsp;length&nbsp;=4<br>2.&nbsp;string&nbsp;bytes&nbsp;length&nbsp;=8<br>2.&nbsp;string&nbsp;char&nbsp;length&nbsp;=4<br>3.&nbsp;string&nbsp;length&nbsp;=3<br>3.&nbsp;string&nbsp;bytes&nbsp;length&nbsp;=7<br>3.&nbsp;string&nbsp;char&nbsp;length&nbsp;=3<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">我们知道,&nbsp;<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">String.getBytes()</code>如果不指定编码格式,Java会使用操作系统的编码格式得到字节数组,在我的MacOS中,默认使用<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">UTF-8</code>作为字符编码(<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">locale</code>命令可以查看操作系统的编码),所以在我的机器运行,<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">String.getBytes()</code>会返回<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">UTF-8</code>编码的字节数组。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;"><code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">String.length</code>返回<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Unicode code units</code>的长度。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;"><code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">String.toCharArray</code>返回字符数组。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">我们设置的字符串都是两个unicode字符,输出结果:</p> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(0, 0, 0);font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 普通的中文字:字符串的长度是2,每个中文字按 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">UTF-8</code>编码是三个字节,字符数组的长度看起来也没问题 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> emojis字符:我们设置了 <strong style="color: rgb(14, 136, 235);">两个</strong>emojis字符,男女头像。结果字符串的长度是 <strong style="color: rgb(14, 136, 235);">4</strong>,&nbsp; <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">UTF-8</code>编码8个字节,字符数组的长度是 <strong style="color: rgb(14, 136, 235);">4</strong> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 生僻的中文字:我们设置了两个中文字,其中一个是生僻的中文字。结果字符串的长度是 <strong style="color: rgb(14, 136, 235);">3</strong>,&nbsp; <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">UTF-8</code>编码7个字节,字符数组的长度是 <strong style="color: rgb(14, 136, 235);">3</strong> </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">看起来字符串的字符数和我们预期的有点不一样,我们的字符串只有两个unicode字符, 可是输出结果有时候是2,有时候是3, 有时候是4,为什么呢?这还得从Java的历史说起。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">Java最初设计的<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Charactor</code>用两个字节来表示unicode字符,这没有问题, 因为最初unicode中的字符还比较少, Java 1.1之前采用<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Unicode version 1.1.5</code>, JDK 1.1中支持<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Unicode 2.0</code>, JDK 1.1.7支持<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Unicode 2.1</code>, Java SE 1.4 支持&nbsp;<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Unicode 3.0</code>, Java SE 5.0开始支持<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Unicode 4.0</code>。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">直到<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Unicode 3.0</code>, Java用两个字节来表示unicode字符还没有问题,因为<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Unicode 3.0</code>最多49,259个字符, 两个字节可以表示65,535个字符,还足够容的下所有的uicode3.0字符。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">但是<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Unicode 4.0</code>(事实上自Unicode 3.1), 字符集进行很大的扩充,已经达到了96,447个字符,<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Unicode 11.0</code>已经包含137,374个字符。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">在Unicode中,为每一个字符对应一个编码点(一个整数),用 U+紧跟着十六进制数表示。所有字符按照使用上的频繁度划分为 17 个平面(编号为 0-16),即基本的多语言平面和增补平面。基本的多语言平面(英文为 Basic Multilingual Plane,简称 BMP)又称平面 0,收集了使用最广泛的字符。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">这样一来,Java的Charactor的两个字节的设计,已经不足以容纳所有的Unicode 4的字符, 所以可能需要4个字节才能表示扩展字符,所以现在的Charactor代表的已经不再是<strong style="color: rgb(14, 136, 235);">一个字符</strong>&nbsp;(代码点 code point), 而是一个代码单元(code unit)。</p> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(0, 0, 0);font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.95;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;color: rgb(51, 51, 51);"><strong style="color: rgb(14, 136, 235);">Code Point</strong>: 代码点,一个字符的数字表示。一个字符集一般可以用一张或多张由多个行和多个列所构成的二维表来表示。二维表中行与列交叉的点称之为代码点,每个码点分配一个唯一的编号数字,称之为码点值或码点编号,除开某些特殊区域(比如代理区、专用区)的非字符代码点和保留代码点,每个代码点唯一对应于一个字符。从<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">U+0000</code>&nbsp;到&nbsp;<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">U+10FFFF</code>。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.95;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;color: rgb(51, 51, 51);"><strong style="color: rgb(14, 136, 235);">Code Unit</strong>:代码单元,是指一个已编码的文本中具有最短的比特组合的单元。对于 UTF-8 来说,代码单元是 8 比特长;对于 UTF-16 来说,代码单元是 16 比特长。换一种说法就是 UTF-8 的是以一个字节为最小单位的,UTF-16 是以两个字节为最小单位的。</p> </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">Java的字符在内部以UTF-16编码方式来表示,<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">String.length</code>返回的是<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Code Unit</code>的长度,而不再是Unicode中字符的长度。对于传统的<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">BMP</code>平面的代码点,<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">String.length</code>和我们传统理解的字符的数量是一致的,对于扩展的字符,<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">String.length</code>可能是我们理解的字符长度的两倍。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">有可能你会问, 对于一个UTF-16编码的扩展字符,它以4个字节来表示,那么前两个字节会不会和<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">BMP</code>平面冲突,导致程序不知道它是扩展字符还是<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">BMP</code>平面的字符?</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">其实是不会的, 幸运的是, 在<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">BMP</code>平面中,&nbsp;<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">U+D800</code>到<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">U+DFFF</code>之间的码位是永久保留不映射到Unicode字符,UTF-16就利用保留下来的0xD800-0xDFFF区块的码位来对辅助平面的字符的码位进行编码。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">UTF-16编码中,辅助平面中的码位从<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">U+10000</code>到<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">U+10FFFF</code>,共计FFFFF个,需要20位来表示。第一个整数(两个字节,称为前导代理)要容纳上述20位的前10位,第二个整数(称为后尾代理)容纳上述20位的后10位。前导代理的值的范围是<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">0xD800</code>到<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">0xDBFF</code>,后尾代理的<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">0xDC00</code>~<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">0xDFFF</code>。可以看到前导代理和后尾代理的范围都落在了<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">BMP</code>平面中不用来映射的码位,所以不会产生冲突,而且前导代理和后尾代理也没有重合。这样我们得到两个字节的,就可以直接判断它是否是<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">BMP</code>平面的字符,还是扩展字符中的前导代理还是后尾代码。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">国外的有些用户用emojis字符做自己的昵称,导致有些系统不能正确的显示出来,这是因为这些系统粗暴的使用<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Charactor</code>来表示,在显示的时候截断的时候有时候可能不是在正确的代码点上进行截断。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">我们在进行字符串截取的时候,比如<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">String.substring</code>有可能会踩到一些坑,尤其经常使用的emojis字符。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">自 Java 1.5 java.lang.String就提供了<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Code Point</code>方法, 用来获取完整的Unicode字符和Unicode字符数量:</p> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(0, 0, 0);font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> public int codePointAt(int index) </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> public int codePointBefore(int index) </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> public int codePointCount(int beginIndex, int endIndex) </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.95;letter-spacing: 0.1em;word-spacing: 0.1em;">注意这些方法中的index使用的是<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">code unit</code>值。</p> <p style="max-width: 100%;min-height: 1em;overflow-wrap: break-word !important;box-sizing: border-box !important;"><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: 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(&quot;https://mmbiz.qpic.cn/mmbiz_png/sUbvrqLicbpzB81mjeBxPuxnYdalGxNnJo30L2Hq3WwGficcq8w5YJkLeXnsNHocN53k55TfN5mBpCdicGRyfDg1g/640?wx_fmt=png&quot;);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="2247497093_1" data-recommend-article-time="1595291460" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/R3InYSAIZkGjvcrUtWN4f6F1pA0VbOQGiawziafmDkgj3EOm6cAAb5iaUOibbEeOZibbribVxicPoOcSCYK9wbdiasaDJw/0?wx_fmt=jpeg" data-recommend-article-title="扬言要干掉 RESTful API 的 GraphQL 是什么鬼?" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&amp;mid=2247497093&amp;idx=1&amp;sn=4e21b75e93f353e91c1f50d5be440e74&amp;chksm=9bd3581daca4d10bc1d82289adb7e2b0a8220b6b549a0e7c71b298a5a2e7969c589da4125311#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&amp;mid=2247497093&amp;idx=1&amp;sn=4e21b75e93f353e91c1f50d5be440e74&amp;chksm=9bd3581daca4d10bc1d82289adb7e2b0a8220b6b549a0e7c71b298a5a2e7969c589da4125311&amp;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="">扬言要干掉 RESTful API 的 GraphQL 是什么鬼?</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247497093_2" data-recommend-article-time="1595291460" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/R3InYSAIZkGjvcrUtWN4f6F1pA0VbOQGJDcnNib1GmyWyKAiaQ2X2Rgd68yem1DDp57EwxqMxUIg8gVrqtSa73ibw/0?wx_fmt=jpeg" data-recommend-article-title="赠书:全球首本VS Code中文书来了,高效编程秘诀全收录!" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&amp;mid=2247497093&amp;idx=2&amp;sn=285b7f7de798b2aeb130097f25fe64af&amp;chksm=9bd3581daca4d10bb18522e8161731b3dbf228286654ef4d3791fea1d9cb2e9ce9cef854e87f#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&amp;mid=2247497093&amp;idx=2&amp;sn=285b7f7de798b2aeb130097f25fe64af&amp;chksm=9bd3581daca4d10bb18522e8161731b3dbf228286654ef4d3791fea1d9cb2e9ce9cef854e87f&amp;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="">赠书:全球首本VS Code中文书来了,高效编程秘诀全收录!</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247497093_3" data-recommend-article-time="1595291460" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/R3InYSAIZkGjvcrUtWN4f6F1pA0VbOQGhwhWciaGNBRLJXstQB1cNlGuMicIXT0tlV5p4NWFpIHaCSZLh4287GNQ/0?wx_fmt=jpeg" data-recommend-article-title="自建分布式存储新选择,性能是Ceph的1.84倍" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&amp;mid=2247497093&amp;idx=3&amp;sn=21b7795125f0ab2bbf5bc6e98509ab1a&amp;chksm=9bd3581daca4d10b811433e1cf1986c71a4680c42710059375f43bc237a8b9496a5fd69b5687#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&amp;mid=2247497093&amp;idx=3&amp;sn=21b7795125f0ab2bbf5bc6e98509ab1a&amp;chksm=9bd3581daca4d10b811433e1cf1986c71a4680c42710059375f43bc237a8b9496a5fd69b5687&amp;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="">自建分布式存储新选择,性能是Ceph的1.84倍</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247497005_2" data-recommend-article-time="1595205060" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/R3InYSAIZkGjvcrUtWN4f6F1pA0VbOQGIEw2rY0dyTAq0dqZS1pD8h3BTKGDQfFgupSVCiaQd2vmWPIgicWF9rGA/0?wx_fmt=jpeg" data-recommend-article-title="项目是如何死掉的?太过真实!" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&amp;mid=2247497005&amp;idx=2&amp;sn=4c505a58d6787c626ca86c154f14c47d&amp;chksm=9bd358b5aca4d1a3fabbce6dd9243e38c3ec8371d3e2e023a9e4fe5078c9f004284812d2b029#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&amp;mid=2247497005&amp;idx=2&amp;sn=4c505a58d6787c626ca86c154f14c47d&amp;chksm=9bd358b5aca4d1a3fabbce6dd9243e38c3ec8371d3e2e023a9e4fe5078c9f004284812d2b029&amp;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="2247496951_1" data-recommend-article-time="1595122260" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/R3InYSAIZkEtoN0MlYqSDoGE0BS5icMxZ5oJx4FZbKfT51rNFpaVCWDqA9KSiab4WuEV7wj2TrvjM4JqawW6niceQ/0?wx_fmt=jpeg" data-recommend-article-title="日志系统新贵Loki,确实比笨重的ELK轻" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&amp;mid=2247496951&amp;idx=1&amp;sn=c3cd2067dd67b140f3cf87564c9565c7&amp;chksm=9bd3596faca4d079bc46507bd8a01635f061bf8c15d37806f1ad369fc04fda3f7b486a76ae1b#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&amp;mid=2247496951&amp;idx=1&amp;sn=c3cd2067dd67b140f3cf87564c9565c7&amp;chksm=9bd3596faca4d079bc46507bd8a01635f061bf8c15d37806f1ad369fc04fda3f7b486a76ae1b&amp;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="">日志系统新贵Loki,确实比笨重的ELK轻</p> </section></a> </section> </section> </section> </section> <p><br></p> <p style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);"><span style="font-size: 14px;color: rgb(62, 62, 62);letter-spacing: 2px;text-align: left;word-spacing: 2px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">欢迎加入我的知识星球,聊技术、说职场、侃社会。</span></p> <section data-mpa-template="t" mpa-paragraph-type="ignored" style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);"> <section style="margin-top: 10px;margin-bottom: 10px;min-height: 1em;color: rgb(62, 62, 62);font-size: 15px;letter-spacing: 2px;word-spacing: 2px;line-height: normal;text-align: left;"> <span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 14px;">头发很多的中年程序员DD和他的朋友们在这里期待你的到来!</span> </section> <p style="margin-top: 1.7em;margin-bottom: 1.7em;color: rgb(62, 62, 62);line-height: inherit;letter-spacing: 2px;word-spacing: 2px;text-align: center;"><span style="font-size: 14px;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">加入方式:</span><strong style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"><span style="color: rgb(255, 76, 0);">长按下方二维码噢</span></strong></span></p> </section> <p style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;"><img data-ratio="0.5453333333333333" data-type="png" data-w="750" src="/upload/f7f418ec5d0483ff3a935bc09553a1ea.png" style="box-sizing: border-box !important;visibility: visible !important;width: 677px !important;"></p> <section style="margin-top: 10px;margin-bottom: 10px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);min-height: 1em;color: rgb(62, 62, 62);letter-spacing: 2px;word-spacing: 2px;line-height: normal;text-align: left;"> <br> </section> <section style="margin-top: 10px;margin-bottom: 10px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);min-height: 1em;letter-spacing: 2px;word-spacing: 2px;line-height: normal;text-align: left;"> <span style="font-size: 14px;"><strong><span style="color: rgb(61, 170, 214);">最近更新:</span></strong></span> </section> <section style="margin-top: 10px;margin-bottom: 10px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);min-height: 1em;letter-spacing: 2px;word-spacing: 2px;line-height: normal;text-align: left;"> <span style="color: rgb(61, 170, 214);font-size: 12px;">周三技术人分享:为什么架构师大多是后端?</span> </section> <section style="margin-top: 10px;margin-bottom: 10px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);min-height: 1em;letter-spacing: 2px;word-spacing: 2px;line-height: normal;text-align: left;"> <span style="color: rgb(61, 170, 214);font-size: 12px;">周六社会人分享:民法典:聊聊那些跟房子相关的东西</span> </section> <p style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;"><br></p> <p style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;"><span style="font-size: 14px;">我的星球是否适合你?</span></p> <p style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;"><span style="font-size: 14px;">点击</span><strong><span style="color: rgb(255, 104, 39);font-size: 14px;">阅读原文</span></strong><span style="font-size: 14px;">看看我们都聊过啥?</span></p>

亿级数据从 MySQL 到 Hbase 的三种同步方案与实践

作者:微信小助手

<section style="display: none;" data-tools="新媒体管家" data-label="powered by xmt.cn" data-mpa-powered-by="yiban.io"> <br> </section> <p style="text-align: center;"><span style="font-size: 13px;color: rgb(136, 136, 136);font-family: Georgia, &quot;Times New Roman&quot;, Times, &quot;Songti SC&quot;, serif;letter-spacing: 0.544px;">点击上方蓝色“</span><span style="font-size: 13px;font-family: Georgia, &quot;Times New Roman&quot;, Times, &quot;Songti SC&quot;, serif;letter-spacing: 0.544px;color: rgb(0, 128, 255);">程序猿DD</span><span style="font-size: 13px;color: rgb(136, 136, 136);font-family: Georgia, &quot;Times New Roman&quot;, Times, &quot;Songti SC&quot;, serif;letter-spacing: 0.544px;">”,选择“设为星标”</span><strong style="max-width: 100%;letter-spacing: 0.544px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;font-size: 16px;white-space: pre-line;background-color: rgb(255, 255, 255);text-align: right;box-sizing: border-box !important;overflow-wrap: break-word !important;"></strong></p> <p style="max-width: 100%;min-height: 1em;white-space: normal;text-align: center;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="max-width: 100%;font-size: 13px;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="max-width: 100%;color: rgb(136, 136, 136);font-family: Georgia, &quot;Times New Roman&quot;, Times, &quot;Songti SC&quot;, serif;letter-spacing: 0.544px;overflow-wrap: break-word !important;box-sizing: border-box !important;">回复“</span><span style="max-width: 100%;font-family: Georgia, &quot;Times New Roman&quot;, Times, &quot;Songti SC&quot;, serif;letter-spacing: 0.544px;color: rgb(0, 128, 255);overflow-wrap: break-word !important;box-sizing: border-box !important;">资源</span><span style="max-width: 100%;color: rgb(136, 136, 136);font-family: Georgia, &quot;Times New Roman&quot;, Times, &quot;Songti SC&quot;, serif;letter-spacing: 0.544px;overflow-wrap: break-word !important;box-sizing: border-box !important;">”获取独家整理的学习资料!</span></span></p> <p style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;min-height: 1em;white-space: normal;text-align: center;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="max-width: 100%;color: rgb(136, 136, 136);font-family: Georgia, &quot;Times New Roman&quot;, Times, &quot;Songti SC&quot;, serif;font-size: 14px;letter-spacing: 0.544px;overflow-wrap: break-word !important;box-sizing: border-box !important;"><img data-backh="34" data-backw="540" data-ratio="0.0625" data-s="300,640" data-type="jpeg" data-w="640" width="100%" src="/upload/8c292e55ba5a23cb6ebc11f2a2c4fece.jpg" style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;overflow-wrap: break-word !important;box-sizing: border-box !important;visibility: visible !important;width: 654px !important;"></span></p> <section style="margin-bottom: 25px;color: rgb(62, 62, 62);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;"> <strong><span style="font-size: 18px;">1.导语</span></strong> </section> <section style="color: rgb(62, 62, 62);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">大家好,我是光城,下面是我之前在gitchat上发布的一个资料,今天全部开源!</span> <span style="font-size: 15px;letter-spacing: 1px;">源码全部存放在本人github仓库,地址:</span> <span style="font-size: 15px;letter-spacing: 1px;"><strong>https://github.com/Light-City/dbSyncScheme</strong></span> <span style="font-size: 15px;letter-spacing: 1px;">,<strong>欢迎大家提issue与star!</strong><strong>接下来进入本节chat内容!PPT点击阅读原文可直达。</strong></span> </section> <section style="margin-top: 15px;margin-bottom: 15px;color: rgb(62, 62, 62);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">本节亿级数据从 MySQL 到 Hbase 的三种同步方案与实践将主要围绕下面架构图中的三种方法进行实践与讲解。</span> </section> <p style="color: rgb(62, 62, 62);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;"><img data-ratio="1.1949685534591195" data-type="jpeg" data-w="1431" src="/upload/ddf9f39dad64625815abc442aca8d00b.jpg" style="margin: 20px auto;border-radius: 0px 0px 5px 5px;display: block;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;box-sizing: border-box !important;visibility: visible !important;width: 541.448px !important;"></p> <h3 style="color: rgb(62, 62, 62);white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;"><br></h3> <p style="color: rgb(62, 62, 62);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;"><br></p> <h3 style="margin-bottom: 5px;color: rgb(62, 62, 62);white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;"><strong><span style="font-size: 18px;">2.工欲善其事,必先利其器</span></strong></h3> <h3 style="margin-top: 40px;margin-bottom: 20px;font-weight: bold;font-size: 18px;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;color: rgb(14, 136, 235);"><span style="font-size: 17px;">2.1 环境需知</span></h3> <section style="margin-top: 10px;margin-bottom: 15px;color: rgb(62, 62, 62);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">我的实验环境为:</span> <span style="font-size: 15px;letter-spacing: 1px;">Ubuntu16.04+hadoop伪分布式(所以重点会介绍伪分布式环境部署),本节实验可以适用于大部分Linux。</span> </section> <p style="margin-top: 10px;margin-bottom: 25px;color: rgb(62, 62, 62);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;">实验的环境有:</span></p> <ul class="list-paddingleft-2" style="margin-right: 16px;margin-left: 16px;color: rgb(62, 62, 62);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;"> <li> <section style="min-height: 1em;line-height: 2em;"> <span style="font-size: 15px;">MySQL</span> </section></li> <li> <section style="min-height: 1em;line-height: 2em;"> <span style="font-size: 15px;">Hadoop伪分布式/完全分布式</span> </section></li> <li> <section style="min-height: 1em;line-height: 2em;"> <span style="font-size: 15px;">HBase</span> </section></li> <li> <section style="min-height: 1em;line-height: 2em;"> <span style="font-size: 15px;">Phoenix</span> </section></li> <li> <section style="min-height: 1em;line-height: 2em;"> <span style="font-size: 15px;">Zookeeper</span> </section></li> <li> <section style="min-height: 1em;line-height: 2em;"> <span style="font-size: 15px;">Kafka</span> </section></li> <li> <section style="min-height: 1em;line-height: 2em;"> <span style="font-size: 15px;">Maxwell</span> </section></li> <li> <section style="min-height: 1em;line-height: 2em;"> <span style="font-size: 15px;">Flink</span> </section></li> </ul> <section style="margin-top: 15px;margin-bottom: 15px;color: rgb(62, 62, 62);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">所以,本节内容先从以上环境部署讲起,再来逐步分析亿级数据从 MySQL 到 Hbase 的三种同步方案与实践。</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;color: rgb(62, 62, 62);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">注意:</span> <span style="font-size: 15px;letter-spacing: 1px;">本节不会非常深入的去讲解HBase、Phoenix、Kafka、Maxwell、Flink等内容,因为涉及的面非常多,光一个就可以讲很多天了,所以本节将具体的某一块与我们的场景相结合进行阐述,谈谈他们的具体应用与使用,相信大家看完后,对这些会有更加深入的理解!</span> </section> <h3 style="margin-top: 40px;margin-bottom: 20px;font-weight: bold;font-size: 18px;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;color: rgb(14, 136, 235);"><span style="font-size: 17px;">2.2 伪分布式环境部署</span></h3> <h4 style="margin-top: 40px;margin-bottom: 20px;font-weight: bold;font-size: 18px;color: rgb(62, 62, 62);white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;"><span style="font-size: 16px;">2.2.1.准备工作</span></h4> <p style="color: rgb(62, 62, 62);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;">【JAVA】</p> <section style="margin-top: 15px;color: rgb(62, 62, 62);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">Hadoop环境需要JAVA环境,所以首先得安装Java,而Ubuntu默认Java为OpenJdk,需要先卸载,再安装Oracle。</span> <span style="font-size: 15px;letter-spacing: 1px;">除此之外,也可以不用卸载OpenJDK,将Oracle JAVA设为默认的即可。</span> </section> <blockquote style="margin-top: 20px;margin-bottom: 20px;padding-top: 10px;padding-right: 10px;padding-bottom: 10px;border-left-style: none;color: rgb(14, 136, 235);font-size: 0.9em;white-space: normal;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;overflow: auto;line-height: 1.8;border-radius: 0px 0px 10px 10px;background-color: rgb(255, 255, 255);box-shadow: rgb(132, 161, 168) 0px 10px 15px;"> <span style="font-family: Arial, serif;line-height: 1em;font-weight: 700;">★</span> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.2em;word-spacing: 0.1em;line-height: 26px;font-size: 15px;display: inline;">https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html</p> <span style="float: right;font-size: 3em;line-height: 1em;">”</span> </blockquote> <figure style="margin-top: 10px;margin-bottom: 10px;color: rgb(62, 62, 62);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;"> <img data-ratio="0.16149870801033592" data-type="png" data-w="774" src="/upload/165ce1f72efb4577b41abf1ee10a0518.png" style="margin: 20px auto;border-radius: 0px 0px 5px 5px;display: block;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;box-sizing: border-box !important;visibility: visible !important;width: 558.448px !important;"> </figure> <section style="margin-top: 20px;margin-bottom: 20px;color: rgb(62, 62, 62);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;"> <span style="font-size: 15px;">关于java配置只要输入java或者javac看到输出,配置成功。</span> </section> <p style="color: rgb(62, 62, 62);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;"><span style="font-size: 15px;">【<strong>用户</strong>】</span></p> <section style="margin-top: 20px;color: rgb(62, 62, 62);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;"> <span style="font-size: 15px;">在Ubuntu或者类Unix系统中,用户可以通过下列命令添加创建用户:</span> </section> <pre style="margin-top: 10px;margin-bottom: 10px;color: rgb(62, 62, 62);font-size: 16px;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);letter-spacing: 0.544px;text-size-adjust: auto;"><code style="padding: 16px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;overflow-x: auto;color: rgb(56, 58, 66);background-color: rgb(250, 250, 250);display: -webkit-box;"><span style="font-size: 14px;">sudo useradd -s /bin/bash -g hadoop -d /home/hadoop -m hadoop</span><br></code></pre> <section style="margin-top: 20px;margin-bottom: 15px;color: rgb(62, 62, 62);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;"> <span style="font-size: 15px;">如果提示hadoop不再sudoers文件中,执行下列命令:</span> </section> <pre style="margin-top: 10px;margin-bottom: 10px;color: rgb(62, 62, 62);font-size: 16px;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);letter-spacing: 0.544px;text-size-adjust: auto;"><code style="padding: 16px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;overflow-x: auto;color: rgb(56, 58, 66);background-color: rgb(250, 250, 250);display: -webkit-box;"><span style="font-size: 14px;">vi /etc/sudoers</span><br></code></pre> <p style="margin-top: 15px;margin-bottom: 15px;color: rgb(62, 62, 62);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;"><span style="font-size: 15px;">编辑上述文件:</span></p> <pre style="margin-top: 10px;margin-bottom: 10px;color: rgb(62, 62, 62);font-size: 16px;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);letter-spacing: 0.544px;text-size-adjust: auto;"><code style="padding: 16px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;overflow-x: auto;color: rgb(56, 58, 66);background-color: rgb(250, 250, 250);display: -webkit-box;"><span style="line-height: 26px;color: rgb(160, 161, 167);font-style: italic;font-size: 14px;"># User privilege specification</span><br><span style="font-size: 14px;">root ALL=(ALL:ALL) ALL</span><br><span style="font-size: 14px;">hadoop ALL=(ALL:ALL) ALL <span style="line-height: 26px;color: rgb(160, 161, 167);font-style: italic;"># 添加此行</span></span><br></code></pre> <section style="margin-top: 15px;margin-bottom: 15px;color: rgb(62, 62, 62);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">再执行上述命令:</span> </section> <pre style="margin-top: 10px;margin-bottom: 10px;color: rgb(62, 62, 62);font-size: 16px;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);letter-spacing: 0.544px;text-size-adjust: auto;"><code style="padding: 16px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;overflow-x: auto;color: rgb(56, 58, 66);background-color: rgb(250, 250, 250);display: -webkit-box;"><span style="font-size: 14px;">light@city:~$ sudo useradd -s /bin/bash -g hadoop -d /home/hadoop -m hadoop</span><br><span style="font-size: 14px;">useradd:</span><span style="font-size: 14px;">“hadoop”组不存在</span><br></code></pre> <section style="margin-top: 25px;margin-bottom: 15px;color: rgb(62, 62, 62);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;"> <span style="font-size: 15px;">添加用户组:</span> </section> <pre style="margin-top: 10px;margin-bottom: 10px;color: rgb(62, 62, 62);font-size: 16px;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);letter-spacing: 0.544px;text-size-adjust: auto;"><code style="padding: 16px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;overflow-x: auto;color: rgb(56, 58, 66);background-color: rgb(250, 250, 250);display: -webkit-box;"><span style="font-size: 14px;">light@city:/home$ sudo groupadd hadoop</span><br></code></pre> <p style="margin-top: 15px;margin-bottom: 15px;color: rgb(62, 62, 62);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;"><span style="font-size: 15px;">再次执行即可:</span></p> <pre style="margin-top: 10px;margin-bottom: 10px;color: rgb(62, 62, 62);font-size: 16px;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);letter-spacing: 0.544px;text-size-adjust: auto;"><code style="padding: 16px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;overflow-x: auto;color: rgb(56, 58, 66);background-color: rgb(250, 250, 250);display: -webkit-box;"><span style="font-size: 14px;">light@city:~$ sudo useradd -s /bin/bash -g hadoop -d /home/hadoop -m hadoop</span><br></code></pre> <p style="margin-top: 20px;margin-bottom: 15px;color: rgb(62, 62, 62);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;">设置或修改密码:</p> <pre style="margin-top: 10px;margin-bottom: 10px;color: rgb(62, 62, 62);font-size: 16px;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);letter-spacing: 0.544px;text-size-adjust: auto;"><code style="padding: 16px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;overflow-x: auto;color: rgb(56, 58, 66);background-color: rgb(250, 250, 250);display: -webkit-box;"><span style="font-size: 14px;">sudo passwd hadoop</span><br></code></pre> <p style="margin: 10px;padding-top: 8px;padding-bottom: 8px;color: rgb(62, 62, 62);white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-size-adjust: auto;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">【<strong style="color: rgb(14, 136, 235);">SSH</strong>】</p> <p style="margin: 10px;padding-top: 8px;padding-bottom: 8px;color: rgb(62, 62, 62);white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-size-adjust: auto;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">安装ssh</p> <pre style="margin-top: 10px;margin-bottom: 10px;color: rgb(62, 62, 62);font-size: 16px;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);letter-spacing: 0.544px;text-size-adjust: auto;"><code style="padding: 16px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;overflow-x: auto;color: rgb(56, 58, 66);background-color: rgb(250, 250, 250);display: -webkit-box;"><span style="font-size: 14px;">sudo apt-get install openssh-server</span><br></code></pre> <p style="margin: 10px;padding-top: 8px;padding-bottom: 8px;color: rgb(62, 62, 62);white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-size-adjust: auto;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">配置免密登陆</p> <pre style="margin-top: 10px;margin-bottom: 10px;color: rgb(62, 62, 62);font-size: 16px;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);letter-spacing: 0.544px;text-size-adjust: auto;"><code style="padding: 16px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;overflow-x: auto;color: rgb(56, 58, 66);background-color: rgb(250, 250, 250);display: -webkit-box;"><span style="font-size: 14px;">su - hadoop</span><br><span style="font-size: 14px;">ssh-keygen -t rsa</span><br><span style="font-size: 14px;">cat ~/.ssh/id_rsa.pub &gt;&gt; ~/.ssh/authorized_keys</span><br><span style="font-size: 14px;">chmod 0600 ~/.ssh/authorized_keys</span><br><br></code></pre> <p style="margin: 10px;padding-top: 8px;padding-bottom: 8px;color: rgb(62, 62, 62);white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-size-adjust: auto;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">然后输入</p> <pre style="margin-top: 10px;margin-bottom: 10px;color: rgb(62, 62, 62);font-size: 16px;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);letter-spacing: 0.544px;text-size-adjust: auto;"><code style="padding: 16px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;overflow-x: auto;color: rgb(56, 58, 66);background-color: rgb(250, 250, 250);display: -webkit-box;"><span style="font-size: 14px;">ssh localhost</span><br></code></pre> <p style="margin: 10px;padding-top: 8px;padding-bottom: 8px;color: rgb(62, 62, 62);white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-size-adjust: auto;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">此时不需要输入密码,说明成功!</p> <p style="margin: 10px;padding-top: 8px;padding-bottom: 8px;color: rgb(62, 62, 62);white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-size-adjust: auto;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><span style="color: red;">注意:关于ssh免秘登陆失败问题,大家可以通过以下方法进行尝试,大部分问题在于目录及文件权限!</span></p> <pre style="margin-top: 10px;margin-bottom: 10px;color: rgb(62, 62, 62);font-size: 16px;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);letter-spacing: 0.544px;text-size-adjust: auto;"><code style="padding: 16px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;overflow-x: auto;color: rgb(56, 58, 66);background-color: rgb(250, 250, 250);display: -webkit-box;"><span style="font-size: 14px;">sudo chmod 755 <span style="line-height: 26px;color: rgb(152, 104, 1);">$HOME</span></span><br><span style="font-size: 14px;">sudo chmod 600 id_rsa</span><br><span style="font-size: 14px;">sudo chmod 600 id_rsa.pub</span><br><span style="font-size: 14px;">sudo chmod 644 authorized_keys</span><br><br></code></pre> <h4 style="margin-top: 40px;margin-bottom: 20px;font-weight: bold;font-size: 18px;color: rgb(62, 62, 62);white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;"><span style="font-size: 16px;">2.2.2 伪分布式</span></h4> <p style="margin: 10px;padding-top: 8px;padding-bottom: 8px;color: rgb(62, 62, 62);white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-size-adjust: auto;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">【<strong style="color: rgb(14, 136, 235);">Hadoop</strong>】</p> <ul class="list-paddingleft-2" style="color: rgb(62, 62, 62);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;"> <li><p><span style="font-size: 15px;">下载及安装</span></p></li> </ul> <p style="margin: 10px;padding-top: 8px;padding-bottom: 8px;color: rgb(62, 62, 62);white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-size-adjust: auto;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">在下列镜像中下载Hadoop版本,我下载的3.0.2。</p> <blockquote style="margin-top: 20px;margin-bottom: 20px;padding-top: 10px;padding-right: 10px;padding-bottom: 10px;border-left-style: none;color: rgb(14, 136, 235);font-size: 0.9em;white-space: normal;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;overflow: auto;line-height: 1.8;border-radius: 0px 0px 10px 10px;background-color: rgb(255, 255, 255);box-shadow: rgb(132, 161, 168) 0px 10px 15px;"> <span style="font-size: 1.1em;font-family: Arial, serif;line-height: 1em;font-weight: 700;">★</span> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.2em;word-spacing: 0.1em;line-height: 26px;font-size: 15px;display: inline;">https://mirrors.cnnic.cn/apache/hadoop/common/</p> <span style="float: right;font-size: 3em;line-height: 1em;">”</span> </blockquote> <pre style="margin-top: 10px;margin-bottom: 10px;color: rgb(62, 62, 62);font-size: 16px;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);letter-spacing: 0.544px;text-size-adjust: auto;"><code style="padding: 16px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;overflow-x: auto;color: rgb(56, 58, 66);background-color: rgb(250, 250, 250);display: -webkit-box;">wget https://mirrors.cnnic.cn/apache/hadoop/common/hadoop-3.0.2/hadoop-3.0.2.tar.gz<br>tar zxvf hadoop-3.0.2.tar.gz<br>sudo mv hadoop-3.0.2 /usr/<span style="line-height: 26px;color: rgb(193, 132, 1);">local</span>/hadoop<br><br></code></pre> <p style="color: rgb(62, 62, 62);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;"><br></p> <ul class="list-paddingleft-2" style="color: rgb(62, 62, 62);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;"> <li><p>配置</p></li> </ul> <p style="margin: 10px;padding-top: 8px;padding-bottom: 8px;color: rgb(62, 62, 62);white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-size-adjust: auto;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">编辑<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.047);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">etc/hadoop/core-site.xml</code>,<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.047);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">configuration</code>配置为</p> <pre style="margin-top: 10px;margin-bottom: 10px;color: rgb(62, 62, 62);font-size: 16px;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);letter-spacing: 0.544px;text-size-adjust: auto;"><code style="padding: 16px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;overflow-x: auto;color: rgb(56, 58, 66);background-color: rgb(250, 250, 250);display: -webkit-box;"><span style="line-height: 26px;font-size: 14px;">&lt;<span style="line-height: 26px;color: rgb(228, 86, 73);">configuration</span>&gt;</span><br> <span style="line-height: 26px;font-size: 14px;">&lt;<span style="line-height: 26px;color: rgb(228, 86, 73);">property</span>&gt;</span><br> <span style="font-size: 14px;"><span style="line-height: 26px;">&lt;<span style="line-height: 26px;color: rgb(228, 86, 73);">name</span>&gt;</span>fs.defaultFS<span style="line-height: 26px;">&lt;/<span style="line-height: 26px;color: rgb(228, 86, 73);">name</span>&gt;</span></span><br> <span style="font-size: 14px;"><span style="line-height: 26px;">&lt;<span style="line-height: 26px;color: rgb(228, 86, 73);">value</span>&gt;</span>hdfs://localhost:9000<span style="line-height: 26px;">&lt;/<span style="line-height: 26px;color: rgb(228, 86, 73);">value</span>&gt;</span></span><br> <span style="line-height: 26px;font-size: 14px;">&lt;/<span style="line-height: 26px;color: rgb(228, 86, 73);">property</span>&gt;</span><br><span style="line-height: 26px;font-size: 14px;">&lt;/<span style="line-height: 26px;color: rgb(228, 86, 73);">configuration</span>&gt;</span><br><br></code></pre> <section style="margin: 10px;padding-top: 8px;padding-bottom: 8px;color: rgb(62, 62, 62);white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-size-adjust: auto;min-height: 1em;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;line-height: 1.75em;"> <span style="color: red;letter-spacing: 1px;">注意:一定要看本机的9000端口是否被占用,如果被占用了,后面就启动不出来NameNode!</span> </section> <section style="margin: 10px;padding-top: 8px;padding-bottom: 8px;color: rgb(62, 62, 62);white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-size-adjust: auto;min-height: 1em;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;line-height: 1.75em;"> <span style="letter-spacing: 1px;">关于查看本机的9000端口是否被占用:</span> </section> <pre style="margin-top: 10px;margin-bottom: 10px;color: rgb(62, 62, 62);font-size: 16px;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);letter-spacing: 0.544px;text-size-adjust: auto;"><code style="padding: 16px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;overflow-x: auto;color: rgb(56, 58, 66);background-color: rgb(250, 250, 250);display: -webkit-box;"><span style="font-size: 14px;">sudo netstat -alnp | grep 9000</span><br></code></pre> <figure style="margin-top: 10px;margin-bottom: 10px;color: rgb(62, 62, 62);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;"> <img data-ratio="0.045940170940170943" data-type="png" data-w="936" src="/upload/de87c03d4ba7f96afd97b34d7dc5e4f1.png" style="margin: 20px auto;border-radius: 0px 0px 5px 5px;display: block;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;box-sizing: border-box !important;visibility: visible !important;width: 558.448px !important;"> </figure> <p style="margin: 10px;padding-top: 8px;padding-bottom: 8px;color: rgb(62, 62, 62);white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-size-adjust: auto;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">会发现9000端口被php-fpm给占用了,所以这里得修改为其他端口,比如我修改为9012,然后可以再次执行这个命令,会发现没被占用,说明可行!</p> <p style="margin: 10px;padding-top: 8px;padding-bottom: 8px;color: rgb(62, 62, 62);white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-size-adjust: auto;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">编辑<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.047);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">etc/hadoop/hdfs-site.xml</code>,<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.047);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">configuration</code>配置为</p> <pre style="margin-top: 10px;margin-bottom: 10px;color: rgb(62, 62, 62);font-size: 16px;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);letter-spacing: 0.544px;text-size-adjust: auto;"><code style="padding: 16px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;overflow-x: auto;color: rgb(56, 58, 66);background-color: rgb(250, 250, 250);display: -webkit-box;"><span style="line-height: 26px;font-size: 14px;">&lt;<span style="line-height: 26px;color: rgb(228, 86, 73);">configuration</span>&gt;</span><br> <span style="line-height: 26px;font-size: 14px;">&lt;<span style="line-height: 26px;color: rgb(228, 86, 73);">property</span>&gt;</span><br> <span style="font-size: 14px;"><span style="line-height: 26px;">&lt;<span style="line-height: 26px;color: rgb(228, 86, 73);">name</span>&gt;</span>dfs.replication<span style="line-height: 26px;">&lt;/<span style="line-height: 26px;color: rgb(228, 86, 73);">name</span>&gt;</span></span><br> <span style="font-size: 14px;"><span style="line-height: 26px;">&lt;<span style="line-height: 26px;color: rgb(228, 86, 73);">value</span>&gt;</span>1<span style="line-height: 26px;">&lt;/<span style="line-height: 26px;color: rgb(228, 86, 73);">value</span>&gt;</span></span><br> <span style="line-height: 26px;font-size: 14px;">&lt;/<span style="line-height: 26px;color: rgb(228, 86, 73);">property</span>&gt;</span><br><span style="line-height: 26px;font-size: 14px;">&lt;/<span style="line-height: 26px;color: rgb(228, 86, 73);">configuration</span>&gt;</span><br><br></code></pre> <ul class="list-paddingleft-2" style="color: rgb(62, 62, 62);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;"> <li><p>初始化</p></li> </ul> <p style="margin: 10px;padding-top: 8px;padding-bottom: 8px;color: rgb(62, 62, 62);white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-size-adjust: auto;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">格式化HDFS</p> <pre style="margin-top: 10px;margin-bottom: 10px;color: rgb(62, 62, 62);font-size: 16px;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);letter-spacing: 0.544px;text-size-adjust: auto;"><code style="padding: 16px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;overflow-x: auto;color: rgb(56, 58, 66);background-color: rgb(250, 250, 250);display: -webkit-box;"><span style="font-size: 14px;">bin/hdfs namenode -format</span><br></code></pre> <p style="margin: 10px;padding-top: 8px;padding-bottom: 8px;color: rgb(62, 62, 62);white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-size-adjust: auto;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><span style="color: red;">注意:格式化执行一次即可!</span></p> <p style="margin: 10px;pad

如何写出健壮的代码?

作者:微信小助手

<p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.6669921875" data-s="300,640" src="/upload/49fd4b2c6c3569bd5b5809534cc5a644.jpg" data-type="jpeg" data-w="1024" style=""></p> <section powered-by="xiumi.us" style="max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;line-height: 27.2px;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section powered-by="xiumi.us" style="max-width: 100%;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section label="Copyright Reserved by PLAYHUDONG." donone="shifuMouseDownCard('shifu_c_008')" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section powered-by="xiumi.us" style="max-width: 100%;letter-spacing: 0.612px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section label="Copyright Reserved by PLAYHUDONG." donone="shifuMouseDownCard('shifu_c_008')" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section label="Copyright Reserved by PLAYHUDONG." donone="shifuMouseDownCard('shifu_c_008')" style="margin-right: 0em;margin-left: 0em;padding: 0.5em 1em;max-width: 100%;border-style: none;background-color: rgb(245, 245, 245);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="max-width: 100%;min-height: 1em;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(136, 136, 136);font-size: 15px;letter-spacing: 0.612px;box-sizing: border-box !important;overflow-wrap: break-word !important;">阿里妹导读:关于代码的健壮性,其重要性不言而喻</span><span style="letter-spacing: 0.612px;max-width: 100%;color: rgb(136, 136, 136);font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">。那么如何才能写出健壮的代码?</span><span style="letter-spacing: 0.612px;max-width: 100%;color: rgb(136, 136, 136);font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">阿里文娱技术专家长统将</span><span style="max-width: 100%;color: rgb(136, 136, 136);font-size: 15px;letter-spacing: 0.612px;box-sizing: border-box !important;overflow-wrap: break-word !important;">从防御式编程、如何正确使用异常和 DRY 原则等三个方面,并结合代码实例,分享自己的看法心得,希望对同学们有所启发。</span><span style="letter-spacing: 0.612px;"></span></p> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> <section style="max-width: 100%;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">你不可能写出完美的软件。因为它不曾出现,也不会出现。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"> 每一个司机都认为自己是最好的司机,我们在鄙视那些闯红灯、乱停车、胡乱变道不遵守规则的司机同时,更应该在行驶的过程中防卫性的驾驶,小心那些突然冲出来的车辆,在他们给我们造成麻烦的时候避开他。这跟编程有极高的相似性,我们在程序的世界里要不断的跟他人的代码接合(那些不符合你的高标准的代码),并处理可能有效也可能无效的输入。无效的的输入就好像一辆横冲直撞的大卡车,这样的世界防御式编程也是必须的,但要驶得万年船我们可能连自己都不能信任,因为你不知道冲出去的那辆是不是你自己的车。关于这点我们将在防御式编程中讨论。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"> 没人能否认异常处理在 Java 中的重要性,但如果不能正确使用异常处理那么它带来的危害可能比好处更多。我将在正确使用异常中讨论这个问题。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"> DRY,Don't Repeat Yourself. 不要重复你自己。我们都知道重复的危害性,但重复时常还会出现在我们的工作中、代码中、文档中。有时重复感觉上是不得不这么做,有时你并没有意识到是在重复,有时却是因为懒惰而重复。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"> 好借好还再借不难。这句俗话在编程世界中同样也是至理名言。只要在编程,我们都要管理资源:内存、事物、线程、文件、定时器,所有数量有限的事物都称为资源。资源使用一般遵循的模式:你分配、你使用、你回收。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(255, 106, 0);">防御式编程</span></strong> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"> 防御式编程是提高软件质量技术的有益辅助手段。防御式编程的主要思想是:程序/方法不应该因传入错误数据而被破坏,哪怕是其他由自己编写方法和程序产生的错误数据。这种思想是将可能出现的错误造成的影响控制在有限的范围内。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"> 一个好程序,在非法输入的情况下,要么什么都不输出,要么输出错误信息。我们往往会检查每一个外部的输入(一切外部数据输入,包括但不仅限于数据库和配置中心),我们往往也会检查每一个方法的入参。我们一旦发现非法输入,根据防御式编程的思想一开始就不引入错误。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(255, 106, 0);">使用卫语句</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"> 对于非法输入的检查我们通常会使用 </span> <span style="font-size: 15px;background-color: rgb(245, 245, 245);color: rgb(102, 102, 102);">if…else</span> <span style="font-size: 15px;color: rgb(62, 62, 62);"> 去做判断,但往往在判断过程中由于参数对象的层次结构会一层一层展开判断。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <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="java"><code><span class="code-snippet_outer"><span class="code-snippet__function"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">void</span> <span class="code-snippet__title">doSomething</span><span class="code-snippet__params">(DomainA a)</span> </span>{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (a != <span class="code-snippet__keyword">null</span>) {</span></code><code><span class="code-snippet_outer"> assignAction;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (a.getB() != <span class="code-snippet__keyword">null</span>) {</span></code><code><span class="code-snippet_outer"> otherAction;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (a.getB().getC() <span class="code-snippet__keyword">instanceof</span> DomainC) {</span></code><code><span class="code-snippet_outer"> doSomethingB();</span></code><code><span class="code-snippet_outer"> doSomethingA();</span></code><code><span class="code-snippet_outer"> doSomthingC();</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">上边的嵌套判断的代码我相信很多人都见过或者写过,这样做虽然做到了基本的防御式编程,但是也把丑陋引了进来。《Java 开发手册》中建议我们碰到这样的情况使用卫语句的方式处理。什么是卫语句?我们给出个例子来说明什么是卫语句。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="line-height: 1.75em;"> <span style="color: rgb(0, 119, 170);font-family: SFMono-Regular, Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;word-spacing: normal;font-size: 13.6px;text-align: left;"></span> </section> <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="java"><code><span class="code-snippet_outer"><span class="code-snippet__function"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">void</span> <span class="code-snippet__title">doSomething</span><span class="code-snippet__params">(DomainA a)</span> </span>{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (a == <span class="code-snippet__keyword">null</span>) {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> ; <span class="code-snippet__comment">//log some errorA</span></span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (a.getB() == <span class="code-snippet__keyword">null</span>) {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> ; <span class="code-snippet__comment">//log some errorB</span></span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (!(a.getB().getC <span class="code-snippet__keyword">instanceof</span> DomainC)) {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> ;<span class="code-snippet__comment">//log some errorC</span></span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> assignAction;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__function">otherAction;</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet_outer"> <span class="code-snippet__title">doSomethingA</span><span class="code-snippet__params">()</span></span>;</span></code><code><span c