作者:じ☆ve宝贝
#### 同一个tomcat配置不同域名访问不同项目 修改tomcat目录中conf/server.xml文件 ``` <Host name="fentiao.studyjava.cn" appBase="/data/tomcatbbs/webapps/fentiao" unpackWARs="true" autoDeploy="true"> <Context path="" docBase="/data/tomcatbbs/webapps/fentiao" debug="0" reloadable="true"/> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log." suffix=".txt" pattern="%h %l %u %t "%r" %s %b" /> </Host> <Host name="www.studyjava.cn" appBase="webapps" unpackWARs="true" autoDeploy="true"> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log." suffix=".txt" pattern="%h %l %u %t "%r" %s %b" /> </Host> ``` appBase 可以修改成你的站点位置如:D:/web path是说明虚拟目录的名字,如果你要只输入ip地址就显示主页,则该键值留为空; docBase是虚拟目录的路径,它默认的是$tomcat/webapps/ROOT目录,现在我在webapps目录下建了一个myweb目录,让该目录作为我的默认目录。 debug和reloadable一般都分别设置成0和true。 #### 同一个项目多域名访问 在host标签中添加 ``` <Alias>www.abc.com</Alias> ```
作者:微信小助手
<section class="output_wrapper" style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;"> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">RocketMQ消息处理成功的标志是消费者消费一条消息后向Broker端发送ACK消息并且被Broker处理,如果由于网络等原因导致ACK丢失,则RocketMQ会重新消费该条消息。这里就涉及到了消息幂等的概念。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">首先我们了解一下什么是幂等,以及何为消息幂等。</p> <h4 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.2em;text-align: center;"><span style="font-size: inherit;color: inherit;line-height: inherit;">什么是幂等</span></h4> <hr style="border-style: solid;border-width: 1px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);"> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">百度对 “幂等” 解释如下</p> <blockquote style="line-height: inherit;padding: 15px 15px 15px 1rem;font-size: 0.9em;color: rgb(129, 145, 152);border-left-width: 6px;border-left-color: rgb(220, 230, 240);background: none 0% 0% repeat scroll rgb(242, 247, 251);overflow: auto;overflow-wrap: normal;word-break: normal;"> <p style="font-size: inherit;color: inherit;line-height: inherit;">设f为一由X映射至X的一元运算,则f为幂等的,当对于所有在X内的x,f(f(x)) = f(x).特别的是,恒等函数一定是幂等的,且任一常数函数也都是幂等的。</p> </blockquote> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">这里的关键是 <strong>f(f(x)) = f(x)</strong>, 翻译成通俗的解释就是:<br>如果有一个操作,多次执行与一次执行所产生的影响是相同的,我们就称这个操作是幂等的。</p> <h4 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.2em;text-align: center;"><span style="font-size: inherit;color: inherit;line-height: inherit;">关于消息幂等</span></h4> <hr style="border-style: solid;border-width: 1px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);"> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">基于上述的概念,结合消息消费的场景,我们能够很容易的总结出消息幂等的概念:<br></p> <blockquote style="line-height: inherit;padding: 15px 15px 15px 1rem;font-size: 0.9em;color: rgb(129, 145, 152);border-left-width: 6px;border-left-color: rgb(220, 230, 240);background: none 0% 0% repeat scroll rgb(242, 247, 251);overflow: auto;overflow-wrap: normal;word-break: normal;"> <p style="font-size: inherit;color: inherit;line-height: inherit;">如果消息重试多次,消费者端对该重复消息消费多次与消费一次的结果是相同的,并且多次消费没有对系统产生副作用,那么我们就称这个过程是消息幂等的。</p> </blockquote> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">例如:<br>支付场景下,消费者消费扣款消息,对一笔订单进行扣款操作,该扣款操作需要扣除10元。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">这个扣款操作重复多次与执行一次的效果相同,只进行一次真实扣款,用户的扣款记录中对应该笔订单的只有一条扣款流水。不会多扣。那么我们就说这个扣款操作是符合要求的,这个消费过程是消息幂等的。</p> <h4 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.2em;text-align: center;"><span style="font-size: inherit;color: inherit;line-height: inherit;">需要进行消息幂等的场景</span></h4> <hr style="border-style: solid;border-width: 1px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);"> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">首先我们回顾一下需要进行消息幂等的场景,也就是上一篇文章提到的消息重复的场景。<br></p> <ol style="" class=" list-paddingleft-2"> <li><p>发送时重复:<br>生产者发送消息时,消息成功投递到broker,但此时发生网络闪断或者生产者down掉,导致broker发送ACK失败。此时生产者由于未能收到消息发送响应,认为发送失败,因此尝试重新发送消息到broker。当消息发送成功后,在broker中就会存在两条相同内容的消息,最终消费者会拉取到两条内容一样并且Message ID也相同的消息。因此造成了消息的重复。</p></li> <li><p>消费时重复:<br>消费消息时同样会出现重复消费的情况。当消费者在处理业务完成返回消费状态给broker时,由于网络闪断等异常情况导致未能将消费完成的CONSUME_SUCCESS状态返回给broker。broker为了保证消息被至少消费一次的语义,会在网络环境恢复之后再次投递该条被处理的消息,最终造成消费者多次收到内容一样并且Message ID也相同的消息,造成了消息的重复。</p></li> </ol> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">可以看到,无论是发送时重复还是消费时重复,最终的效果均为消费者消费时收到了重复的消息,那么我们就知道:只需要在消费者端统一进行幂等处理就能够实现消息幂等。</p> <h4 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.2em;text-align: center;"><span style="font-size: inherit;color: inherit;line-height: inherit;">实现消息幂等</span></h4> <hr style="border-style: solid;border-width: 1px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);"> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">那么如何才能实现消息幂等呢?</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">首先我们要定义消息幂等的两要素:<br></p> <ul style="" class=" list-paddingleft-2"> <li><p><span style="font-size: inherit;color: inherit;line-height: inherit;">幂等令牌</span></p></li> <li><p><span style="font-size: inherit;color: inherit;line-height: inherit;">处理唯一性的确保</span></p></li> </ul> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">我们必须保证存在幂等令牌的情况下保证业务处理结果的唯一性,才认为幂等实现是成功的。<br>接下来分别解释这两个要素</p> <h5 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">幂等令牌</span></h5> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">幂等令牌是生产者和消费者两者中的既定协议,在业务中通常是具备唯一业务标识的字符串,如:下单场景使用订单号、支付场景使用支付流水号等。且一般由生产者端生成并传递给消费者端。</p> <h5 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">处理唯一性的确保</span></h5> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">即服务端应当采用一定的策略保证同一个业务逻辑一定不会重复执行成功多次。如:使用支付宝进行支付,买一个产品支付多次只会成功一笔。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">较为常用的方式是采用缓存去重并且通过对业务标识添加数据库的唯一索引实现幂等。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">具体的思路为:如支付场景下,支付的发起端生成了一个支付流水号,服务端处理该支付请求成功后,数据持久化成功。由于表中对支付流水添加了唯一索引,因此当重复支付时会因为唯一索引的存在报错 <strong>duplicate entry</strong>,服务端的业务逻辑捕获该异常并返回调用侧“重复支付”提示。这样就不会重复扣款。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">在上面场景的基础上,我们还可以引入Redis等缓存组件实现去重:当支付请求打到服务端,首先去缓存进行判断,根据key=“支付流水号”去get存储的值,如果返回为空,表明是首次进行支付操作同时将当前的支付流水号作为key、value可以为任意字符串通过set(key,value,expireTime)存储在redis中。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">当重复的支付请求到来时,尝试进行get(支付流水号)操作,这个操作会命中缓存,因此我们可以认为该请求是重复的支付请求,服务端业务将重复支付的业务提示返回给请求方。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;"><br>由于我们一般都会在缓存使用过程中设置过期时间,缓存可能会失效从而导致请求穿透到持久化存储中(如:MySQL)。因此不能因为引入缓存而放弃使用唯一索引,将二者结合在一起是一个比较好的方案。</p> <h5 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">RocketMQ场景下如何处理消息幂等</span></h5> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">了解了两个要素及典型案例之后,我们回到消息消费的场景。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">作为一款高性能的消息中间件,RocketMQ能够保证消息不丢失但不保证消息不重复。如果在RocketMQ中实现消息去重实际也是可以的,但是考虑到高可用以及高性能的需求,如果做了服务端的消息去重,RocketMQ就需要对消息做额外的rehash、排序等操作,这会花费较大的时间和空间等资源代价,收益并不明显。RocketMQ考虑到正常情况下出现重复消息的概率其实是很小的,因此RocketMQ将消息幂等操作交给了业务方处理。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">实际上上述问题的本质在于:网络调用本身存在不确定性,也就是既不成功也不失败的第三种状态,即所谓的 处理中 状态,因此会有重复的情况发生。这个问题是很多其他的MQ产品同样会遇到的,通常的方法就是要求消费方在消费消息时进行去重,也就是本文我们说的消费幂等性。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">对RocketMQ有一定使用经验的读者可能注意到,每条消息都有一个MessageID,那么我们能否使用该ID作为去重依据,也就是上面提到的幂等令牌呢?</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">答案是否定的,因为MessageID可能出现冲突的情况,因此不建议通过MessageID作为处理依据而应当使用业务唯一标识如:订单号、流水号等作为幂等处理的关键依据。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">上面也提到了,幂等依据应当由消息生产者生成,在发送消息时候,我们能够通过消息的key设置该id,对应的API为 org.apache.rocketmq.common.message.setKeys(String keys) 代码如下:</p> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code class="java language-java hljs" style="margin-right: 2px;margin-left: 2px;line-height: 15px;font-size: 11px;word-spacing: -3px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;padding: 0.5em;color: rgb(51, 51, 51);background: none 0% 0% repeat scroll rgb(248, 248, 248);overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span class="linenum hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(0, 128, 128);padding-right: 20px;word-spacing: 0px;overflow-wrap: inherit !important;word-break: inherit !important;">1</span>Message sendMessage = <span class="hljs-keyword" style="font-size: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">new</span> Message(<br><span class="linenum hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(0, 128, 128);padding-right: 20px;word-spacing: 0px;overflow-wrap: inherit !important;word-break: inherit !important;">2</span> MessageProtocolConst.WALLET_PAY_TOPIC.getTopic(),<br><span class="linenum hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(0, 128, 128);padding-right: 20px;word-spacing: 0px;overflow-wrap: inherit !important;word-break: inherit !important;">3</span> message.getBytes());<br><span class="linenum hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(0, 128, 128);padding-right: 20px;word-spacing: 0px;overflow-wrap: inherit !important;word-break: inherit !important;">4</span><br><span class="linenum hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(0, 128, 128);padding-right: 20px;word-spacing: 0px;overflow-wrap: inherit !important;word-break: inherit !important;">5</span>sendMessage.setKeys(<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(221, 17, 68);overflow-wrap: inherit !important;word-break: inherit !important;">"OD0000000001"</span>);<br></code></pre> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">当消息消费者收到该消息时,根据该消息的key做幂等处理,API为 org.apache.rocketmq.common.message.getKeys() 代码如下:</p> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code class="java language-java hljs" style="margin-right: 2px;margin-left: 2px;line-height: 15px;font-size: 11px;word-spacing: -3px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;padding: 0.5em;color: rgb(51, 51, 51);background: none 0% 0% repeat scroll rgb(248, 248, 248);overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span class="linenum hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(0, 128, 128);padding-right: 20px;word-spacing: 0px;overflow-wrap: inherit !important;word-break: inherit !important;"> 1</span>(msgs, context) -> {<br><span class="linenum hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(0, 128, 128);padding-right: 20px;word-spacing: 0px;overflow-wrap: inherit !important;word-break: inherit !important;"> 2</span> <span class="hljs-keyword" style="font-size: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">try</span> {<br><span class="linenum hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(0, 128, 128);padding-right: 20px;word-spacing: 0px;overflow-wrap: inherit !important;word-break: inherit !important;"> 3</span> <span class="hljs-comment" style="font-size: inherit;line-height: inherit;color: rgb(153, 153, 136);font-style: italic;overflow-wrap: inherit !important;word-break: inherit !important;">// 默认msgs只有一条消息</span><br><span class="linenum hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(0, 128, 128);padding-right: 20px;word-spacing: 0px;overflow-wrap: inherit !important;word-break: inherit !important;"> 4</span> <span class="hljs-keyword" style="font-size: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">for</span> (MessageExt msg : msgs) {<br><span class="linenum hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(0, 128, 128);padding-right: 20px;word-spacing: 0px;overflow-wrap: inherit !important;word-break: inherit !important;"> 5</span> String key = msg.getKeys();<br><span class="linenum hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(0, 128, 128);padding-right: 20px;word-spacing: 0px;overflow-wrap: inherit !important;word-break: inherit !important;"> 6</span> <span class="hljs-keyword" style="font-size: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">return</span> walletCharge(msg);<br><span class="linenum hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(0, 128, 128);padding-right: 20px;word-spacing: 0px;overflow-wrap: inherit !important;word-break: inherit !important;"> 7</span> }<br><span class="linenum hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(0, 128, 128);padding-right: 20px;word-spacing: 0px;overflow-wrap: inherit !important;word-break: inherit !important;"> 8</span> <span class="hljs-keyword" style="font-size: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">return</span> ConsumeConcurrentlyStatus.CONSUME_SUCCESS;<br><span class="linenum hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(0, 128, 128);padding-right: 20px;word-spacing: 0px;overflow-wrap: inherit !important;word-break: inherit !important;"> 9</span> } <span class="hljs-keyword" style="font-size: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">catch</span> (Exception e) {<br><span class="linenum hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(0, 128, 128);padding-right: 20px;word-spacing: 0px;overflow-wrap: inherit !important;word-break: inherit !important;">10</span> LOGGER.error(<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(221, 17, 68);overflow-wrap: inherit !important;word-break: inherit !important;">"钱包扣款消费异常,e={}"</span>, e);<br><span class="linenum hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(0, 128, 128);padding-right: 20px;word-spacing: 0px;overflow-wrap: inherit !important;word-break: inherit !important;">11</span> <span class="hljs-keyword" style="font-size: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">return</span> ConsumeConcurrentlyStatus.RECONSUME_LATER;<br><span class="linenum hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(0, 128, 128);padding-right: 20px;word-spacing: 0px;overflow-wrap: inherit !important;word-break: inherit !important;">12</span> }<br><span class="linenum hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(0, 128, 128);padding-right: 20px;word-spacing: 0px;overflow-wrap: inherit !important;word-break: inherit !important;">13</span>}<br></code></pre> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">消费者通过getKeys()能够读取到生产者设置的幂等依据(如:订单号等),然后业务逻辑围绕该id进行幂等处理即可。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">如果你觉得每次都需要在生产者侧setkey,在消费者侧getkey,有点繁琐。也可以将该幂等依据设置在消息协议中,消费者接收到消息后解析该id进行幂等操作也是可以的。只需要消息的生产者和消费者约定好如何解析id的协议即可。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">具体的幂等逻辑视使用的场景而定,我在这里尝试从我的经验进行一些总结。</p> <h5 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">消费端常见的幂等操作</span></h5> <ol style="" class=" list-paddingleft-2"> <li><p>业务操作之前进行状态查询<br>消费端开始执行业务操作时,通过幂等id首先进行业务状态的查询,如:修改订单状态环节,当订单状态为成功/失败则不需要再进行处理。那么我们只需要在消费逻辑执行之前通过订单号进行订单状态查询,一旦获取到确定的订单状态则对消息进行提交,通知broker消息状态为:ConsumeConcurrentlyStatus.CONSUME_SUCCESS 。</p></li> <li><p>业务操作前进行数据的检索<br>逻辑和第一点相似,即消费之前进行数据的检索,如果能够通过业务唯一id查询到对应的数据则不需要进行再后续的业务逻辑。如:下单环节中,在消费者执行异步下单之前首先通过订单号查询订单是否已经存在,这里可以查库也可以查缓存。如果存在则直接返回消费成功,否则进行下单操作。</p></li> <li><p>唯一性约束保证最后一道防线<br>上述第二点操作并不能保证一定不出现重复的数据,如:并发插入的场景下,如果没有乐观锁、分布式锁作为保证的前提下,很有可能出现数据的重复插入操作,因此我们务必要对幂等id添加唯一性索引,这样就能够保证在并发场景下也能保证数据的唯一性。</p></li> <li><p>引入锁机制<br>上述的第一点中,如果是并发更新的情况,没有使用悲观锁、乐观锁、分布式锁等机制的前提下,进行更新,很可能会出现多次更新导致状态的不准确。如:对订单状态的更新,业务要求订单只能从初始化->处理中,处理中->成功,处理中->失败,不允许跨状态更新。如果没有锁机制,很可能会将初始化的订单更新为成功,成功订单更新为失败等异常的情况。<br>高并发下,建议通过状态机的方式定义好业务状态的变迁,通过乐观锁、分布式锁机制保证多次更新的结果是确定的,悲观锁在并发环境不利于业务吞吐量的提高因此不建议使用。</p></li> <li><p>消息记录表<br>这种方案和业务层做的幂等操作类似,由于我们的消息id是唯一的,可以借助该id进行消息的去重操作,间接实现消费的幂等。</p></li> </ol> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">首先准备一个消息记录表,在消费成功的同时插入一条已经处理成功的消息id记录到该表中,注意一定要 与业务操作处于同一个事物 中,当新的消息到达的时候,根据新消息的id在该表中查询是否已经存在该id,如果存在则表明消息已经被消费过,那么丢弃该消息不再进行业务操作即可。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">肯定还有更多的场景我没有涉及到,这里说到的操作均是互相之间有关联的,将他们配合使用更能够保证消费业务的幂等性。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">不论怎样,请牢记一个原则:<strong>缓存是不可靠的,查询是不可靠的 </strong>。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">在高并发的场景下,一定要通过持久化存储的唯一索引以及引入锁机制作为共同保障数据准确性和完整性的最后一道防线!</p> <h4 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.2em;text-align: center;"><span style="font-size: inherit;color: inherit;line-height: inherit;">总结</span></h4> <hr style="border-style: solid;border-width: 1px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);"> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">本文主要讲解了何为幂等及消息消费场景下如何传递唯一幂等id,并进一步分析了如何保证消息幂等的思路以及总结了常见的消息幂等处理方式。<br></p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">套路是多变的,关键是掌握思路和方法,我们的原则就是 不管执行多少次,业务表现出来的行为是统一的 , 在这个前提下,我们引入了操作前查库、操作前查缓存、乐观锁/分布式锁机制、加入唯一索引等多重防重放策略,通过这些策略的综合作用,最终达到了消息幂等的目的。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">最后有句话分享,有道无术术可求。有术无道止于术。相信聪明的你一定会在技术的道路上结合实际场景将各种技术手段融会贯通,从而走的越来越远。</p> </section> <section class="output_wrapper" style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;"> <blockquote style="line-height: inherit;padding: 15px 15px 15px 1rem;font-size: 0.9em;color: rgb(129, 145, 152);border-left-width: 6px;border-left-color: rgb(220, 230, 240);background: none 0% 0% repeat scroll rgb(242, 247, 251);overflow: auto;overflow-wrap: normal;word-break: normal;"> <p style="font-size: inherit;color: inherit;line-height: inherit;">作者简介:SnoWalker,中间件发烧友,RocketMQ北京社区联合发起人之一,社区布道师。专注于后端分布式领域,对分布式架构、中间件原理、Devops有着较为深刻的认识和丰富的实践经验。 </p> </blockquote> </section> <p><br></p>
作者:じ☆ve宝贝
经常看到网站不显示时间而是显示的是刚刚、5分钟之前、1年以前。今天用js 实现了一下  ``` <html> <head> <title>studyjava测试</title> <script> function formatDateTime(datetime) { var current_date = new Date().getTime(); var _date = datetime.split(" ")[0]; var _time = datetime.split(" ")[1]; var date = new Date(); date.setFullYear(_date.split("-")[0]); date.setMonth(_date.split("-")[1] - 1); date.setDate(_date.split("-")[2]); date.setHours(_time.split(":")[0]); date.setMinutes(_time.split(":")[1]); date.setSeconds(_time.split(":")[2]); var mul = current_date - date.getTime(); var time = parseInt(mul / 1000); if (time < 60) { return "刚刚" } else if (time < 3600) { return parseInt(time / 60) + " 分钟前" } else if (time < 86400) { return parseInt(time / 3600) + " 小时前" } else if (time < 604800) { return parseInt(time / 86400) + " 天前" } else if (time < 2592000) { return parseInt(time / 604800) + " 周前" } else if (time < 31536000) { return parseInt(time / 2592000) + " 个月前" } else { return parseInt(time / 31536000) + " 年前" } return datetime } </script> </head> <body> <script>document.write(formatDateTime('2015-09-19 12:41:19'))</script> </body> </html> ```
作者:じ☆ve宝贝
## 3.单例模式(Singleton) 单例对象(Singleton)是一种常用的设计模式。在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在。这样的模式有几个好处: 1、某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销。 2、省去了new操作符,降低了系统内存的使用频率,减轻GC压力。 3、有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了。(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程。 首先我们写一个简单的单例类: ``` public class Singleton { /* 持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载 */ private static Singleton instance = null; /* 私有构造方法,防止被实例化 */ private Singleton() { } /* 静态工厂方法,创建实例 */ public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } /* 如果该对象被用于序列化,可以保证对象在序列化前后保持一致 */ public Object readResolve() { return instance; } } ``` 这个类可以满足基本要求,但是,像这样毫无线程安全保护的类,如果我们把它放入多线程的环境下,肯定就会出现问题了,如何解决?我们首先会想到对getInstance方法加synchronized关键字,如下: ``` public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } ``` 但是,synchronized关键字锁住的是这个对象,这样的用法,在性能上会有所下降,因为每次调用getInstance(),都要对对象上锁,事实上,只有在第一次创建对象的时候需要加锁,之后就不需要了,所以,这个地方需要改进。我们改成下面这个: ``` public static Singleton getInstance() { if (instance == null) { synchronized (instance) { if (instance == null) { instance = new Singleton(); } } } return instance; } ``` 似乎解决了之前提到的问题,将synchronized关键字加在了内部,也就是说当调用的时候是不需要加锁的,只有在instance为null,并创建对象的时候才需要加锁,性能有一定的提升。但是,这样的情况,还是有可能有问题的,看下面的情况:在Java指令中创建对象和赋值操作是分开进行的,也就是说instance = new Singleton();语句是分两步执行的。但是JVM并不保证这两个操作的先后顺序,也就是说有可能JVM会为新的Singleton实例分配空间,然后直接赋值给instance成员,然后再去初始化这个Singleton实例。这样就可能出错了,我们以A、B两个线程为例: a>A、B线程同时进入了第一个if判断 b>A首先进入synchronized块,由于instance为null,所以它执行instance = new Singleton(); c>由于JVM内部的优化机制,JVM先画出了一些分配给Singleton实例的空白内存,并赋值给instance成员(注意此时JVM没有开始初始化这个实例),然后A离开了synchronized块。 d>B进入synchronized块,由于instance此时不是null,因此它马上离开了synchronized块并将结果返回给调用该方法的程序。 e>此时B线程打算使用Singleton实例,却发现它没有被初始化,于是错误发生了。 所以程序还是有可能发生错误,其实程序在运行过程是很复杂的,从这点我们就可以看出,尤其是在写多线程环境下的程序更有难度,有挑战性。我们对该程序做进一步优化: ``` private static class SingletonFactory{ private static Singleton instance = new Singleton(); } public static Singleton getInstance(){ return SingletonFactory.instance; } ``` 实际情况是,单例模式使用内部类来维护单例的实现,JVM内部的机制能够保证当一个类被加载的时候,这个类的加载过程是线程互斥的。这样当我们第一次调用getInstance的时候,JVM能够帮我们保证instance只被创建一次,并且会保证把赋值给instance的内存初始化完毕,这样我们就不用担心上面的问题。同时该方法也只会在第一次调用的时候使用互斥机制,这样就解决了低性能问题。这样我们暂时总结一个完美的单例模式: ``` public class Singleton { /* 私有构造方法,防止被实例化 */ private Singleton() { } /* 此处使用一个内部类来维护单例 */ private static class SingletonFactory { private static Singleton instance = new Singleton(); } /* 获取实例 */ public static Singleton getInstance() { return SingletonFactory.instance; } /* 如果该对象被用于序列化,可以保证对象在序列化前后保持一致 */ public Object readResolve() { return getInstance(); } } ``` 其实说它完美,也不一定,如果在构造函数中抛出异常,实例将永远得不到创建,也会出错。所以说,十分完美的东西是没有的,我们只能根据实际情况,选择最适合自己应用场景的实现方法。也有人这样实现:因为我们只需要在创建类的时候进行同步,所以只要将创建和getInstance()分开,单独为创建加synchronized关键字,也是可以的: ``` public class SingletonTest { private static SingletonTest instance = null; private SingletonTest() { } private static synchronized void syncInit() { if (instance == null) { instance = new SingletonTest(); } } public static SingletonTest getInstance() { if (instance == null) { syncInit(); } return instance; } } ``` 考虑性能的话,整个程序只需创建一次实例,所以性能也不会有什么影响。 补充:采用"影子实例"的办法为单例对象的属性同步更新,采用"影子实例"的办法具体说,就是在更新属性时,直接生成另一个单例对象实例,这个新生成的单例对象实例将从数据库或文件中读取最新的配置信息;然后将这些配置信息直接赋值给旧单例对象的属性。 ``` public class GlobalConfig { private static GlobalConfig instance = null; private Vector properties = null; private GlobalConfig() { //Load configuration information from DB or file //Set values for properties } private static synchronized void syncInit() { if (instance = null) { instance = new GlobalConfig(); } } public static GlobalConfig getInstance() { if (instance = null) { syncInit(); } return instance; } public Vector getProperties() { return properties; } public void updateProperties() { //Load updated configuration information by new a GlobalConfig object GlobalConfig shadow = new GlobalConfig(); properties = shadow.getProperties(); } } ``` 通过单例模式的学习告诉我们: 1、单例模式理解起来简单,但是具体实现起来还是有一定的难度。 2、synchronized关键字锁定的是对象,在用的时候,一定要在恰当的地方使用(注意需要使用锁的对象和过程,可能有的时候并不是整个对象及整个过程都需要锁)。 到这儿,单例模式基本已经讲完了,结尾处,笔者突然想到另一个问题,就是采用类的静态方法,实现单例模式的效果,也是可行的,此处二者有什么不同? 首先,静态类不能实现接口。(从类的角度说是可以的,但是那样就破坏了静态了。因为接口中不允许有static修饰的方法,所以即使实现了也是非静态的) 其次,单例可以被延迟初始化,静态类一般在第一次加载是初始化。之所以延迟加载,是因为有些类比较庞大,所以延迟加载有助于提升性能。 再次,单例类可以被继承,他的方法可以被覆写。但是静态类内部方法都是static,无法被覆写。 最后一点,单例类比较灵活,毕竟从实现上只是一个普通的Java类,只要满足单例的基本需求,你可以在里面随心所欲的实现一些其它功能,但是静态类不行。从上面这些概括中,基本可以看出二者的区别,但是,从另一方面讲,我们上面最后实现的那个单例模式,内部就是用一个静态类来实现的,所以,二者有很大的关联,只是我们考虑问题的层面不同罢了。两种思想的结合,才能造就出完美的解决方案,就像HashMap采用数组+链表来实现一样,其实生活中很多事情都是这样,单用不同的方法来处理问题,总是有优点也有缺点,最完美的方法是,结合各个方法的优点,才能最好的解决问题!
作者:微信小助手
<section style="box-sizing: border-box;font-size: 16px;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section style="padding-top: 10px;padding-right: 10px;padding-left: 10px;box-sizing: border-box;background-color: rgb(239, 239, 239);"> <span style="display: inline-block;width: 5%;line-height: 0.8;font-weight: bolder;font-size: 48px;box-sizing: border-box;"> <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;">小史是一个应届生,虽然学的是电子专业,但是自己业余时间看了很多互联网与编程方面的书,一心想进 BAT 互联网公司。</span></p> </section> <section style="clear: both;box-sizing: border-box;"></section> </section> </section> </section> </section> <p style="line-height: 1.75em;"><br></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="0.49933598937583" data-s="300,640" src="/upload/ebb3d6435d062195338027a1f83a7476.png" data-type="png" data-w="753" style=""></p> <p 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;">话说两个多月前,小史通过了 A 厂的一面,两个多月后的今天,小史终于等到了 A 厂的二面。</span></p> <p style="line-height: normal;text-align: center;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="0.5628517823639775" data-s="300,640" data-type="jpeg" data-w="533" src="/upload/a3b19de58c850e95be75a656a16b68bc.jpg" style="line-height: 29.75px;text-align: center;white-space: normal;box-sizing: border-box !important;word-wrap: break-word !important;width: 533px !important;visibility: visible !important;"></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> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;"> <section style="display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">面试现场</p> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0120481927710843" data-s="300,640" data-type="jpeg" data-w="498" src="/upload/3c192336b4c03d1cfe700c31b0b1dec5.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 498px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="1.0260869565217392" data-s="300,640" data-type="jpeg" data-w="460" src="/upload/73bbdf2d956bc82e773aa7c11c146bd6.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 460px !important;visibility: visible !important;"></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><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;">没问题,这个项目前端用的 React+Webpack,后端用的 Nginx+Spring Boot+Redis+MySQL,前后端是分离的,最后用 Docker 进行容器化部署。主要模块有师生系统、课程系统、成绩系统、选课系统等。</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0120481927710843" data-s="300,640" data-type="jpeg" data-w="498" src="/upload/5f1e9bb8728cf7157a1be9b95c342115.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 498px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0260869565217392" data-s="300,640" data-type="jpeg" data-w="460" src="/upload/22f1767d9b631c0688dfd122d50b74.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 460px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0120481927710843" data-s="300,640" data-type="jpeg" data-w="498" src="/upload/ceba1e0099f9ae18d261ce38dd0678f8.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 498px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0260869565217392" data-s="300,640" data-type="jpeg" data-w="460" src="/upload/41a62f4d6b144f4aedfb5bea92121637.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 460px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="1.6910377358490567" data-s="300,640" data-type="jpeg" data-w="424" src="/upload/b744d5e10adfd688b03955cd464650d3.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 424px !important;visibility: visible !important;"></p> <p 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></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="1.0260869565217392" data-s="300,640" data-type="jpeg" data-w="460" src="/upload/aa37fbaa2bbc3c94df509020247b2111.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 460px !important;visibility: visible !important;"></p> <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;">底层 MySQL 是存储,Redis 是缓存,Dao 层操作 MySQL,Cache层操作 Redis,Service 层处理业务逻辑,Rest API 层为前端提供 Rest 接口。</span></p> <p style="line-height: normal;"><br></p> <p 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;">前端这边用 React 进行模块化,Webpack 打包部署。网关 Nginx 进行负载均衡。MySQL、Redis、Nginx 和 Spring Boot 应用都放在 Docker 里部署。</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0120481927710843" data-s="300,640" data-type="jpeg" data-w="498" src="/upload/8b94f90c8368a0bc2a8c9218b2e7288c.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 498px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0260869565217392" data-s="300,640" data-type="jpeg" data-w="460" src="/upload/2c857146001d6ddd0e7bfa09fe698685.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 460px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0120481927710843" data-s="300,640" data-type="jpeg" data-w="498" src="/upload/82e02b1abf92d24c1f60908b4b3f1cbb.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 498px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0260869565217392" data-s="300,640" data-type="jpeg" data-w="460" src="/upload/e5a595fa9ac59780857930259dcfe8df.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 460px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0120481927710843" data-s="300,640" data-type="jpeg" data-w="498" src="/upload/f84411840452d0c6d29f515757c11543.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 498px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0120481927710843" data-s="300,640" data-type="jpeg" data-w="498" src="/upload/2ec77793e794cf0bd58f0532aede3a47.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 498px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0260869565217392" data-s="300,640" data-type="jpeg" data-w="460" src="/upload/a5e4340a46164cedbd1513261036a9c7.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 460px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0120481927710843" data-s="300,640" data-type="jpeg" data-w="498" src="/upload/9624094a94513dc16a1bc9f4157aa7f4.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 498px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0260869565217392" data-s="300,640" data-type="jpeg" data-w="460" src="/upload/f4b1dd2582f87c236ab6b542a87cb928.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 460px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0120481927710843" data-s="300,640" data-type="jpeg" data-w="498" src="/upload/4f4a2826f338cd0ec0e45051aa892d1.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 498px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0260869565217392" data-s="300,640" data-type="jpeg" data-w="460" src="/upload/6b26a6b50c740cd13d7e795fbc49c8e4.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 460px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0120481927710843" data-s="300,640" data-type="jpeg" data-w="498" src="/upload/844d42d8e71eb161b4341db7bda00bd6.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 498px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0260869565217392" data-s="300,640" data-type="jpeg" data-w="460" src="/upload/2529c919e341f39da0a384b68ceafef9.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 460px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="1.0120481927710843" data-s="300,640" data-type="jpeg" data-w="498" src="/upload/f70380eea182270e5a0ca5791e8763d3.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 498px !important;visibility: visible !important;"></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><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;">为什么 MySQL 数据库要用 B+ 树存储索引?</span><span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 1px;line-height: 1.75em;">小史听到这个题目,陷入了回忆。</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="0.396" data-s="300,640" data-type="jpeg" data-w="500" src="/upload/79cd9333a0ee2333b694b003c501a292.jpg" style="line-height: 29.75px;text-align: center;white-space: normal;box-sizing: border-box !important;word-wrap: break-word !important;width: 500px !important;visibility: visible !important;"></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;"> <section style="display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">前段时间的饭局</p> </section> </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;margin-bottom: 5px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">话说吕老师给小史讲完人工智能的一些知识后,他们一起回家吃小史姐姐做的饭去了。</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0599078341013826" data-s="300,640" data-type="jpeg" data-w="434" src="/upload/612d7ad2c296efc375607b81fb392619.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 434px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="1.0599078341013826" data-s="300,640" data-type="jpeg" data-w="434" src="/upload/21d5c55b663f3d18b0f37eac11c9ef42.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 434px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0599078341013826" data-s="300,640" data-type="jpeg" data-w="434" src="/upload/153dfc323edc8bf50de2b31b7d70c3da.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 434px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="1.0223214285714286" data-s="300,640" data-type="jpeg" data-w="448" src="/upload/1dc56ced33d8f50cda956b4f155baaff.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 448px !important;visibility: visible !important;"></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><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;">面试的时候一定是往深了问,不精通的话容易吃亏。不过面试时一般都是根据项目来问,项目中用到的技术,一定要多看看原理,特别是能和数据结构和算法挂钩的那部分。</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0599078341013826" data-s="300,640" data-type="jpeg" data-w="434" src="/upload/751b52f7e453b744e8bf59d303c0e533.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 434px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0223214285714286" data-s="300,640" data-type="jpeg" data-w="448" src="/upload/a71a9fb92cba8004bf25afde03cf3336.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 448px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="1.0599078341013826" data-s="300,640" data-type="jpeg" data-w="434" src="/upload/49a69f8d8b0cee5a321d7f9e948be114.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 434px !important;visibility: visible !important;"></p> <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;">树的话,无非就是前中后序遍历、二叉树、二叉搜索树、平衡二叉树,更高级一点的有红黑树、B 树、B+ 树,还有之前你教我的字典树。</span></p> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;"> <section style="display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">红黑树</p> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="1.0223214285714286" data-s="300,640" data-type="jpeg" data-w="448" src="/upload/1733f7f70c345c974c6fb55173cc88aa.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 448px !important;visibility: visible !important;"></p> <p 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></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="1.0599078341013826" data-s="300,640" data-type="jpeg" data-w="434" src="/upload/5ff4edac55c5a80fa0ab87bb2ea3e52.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 434px !important;visibility: visible !important;"></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><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;">红黑树看过很多遍了,但是每次都记不住,它的规则实在是太多了,光定义就有四五条规则,还有插入删除的时候,需要调整树,复杂得很。</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="1.0223214285714286" data-s="300,640" data-type="jpeg" data-w="448" src="/upload/9c1d83cb96f025cc5246521599d00fad.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 448px !important;visibility: visible !important;"></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><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;">小史,问你红黑树,并不是让你背诵它的定义,或者让你手写一个红黑树,而是想问问你它为什么这样设计,它的使用场景有哪些。</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0599078341013826" data-s="300,640" data-type="jpeg" data-w="434" src="/upload/24787e66ecc950dd7ba9e7942ce5906f.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 434px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0223214285714286" data-s="300,640" data-type="jpeg" data-w="448" src="/upload/9889d6b049a349fac7c01c12b224db75.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 448px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0599078341013826" data-s="300,640" data-type="jpeg" data-w="434" src="/upload/493abb80d9d88a920265fda984a436e5.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 434px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0223214285714286" data-s="300,640" data-type="jpeg" data-w="448" src="/upload/b4e7c4e7ba27f53fe252f610de596fe9.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 448px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0599078341013826" data-s="300,640" data-type="jpeg" data-w="434" src="/upload/e4fbb55084cfaf533414d129aa130d92.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 434px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.3608490566037736" data-s="300,640" data-type="jpeg" data-w="424" src="/upload/a26d53fc18d6d66824a55a528b09491e.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 424px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0223214285714286" data-s="300,640" data-type="jpeg" data-w="448" src="/upload/97beb9e9cc056664b5f0e30805242e8d.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 448px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.4203980099502487" data-s="300,640" data-type="jpeg" data-w="402" src="/upload/9fa77ac5f5aed32370e1f76f057c6bbc.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 402px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0599078341013826" data-s="300,640" data-type="jpeg" data-w="434" src="/upload/aabb5cfec32703697cdef3c970c5ac2b.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 434px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0223214285714286" data-s="300,640" data-type="jpeg" data-w="448" src="/upload/4327541e3ff0a1f8499468409cfc0b53.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 448px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.4203980099502487" data-s="300,640" data-type="jpeg" data-w="402" src="/upload/14f0c5f704ded5f1d8ee8d066419114a.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 402px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0223214285714286" data-s="300,640" data-type="jpeg" data-w="448" src="/upload/74d696db322c2ac1f91a883b2996e1db.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 448px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0599078341013826" data-s="300,640" data-type="jpeg" data-w="434" src="/upload/169c8ddfe211a43549cb157c4aadecff.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 434px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0223214285714286" data-s="300,640" data-type="jpeg" data-w="448" src="/upload/a69615d8b6171d85c8fe58e9277a775c.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 448px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="1.0599078341013826" data-s="300,640" data-type="jpeg" data-w="434" src="/upload/b0334032835201d4101ba60ef3fbc44f.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 434px !important;visibility: visible !important;"></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;"> <section style="display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">B 树</p> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0223214285714286" data-s="300,640" data-type="jpeg" data-w="448" src="/upload/92b3493c5443bc7f8276c83bf3f09db9.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 448px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0599078341013826" data-s="300,640" data-type="jpeg" data-w="434" src="/upload/41d50a044a8617a3bcb72e840751890.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 434px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0223214285714286" data-s="300,640" data-type="jpeg" data-w="448" src="/upload/90e91520a2c3820445bb0b2083f107e.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 448px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0599078341013826" data-s="300,640" data-type="jpeg" data-w="434" src="/upload/e44cf1cebbd73f5e2fc8228e22bec3c8.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 434px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0589622641509433" data-s="300,640" data-type="jpeg" data-w="424" src="/upload/8b09be6f3111d20daacda988b55b3c10.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 424px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0223214285714286" data-s="300,640" data-type="jpeg" data-w="448" src="/upload/eb0f9413c79ea05052f64d30548dfe7d.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 448px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0599078341013826" data-s="300,640" data-type="jpeg" data-w="434" src="/upload/d070ff8ad1f1218bf593ff7b31714436.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 434px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0223214285714286" data-s="300,640" data-type="jpeg" data-w="448" src="/upload/bcfcc4881f1c89158c2d8ce2eaa834aa.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 448px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0599078341013826" data-s="300,640" data-type="jpeg" data-w="434" src="/upload/534b1c20d4ed3f6d1bf8323f3c7baab5.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 434px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="0.714622641509434" data-s="300,640" data-type="jpeg" data-w="424" src="/upload/65c2d6f108a2116e5400c7515923ca3d.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 424px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0223214285714286" data-s="300,640" data-type="jpeg" data-w="448" src="/upload/8b6c01d5b40d57669545b94bf973a31e.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 448px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0599078341013826" data-s="300,640" data-type="jpeg" data-w="434" src="/upload/4dabe964d859773d03efe6ea96654107.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 434px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0223214285714286" data-s="300,640" data-type="jpeg" data-w="448" src="/upload/acb6383c0ca3121a2023cc62e60b32f7.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 448px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0599078341013826" data-s="300,640" data-type="jpeg" data-w="434" src="/upload/cfc1085673267726bb422cd98a2e283f.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 434px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0223214285714286" data-s="300,640" data-type="jpeg" data-w="448" src="/upload/7503853f414bc119521ca1aece808c91.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 448px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0599078341013826" data-s="300,640" data-type="jpeg" data-w="434" src="/upload/42b72059a42b6bb1d7de9f502023f86d.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 434px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="1.0223214285714286" data-s="300,640" data-type="jpeg" data-w="448" src="/upload/da52530530cc7a9f3442cfc92cb144cc.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 448px !important;visibility: visible !important;"></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><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;">小史,你要知道,文件系统和数据库的索引都是存在硬盘上的,并且如果数据量大的话,不一定能一次性加载到内存中。</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="1.0599078341013826" data-s="300,640" data-type="jpeg" data-w="434" src="/upload/47ccee7676ee9f1adea716332223f4f.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 434px !important;visibility: visible !important;"></p> <p 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></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0223214285714286" data-s="300,640" data-type="jpeg" data-w="448" src="/upload/543df5592d4218d3765973ac314ef6f5.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 448px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0599078341013826" data-s="300,640" data-type="jpeg" data-w="434" src="/upload/283601167d8b0f7c7a7b2cf7368bd9c.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 434px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="0.714622641509434" data-s="300,640" data-type="jpeg" data-w="424" src="/upload/7f9f61a6889f6917b8adc36672dd6de6.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 424px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0589622641509433" data-s="300,640" data-type="jpeg" data-w="424" src="/upload/a22aced0c1bfecdfdadfcde03f4a7c30.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 424px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0589622641509433" data-s="300,640" data-type="jpeg" data-w="424" src="/upload/7488d93011af263b963787d189decdcb.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 424px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="1.0223214285714286" data-s="300,640" data-type="jpeg" data-w="448" src="/upload/7c00ebb3891f842a2ec3095c8ca778df.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 448px !important;visibility: visible !important;"></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;"> <section style="display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">B+ 树</p> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0599078341013826" data-s="300,640" data-type="jpeg" data-w="434" src="/upload/40b774bd4f4ccddbab3689d6afb168f.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 434px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0589622641509433" data-s="300,640" data-type="jpeg" data-w="424" src="/upload/f5380277d90ecd3e8ae29c07ca8a4fcd.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 424px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0223214285714286" data-s="300,640" data-type="jpeg" data-w="448" src="/upload/abc90a99c1dcb0687b0764368c6a03ef.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 448px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0599078341013826" data-s="300,640" data-type="jpeg" data-w="434" src="/upload/c10cfba2040bfd393c383cb2251acbe3.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 434px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0223214285714286" data-s="300,640" data-type="jpeg" data-w="448" src="/upload/e32b010dce5e75e182cc57e1b1400c99.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 448px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0599078341013826" data-s="300,640" data-type="jpeg" data-w="434" src="/upload/ecbfbbc0bcbcad648df7790e64c7bf2d.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 434px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="1.0223214285714286" data-s="300,640" data-type="jpeg" data-w="448" src="/upload/f204e20fae4a7f60d6665842ac0062b6.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 448px !important;visibility: visible !important;"></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><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;">这也是和业务场景相关的,你想想,数据库中 Select 数据,不一定只选一条,很多时候会选多条,比如按照 ID 排序后选 10 条。</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="1.0599078341013826" data-s="300,640" data-type="jpeg" data-w="434" src="/upload/afccf5de6b70ed25b213fa4a72ce3e01.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 434px !important;visibility: visible !important;"></p> <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;">我明白了,如果是多条的话,B 树需要做局部的中序遍历,可能要跨层访问。</span></p> <p style="line-height: normal;"><br></p> <p 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;">而 B+ 树由于所有数据都在叶子结点,不用跨层,同时由于有链表结构,只需要找到首尾,通过链表就能把所有数据取出来了。</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0589622641509433" data-s="300,640" data-type="jpeg" data-w="424" src="/upload/c953e08fdbf25198e99b1b040096aab3.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 424px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="1.0223214285714286" data-s="300,640" data-type="jpeg" data-w="448" src="/upload/afee43454fc63332b546e827e91a5f8f.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 448px !important;visibility: visible !important;"></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;"> <section style="display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">回到现场</p> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0120481927710843" data-s="300,640" data-type="jpeg" data-w="498" src="/upload/f70380eea182270e5a0ca5791e8763d3.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 498px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="1.0260869565217392" data-s="300,640" data-type="jpeg" data-w="460" src="/upload/98366c02b9be1220fed033345bcbc224.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 460px !important;visibility: visible !important;"></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><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;">这和业务场景有关。如果只选一个数据,那确实是 Hash 更快。但是数据库中经常会选择多条,这时候由于 B+ 树索引有序,并且又有链表相连,它的查询效率比 Hash 就快很多了。</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="1.0260869565217392" data-s="300,640" data-type="jpeg" data-w="460" src="/upload/f27996ef3f34cc72b39eb25f3873e51a.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 460px !important;visibility: visible !important;"></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><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;">而且数据库中的索引一般是在磁盘上,数据量大的情况可能无法一次装入内存,B+ 树的设计可以允许数据分批加载,同时树的高度较低,提高查找效率。</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="1.0120481927710843" data-s="300,640" data-type="jpeg" data-w="498" src="/upload/3e851b7ef557399a4efcc41f53f9d7e2.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 498px !important;visibility: visible !important;"></p> <p 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;">HR 和小史简单地聊了聊基本情况,这次面试就结束了。</span><span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 1px;line-height: 1.75em;">小史走后,面试官在系统中写下了面试评语:</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="0.3755274261603376" data-s="300,640" data-type="jpeg" data-w="474" src="/upload/54890a8d2e3975a46028086b21cf8b54.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 474px !important;visibility: visible !important;"></p> <p 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;">几天后,小史收到了 A 厂的 Offer。</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0599078341013826" data-s="300,640" data-type="jpeg" data-w="434" src="/upload/3e5791751af53192c5dd7ec2a4fb7686.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 434px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="1.0223214285714286" data-s="300,640" data-type="jpeg" data-w="448" src="/upload/47043a6cf1d4b3cb076c182a1622daaf.jpg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 448px !important;visibility: visible !important;"></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;">作者:</span></em></span><span style="color: rgb(89, 89, 89);letter-spacing: 1px;font-size: 14px;"><em>channingbreeze</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;">编辑:陶家龙、孙淑娟</span></em></span><br></p> <p style="line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;"><em>出处:转载自微信公众号:互联网侦察</em></span></p> <p style="text-align: center;"><img class="" data-copyright="0" data-ratio="0.3939393939393939" src="/upload/58a14061a632a0fe87d40beb73c1aa.gif" data-type="gif" data-w="660" style=""></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin-top: 0.5em;margin-bottom: 0.5em;box-sizing: border-box;"> <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> <p style="line-height: 2em;"><a href="http://mp.weixin.qq.com/s?__biz=MjM5ODI5Njc2MA==&mid=2655822247&idx=1&sn=d65f8646120671b654a9e76e8e4589d6&chksm=bd74ec708a0365666477170c2e40d113986d7a04c8cfdd93c0c73c09f07931bb7a9027872e07&scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;text-decoration: none;" data-linktype="2"><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">傻瓜都能看懂,30张图彻底理解红黑树!</span></a><br></p> <p style="line-height: 2em;"><a href="http://mp.weixin.qq.com/s?__biz=MjM5ODI5Njc2MA==&mid=2655819377&idx=1&sn=bdb5a1c1dd757699c1e1b65c35c21d88&chksm=bd74dba68a0352b08f5fd158eaa4e0930c6dced7b8ba53cf2710e3d798fd0adc2cbe5ca62276&scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;text-decoration: none;" data-linktype="2"><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">老司机也必须掌握的MySQL优化指南</span></a><br></p> <p style="line-height: 2em;"><a href="http://mp.weixin.qq.com/s?__biz=MjM5ODI5Njc2MA==&mid=2655822993&idx=1&sn=0a80725aac9e7edc5e2c15db2b7d3583&chksm=bd74e9468a0360501b722a085efa876d017712ad8034e595898656187bc902fba5cc4e8e5cf5&scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;text-decoration: none;" data-linktype="2"><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">漫话:如何给女朋友解释反向代理?</span></a><br></p>
作者:じ☆ve宝贝
如题:网站什么时候支持手机浏览?
作者:不要哭啦
<section class="xmteditor" style="display:none;" data-tools="新媒体管家" data-label="powered by xmt.cn"></section> <section class="xmteditor" style="display:none;" data-tools="新媒体管家" data-label="powered by xmt.cn"></section> <section class="" data-tools="135编辑器" data-id="91525"> <section style="margin: 8px;padding: 10px;max-width: 100%;box-sizing: border-box;word-wrap: break-word !important;line-height: 25.6px;border-radius: 10px;height: auto;box-shadow: rgb(221, 221, 221) 2px 2px 8px;display: -webkit-flex;"> <section style="max-width: 100%;flex: 0 0 2cm;height: 78px;width: 75px;box-sizing: border-box !important;word-wrap: break-word !important;"> <p style="max-width: 100%;min-height: 1em;text-align: center;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-copyright="0" data-cropselx1="0" data-cropselx2="76" data-cropsely1="0" data-cropsely2="76" data-ratio="1" src="/upload/9816e4ca9d7f3628b8e2432c5f8a0fb7.jpg" data-type="jpeg" data-w="400" style="letter-spacing: 0.544px;line-height: 25.6px;text-align: justify;color: rgb(62, 62, 62);border-radius: 3em;height: 76px;box-sizing: border-box !important;word-wrap: break-word !important;visibility: visible !important;width: 76px;"></p> </section> <section style="padding-right: 10px;padding-left: 10px;max-width: 100%;box-sizing: border-box;flex: 1 1 auto;height: 55px;word-wrap: break-word !important;"> <section style="max-width: 100%;line-height: 35px;white-space: nowrap;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="max-width: 100%;font-family: 宋体, SimSun;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;letter-spacing: 0.544px;color: rgb(31, 73, 125);box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="">程序员大咖</strong></span></strong></span> <span style="max-width: 100%;font-family: 黑体, SimHei;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;letter-spacing: 0.544px;color: rgb(31, 73, 125);box-sizing: border-box !important;word-wrap: break-word !important;"></span></strong><strong style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;letter-spacing: 0.544px;color: rgb(31, 73, 125);box-sizing: border-box !important;word-wrap: break-word !important;"></span></strong><strong style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;letter-spacing: 0.544px;color: rgb(31, 73, 125);box-sizing: border-box !important;word-wrap: break-word !important;"></span></strong></span> </section> <section style="max-width: 100%;font-size: 13px;line-height: 20px;color: rgb(127, 127, 127);box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="max-width: 100%;letter-spacing: 0.544px;color: rgb(165, 165, 165);font-family: 黑体, SimHei;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="">点击右侧关注,免费进阶高级!</span></span> </section> </section> <section style="max-width: 100%;flex: 0 0 1.5cm;font-size: 15px;color: rgb(86, 187, 55);letter-spacing: 0px;text-align: center;line-height: 6;box-sizing: border-box !important;word-wrap: break-word !important;"> <section style="margin-top: 25px;max-width: 100px;vertical-align: middle;overflow: hidden;box-sizing: border-box !important;word-wrap: break-word !important;"> <section style="max-width: 100%;width: 55px;height: 30px;box-sizing: border-box !important;word-wrap: break-word !important;background-image: url(https://mmbiz.qpic.cn/mmbiz_gif/S7SAuLQzeTVj0YaoibbZqxicYkQrLnR3WtTQlHpHouqUmibjUCY9F5wpG0DmyMetZy9pjDdiabWo4XXdtCib3VcnI7w/640?wx_fmt=gif);background-size: 100% 100%;background-repeat: no-repeat;"> <section style="max-width: 100%;opacity: 0;box-sizing: border-box !important;word-wrap: break-word !important;"> <a href="https://mp.weixin.qq.com/s?__biz=MzAxMzQ3NzQ3Nw==&mid=2654251628&idx=6&sn=3f3e44c1d450a8953420db746c350403&scene=21#wechat_redirect" target="_blank"><span class="js_jump_icon h5_image_link" data-positionback="static" style="top: auto;left: auto;margin: 0px;right: auto;bottom: auto;"><img class="" data-copyright="0" data-cropselx1="0" data-cropselx2="55" data-cropsely1="0" data-cropsely2="63" data-ratio="1" src="/upload/1f180962c0d23c5df8c05ea79b5fb8f0.jpg" data-type="jpeg" data-w="258" style="margin: 0px;top: auto;left: auto;right: auto;bottom: auto;width: 63px;height: 63px;box-sizing: border-box !important;word-wrap: break-word !important;visibility: visible !important;" title="1081255447.jpg"></span></a> </section> </section> </section> </section> </section> </section> <p><br></p> <p style="white-space: normal;">说起Bug,那可是让程序员又爱又恨的存在,它仿佛无处不在一般,无论多完美的代码,或多或少都是有Bug的,有些Bug能够比较简单的处理掉,程序员就能在解决的过程中学到东西,而有些Bug非常难发现,甚至到了可遇不可求的地步!</p> <p style="white-space: normal;"><br></p> <p style="white-space: normal;"><img class="" data-copyright="0" data-ratio="0.7670886075949367" data-s="300,640" src="/upload/f30536bc0b05cc730ff3460f4af88966.jpg" data-type="jpeg" data-w="395"></p> <p style="white-space: normal;"><img class="" data-copyright="0" data-ratio="0.48826979472140764" data-s="300,640" src="/upload/81085bcda4b0f9766d1072a8987393ba.jpg" data-type="jpeg" data-w="682"></p> <p style="white-space: normal;"><br></p> <p style="white-space: normal;">很多网友也是从来没见过这样的Bug,甚至算不算得上Bug还不好说。</p> <p style="white-space: normal;"><br></p> <p style="white-space: normal;"><img class="" data-copyright="0" data-ratio="1.094949494949495" data-s="300,640" src="/upload/87a955daea2cf33b795d9beeacfe4687.jpg" data-type="jpeg" data-w="495"></p> <p style="white-space: normal;">有网友猜测难道是接了上面的if?可是上面的if已经注释掉了啊,按理说并没有起作用,可是下方竟然没有报错!不得不说实在有一些诡异。还有网友称看不懂这是啥语言,但是感觉这么多条件判断语句感觉很恶心。</p> <p style="white-space: normal;"><br></p> <p style="white-space: normal;"><img class="" data-copyright="0" data-ratio="0.9436619718309859" data-s="300,640" src="/upload/1f404c8d3e58990138a726c82dd16f9a.jpg" data-type="jpeg" data-w="497"></p> <p style="white-space: normal;"><br></p> <p style="white-space: normal;">有网友想不通为什么这样还能编译通过,而且还等了4个月最后才发现这个Bug,不得不说这样的偶然性Bug真的很少见。</p> <p style="white-space: normal;"><br></p> <p style="white-space: normal;">出现这种情况的原因可能就是写代码的习惯问题了,毕竟每个程序员或多或少都有自己的习惯,有些习惯在写if的时候后面马上再接一个else,有一些习惯大小括号要对齐等等,这些都是根据每个人不同而不同的。你认为这个Bug究竟是怎么回事呢?欢迎在评论区留下你的看法!</p> <p><br></p> <p><strong style="font-size: 16px;white-space: normal;font-family: 微软雅黑;letter-spacing: 1px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><a href="https://mp.weixin.qq.com/s?__biz=MzI0NjYxMDQ4OQ==&mid=2247484655&idx=4&sn=b63f0a1e32df2fed7ba7e0f0e838e3f9&scene=21#wechat_redirect" target="_blank"><strong style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(67, 149, 245);outline: none 0px;line-height: normal;text-indent: 2em;top: auto;left: auto;right: auto;bottom: auto;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"><span class="js_jump_icon h5_image_link" data-positionback="static" style="top: auto;left: auto;right: auto;bottom: auto;"><img class="__bg_gif" data-ratio="0.48936170212765956" src="/upload/6f7a0016c2a7d885c35da32a06291359.null" data-type="gif" data-w="47" width="auto" style="border-width: 0px;border-style: initial;border-color: initial;line-height: 38.4384px;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: auto !important;"></span></span><span style="max-width: 100%;color: rgb(255, 41, 65);outline: none 0px;font-size: 20px;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;">【点击成为源码大神】</span></strong></strong></a></strong></strong></p>
作者:微信小助手
<section class="xmteditor" style="display:none;" data-tools="新媒体管家" data-label="powered by xmt.cn"></section> <section class="xmteditor" style="display:none;" data-tools="新媒体管家" data-label="powered by xmt.cn"></section> <section class="" data-tools="135编辑器" data-id="91525"> <section style="margin: 8px;padding: 10px;max-width: 100%;box-sizing: border-box;word-wrap: break-word !important;line-height: 25.6px;border-radius: 10px;height: auto;box-shadow: rgb(221, 221, 221) 2px 2px 8px;display: -webkit-flex;"> <section style="max-width: 100%;flex: 0 0 2cm;height: 78px;width: 75px;box-sizing: border-box !important;word-wrap: break-word !important;"> <p style="max-width: 100%;min-height: 1em;text-align: center;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-copy
作者:微信小助手
<section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">继续解答星球水友提问。<br>===<br>沈老师,我们有个业务,同一个用户在<span style="font-size: 15px;letter-spacing: 1px;">并发</span>“查询,逻辑计算,扣款”的情况下,余额可能出现不一致,请问有什么优化方法么?<br>===<br><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;"> <strong><span style="font-size: 15px;letter-spacing: 1px;">第一步</span></strong> <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;">用户现有余额:<br></span> <em><span style="letter-spacing: 1px;font-size: 12px;">SELECT money FROM t_yue WHERE uid=$uid;</span></em> <span style="font-size: 15px;letter-spacing: 1px;"><br>不妨设查询出来的$old_money=100元。</span> </section> <p><br></p> <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> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">业务逻辑计算</span> <span style="font-size: 15px;letter-spacing: 1px;">,比如:<br>(1)先查询购买商品的价格,例如是80元;<br>(2)再查询产品是否有活动,以及活动折扣,例如是9折;<br>(3)比对余额是否足够,足够时才往下走;</span> </section> <p style="line-height: normal;"><span style="font-size: 12px;"><em><span style="letter-spacing: 1px;">if($old_money> 80*0.9){<br> $new_money=$old_money-80*0.9=28<br>} else {<br> return "Not enough minerals";<br>}</span></em></span><em><span style="font-size: 15px;letter-spacing: 1px;"></span></em></p> <p><br></p> <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> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">修改</span> <span style="font-size: 15px;letter-spacing: 1px;">。<br></span> <span style="letter-spacing: 1px;font-size: 12px;"><em>UPDATE t_yue SET money=$new_money WHERE uid=$uid;</em></span> <span style="font-size: 15px;letter-spacing: 1px;"></span> <br> </section> <p><br></p> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">在并发量低的情况下,这个流程没有任何问题,原有金额100元,购买了80元的九折商品(72元),剩余28元。</span> </section> <p><br></p> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;letter-spacing: 1px;">同一个用户,并发扣款可能出现什么问题?<br></span></strong> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">在分布式环境中,如果并发量很大,这种“查询+修改”的业务有一定概率出现数据不一致。<br><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;">,业务1和业务2并发查询余额,是100元。</span> </section> <section style="line-height: 1.75em;"> <span style="color: rgb(0, 82, 255);"><em><img data-ratio="0.759090909090909" data-s="300,640" src="/upload/ce6f4c62c83d223c40693e8c927adb1e.png" data-type="png" data-w="220"><br></em></span> </section> <p><span style="color: rgb(0, 82, 255);"><em><span style="color: rgb(0, 82, 255);font-size: 15px;letter-spacing: 1px;">画外音:这些并发查询,是在不同的站点实例/服务实例上完成的,进程内互斥锁肯定解决不了。</span></em></span><br><span style="font-size: 15px;letter-spacing: 1px;"></span></p> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><br><strong>步骤二</strong>,业务1和业务2并发进行逻辑计算,算出各自业务的余额,假设业务1算出的余额是28元,业务2算出的余额是38元。</span> </section> <section style="line-height: 1.75em;"> <img data-ratio="0.37438423645320196" data-s="300,640" src="/upload/5cb7233d4dd2532298d828f20c5772ae.png" data-type="png" data-w="203"> <br> </section> <p><br></p> <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;">,业务1对数据库中的余额先进行修改,设置成28元。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">业务2对数据库中的余额后进行修改,设置成38元。</span> </section> <section style="line-height: 1.75em;"> <img data-ratio="0.3722627737226277" data-s="300,640" src="/upload/bf9e10c160b385a3d21b6c3eff8ed17b.png" data-type="png" data-w="411"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">此时异常出现了,原有金额100元,业务1扣除了72元,业务2扣除了62元,最后剩余38元。<br></span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(0, 82, 255);"><em>画外音:</em><em>假设业务1先写回余额,业务2再写回余额。</em></span> </section> <p><br></p> <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;">,例如:在redis/zk里抢到一个key才能继续操作,否则禁止操作。<br><br>这种<strong>悲观锁</strong>方案确实可行,但要引入额外的组件(redis/zk),并且会降低吞吐量。<br><br><strong>对于小概率的不一致,有没有乐观锁的方案呢?</strong></span> </section> <p><br></p> <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;">(1)业务1写回时,旧余额100,这是一个</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">初始状态</span> <span style="font-size: 15px;letter-spacing: 1px;">;新余额28,这是一个</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">结束状态</span> <span style="font-size: 15px;letter-spacing: 1px;">。理论上只有在旧余额为100时,新余额才应该写回成功。<br><br>而业务1并发写回时,旧余额确实是100,理应写回成功。<br><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)业务2写回时,<span style="font-size: 15px;letter-spacing: 1px;">旧余额100,这是一个</span></span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">初始状态</span> <span style="font-size: 15px;letter-spacing: 1px;">;新余额28,这是一个</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;">。理论上只有在旧余额为100时,新余额才应该写回成功。</span><br><br>可实际上,这个时候数据库中的金额已经变为28了,所以业务2的并发写回,不应该成功。</span> </section> <p><br></p> <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;">在set写回的时候,加上初始状态的条件compare,只有初始状态不变时,才允许set写回成功,</span> <span style="letter-spacing: 1px;font-size: 12px;">Compare And Set</span> <span style="font-size: 15px;letter-spacing: 1px;">(CAS),是一种常见的降低读写锁冲突,保证数据一致性的方法。</span> </section> <p><br></p> <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;">使用CAS解决高并发时数据一致性问题,只需要在进行set操作时,compare初始值,如果初始值变换,不允许set成功。<br><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">具体到这个case,只需要将:<br></span> <span style="letter-spacing: 1px;font-size: 12px;"><em>UPDATE t_yue SET money=$new_money WHERE uid=$uid;</em></span> <span style="font-size: 15px;letter-spacing: 1px;"><br>升级为:</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 12px;"><em><span style="letter-spacing: 1px;">UPDATE t_yue SET money=$new_money WHERE uid=$uid </span></em></span> <span style="font-size: 12px;color: rgb(255, 76, 0);"><em><span style="font-size: 12px;letter-spacing: 1px;">AND money=$old_money</span></em></span> <span style="font-size: 12px;"><em><span style="letter-spacing: 1px;">;</span></em></span> <em><span style="font-size: 15px;letter-spacing: 1px;"><br>即可。<br></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;">业务1执行:<br></span> <span style="letter-spacing: 1px;font-size: 12px;"><em>UPDATE t_yue SET money=28 WHERE uid=$uid AND money=100;</em></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>业务2执行:<br></span> <span style="letter-spacing: 1px;font-size: 12px;"><em>UPDATE t_yue SET money=38 WHERE uid=$uid AND money=100;</em></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">这两个操作同时进行时,只可能有一个执行成功。</span> </section> <p><br></p> <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;">set操作,其实无所谓成功或者失败,业务能</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">通过affect rows来判断</span> <span style="font-size: 15px;letter-spacing: 1px;">:</span> </section> <ul style="list-style-type: disc;" class=" list-paddingleft-2"> <li><p><span style="font-size: 15px;letter-spacing: 1px;">写回成功的,affect rows为1</span></p></li> <li><p><span style="font-size: 15px;letter-spacing: 1px;">写回失败的,affect rows为0</span></p></li> </ul> <section style="line-height: 1.75em;"></section> <section style="line-height: 1.75em;"></section> <p><br></p> <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;">高并发“查询并修改”的场景,可以用CAS</span> <span style="letter-spacing: 1px;font-size: 12px;">(Compare and Set)</span> <span style="font-size: 15px;letter-spacing: 1px;">的方式解决数据一致性问题。对应到业务,即在set的时候,加上初始条件的比对即可。<br><br>优化不难,只改了半行SQL,但确实能解决问题。<br>但希望大家有收获<strong>,思路比结论重要</strong>。<span style="font-size: 15px;letter-spacing: 1px;"></span></span> </section> <section style="text-align: center;color: rgb(51, 51, 51);clear: both;box-sizing: border-box;background-color: transparent;line-height: 1.75em;"> <img class="rich_pages " style="box-sizing: border-box;margin: 0px;max-width: 677px;padding: 0px;visibility: visible !important;overflow-wrap: break-word;width: 317px !important;height: auto !important;" data-ratio="0.596" data-w="750" data-s="300,640" data-type="png" src="/upload/d0d66cab6277fcb1b00294a045b8323b.png"> </section> <section style="background-color: rgb(255, 255, 255);box-sizing: border-box;clear: both;color: rgb(51, 51, 51);line-height: 1.75em;"> <span style="margin: 0px;padding: 0px;overflow-wrap: break-word;max-width: 100%;box-sizing: border-box;font-size: 15px;letter-spacing: 1px;">欢迎大家继续提问,有问必答。<br style="box-sizing: border-box;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;margin-top: 0px;max-width: 100%;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;padding-top: 0px;word-wrap: break-word;"></span> </section> <p style="background-color: rgb(255, 255, 255);box-sizing: border-box;clear: both;color: rgb(51, 51, 51);"><br style="box-sizing: border-box;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;margin-top: 0px;max-width: 100%;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;padding-top: 0px;word-wrap: break-word;"></p> <section style="background-color: transparent;box-sizing: border-box;color: rgb(51, 51, 51);"></section> <section style="background-color: transparent;box-sizing: border-box;clear: both;color: rgb(51, 51, 51);line-height: 1.75em;"> <span style="letter-spacing: 1px;"><span style="margin: 0px;padding: 0px;letter-spacing: 1px;overflow-wrap: break-word;max-width: 100%;box-sizing: border-box;font-size: 15px;"><strong style="box-sizing: border-box;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;margin-top: 0px;max-width: 100%;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;padding-top: 0px;word-wrap: break-word;">答球友问</strong><span style="font-size: 15px;margin: 0px;padding: 0px;text-align: justify;color: rgb(0, 0, 0);text-transform: none;text-indent: 0px;letter-spacing: 1px;overflow-wrap: break-word;max-width: 100%;box-sizing: border-box;">:</span></span></span> <span style="margin: 0px;padding: 0px;text-align: justify;color: rgb(0, 0, 0);text-transform: none;text-indent: 0px;overflow-wrap: break-word;max-width: 100%;box-sizing: border-box;font-size: 15px;letter-spacing: 1px;"><br>《<a style="box-sizing: border-box;color: rgb(87, 107, 149);margin-bottom: 0px;margin-left: 0px;margin-right: 0px;margin-top: 0px;max-width: 100%;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;padding-top: 0px;text-decoration: none;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);word-wrap: break-word;" href="http://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&mid=2651962667&idx=1&sn=7cb8c095550f9cd777da13bdbc02c8b8&chksm=bd2d08f78a5a81e198424bcba45d16bc696073485204aca49e3e5cd8854aabe1491c463ec5fb&scene=21#wechat_redirect" target="_blank" data-linktype="2" data-itemshowtype="0">用DB自增键生成uid了,还能分库吗?</a>》</span> </section> <section style="line-height: 1.75em;"> <span style="margin: 0px;padding: 0px;text-align: justify;color: rgb(0, 0, 0);text-transform: none;text-indent: 0px;overflow-wrap: break-word;max-width: 100%;box-sizing: border-box;font-size: 15px;letter-spacing: 1px;">《<a href="http://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&mid=2651962693&idx=1&sn=03c8aa29078a4321d18f5ee1369aa408&chksm=bd2d08998a5a818fb837de67d378b3f6085bb2e0a19334e000b4e6640ff8d0282ba390deb6e5&scene=21#wechat_redirect" target="_blank" data-linktype="2" data-itemshowtype="0">粉丝关系链,10亿数据,如何设计?</a>》<br>《<a href="http://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&mid=2651962701&idx=1&sn=19a3bb1c5c4ca4025bfa5a500817341e&chksm=bd2d08918a5a8187ed1a0d77f1aa5bcdc686799b3f9d61a33612f5596286e34a7558feec7365&scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" data-linktype="2">几万条群离线消息,如何高效拉取?</a>》<br>《<a href="http://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&mid=2651962726&idx=1&sn=852d19052f55c163e8e7682513ccf6f8&chksm=bd2d08ba8a5a81ac00bcde40963f24801b3ad223520a71c148fa29636825877f954cb8887d74&scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" data-linktype="2">每秒30W次的点赞业务,怎么优化?</a>》</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;">,为什么不能使用:<br></span> <span style="letter-spacing: 1px;font-size: 12px;"><em>UPDATE t_yue SET money=money-$diff;</em></span> </section>
作者:じ☆ve宝贝
> utf-8编码可能2个字节、3个字节、4个字节的字符,但是MySQL的utf8编码只支持3字节的数据,而移动端的表情数据是4个字节的字符。如果直接往采用utf-8编码的数据库中插入表情数据,Java程序中将报SQL异常: ``` java.sql.SQLException: Incorrect string value: ‘\xF0\x9F\x92\x94’ for column ‘name’ at row 1 at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1073) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3593) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3525) at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1986) at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2140) at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2620) at com.mysql.jdbc.StatementImpl.executeUpdate(StatementImpl.java:1662) at com.mysql.jdbc.StatementImpl.executeUpdate(StatementImpl.java:1581) ``` 可以对4字节的字符进行编码存储,然后取出来的时候,再进行解码。但是这样做会使得任何使用该字符的地方都要进行编码与解码。 utf8mb4编码是utf8编码的超集,兼容utf8,并且能存储4字节的表情字符。 采用utf8mb4编码的好处是:存储与获取数据的时候,不用再考虑表情字符的编码与解码问题。 更改数据库的编码为utf8mb4: ### 1. MySQL的版本 utf8mb4的最低mysql版本支持版本为5.5.3+,若不是,请升级到较新版本。 ### 2. MySQL驱动 5.1.34可用,最低不能低于5.1.13 ### 3.修改MySQL配置文件 修改mysql配置文件my.cnf(windows为my.ini) my.cnf一般在etc/mysql/my.cnf位置。找到后请在以下三部分里添加如下内容: [client] default-character-set = utf8mb4 [mysql] default-character-set = utf8mb4 [mysqld] character-set-client-handshake = FALSE character-set-server = utf8mb4 collation-server = utf8mb4_unicode_ci init_connect=''SET NAMES utf8mb4'' ### 4. 重启数据库,检查变量 SHOW VARIABLES WHERE Variable_name LIKE ''character_set_%'' OR Variable_name LIKE ''collation%''; Variable_name Value character_set_client utf8mb4 character_set_connection utf8mb4 character_set_database utf8mb4 character_set_filesystem binary character_set_results utf8mb4 character_set_server utf8mb4 character_set_system utf8 collation_connection utf8mb4_unicode_ci collation_database utf8mb4_unicode_ci collation_server utf8mb4_unicode_ci collation_connection 、collation_database 、collation_server是什么没关系。 但必须保证 系统变量 描述 character_set_client (客户端来源数据使用的字符集) character_set_connection (连接层字符集) character_set_database (当前选中数据库的默认字符集) character_set_results (查询结果字符集) character_set_server (默认的内部操作字符集) 这几个变量必须是utf8mb4。 ### 5. 数据库连接的配置 数据库连接参数中: characterEncoding=utf8会被自动识别为utf8mb4,也可以不加这个参数,会自动检测。 而autoReconnect=true是必须加上的。 ### 6. 将数据库和已经建好的表也转换成utf8mb4 更改数据库编码:ALTER DATABASE caitu99 CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 更改表编码:ALTER TABLE TABLE_NAME CONVERT TO CHARACTER SET utf8mb4 COLLATEutf8mb4_general_ci; 如有必要,还可以更改列的编码 原文:http://blog.csdn.net/woslx/article/details/49685111