文章列表

架构揭秘:「京东白条」的数据架构进化之路

作者:微信小助手

<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="line-height: 1.6;word-break: break-word;text-align: left;font-size: 15px;color: rgb(53, 53, 53);word-spacing: 0.8px;letter-spacing: 0.8px;border-radius: 16px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;" data-mpa-powered-by="yiban.io"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">你好,我是悟空呀。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">最近小伙伴在讨论单体到微服务架构中数据这块如何演进,相信这篇能给大家带来启发。</p> <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);"> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="line-height: 1.6;word-break: break-word;text-align: left;font-size: 15px;color: rgb(53, 53, 53);word-spacing: 0.8px;letter-spacing: 0.8px;border-radius: 16px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;"> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(255, 177, 27);background: rgb(255, 245, 227);"> <p style="padding-top: 8px;padding-bottom: 8px;font-size: 15px;color: black;line-height: 26px;">来源:SphereEx<br>链接:https://segmentfault.com/a/1190000041107436<br>排版:悟空哥</p> </blockquote> </section> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">京东白条的快速发展满足了当前人们日益增长的消费需求。在京东商城上用京东白条来支付,已经成为一大批用户的消费习惯,更是在某种意义上成为了京东对外的『标签』。而作为一家互联网金融消费平台,京东白条的后台技术团队更是不容忽视的存在。而其也正是支撑京东白条自 2014 年初上线伊始,至今服务数亿用户的最终根源所在。正是京东白条技术团队多年的努力,才造就了当前京东白条的『土生土长』,但具有京东白条特色的金融级数据库选型方法论。</p> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(255, 177, 27);background: rgb(255, 245, 227);"> <p style="padding-top: 8px;padding-bottom: 8px;font-size: 15px;color: black;line-height: 26px;">当京东白条的金融类业务启动时,现任京东白条研发负责人张栋芳,虽然预料到了其数据体量的大幅度增长,却没有想到这种增长将导致数据库选型方面的一系列变化,以及对数据库未来发展模式的启发。</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">作为京东科技旗下的杀手级金融消费应用,今天的京东白条已经成长为服务数亿用户、日均产生巨额流量的庞大金融生态。在业务和数据量飞速增长的同时,京东白条后台的研发人员,也在紧张的焦头烂额中....</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">这一点,完美契合了京东白条后台数据架构的成长过程。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">1、技术的保质期:从 MySQL 到 NoSQL 再到 DBRep</span></h2> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(255, 177, 27);background: rgb(255, 245, 227);"> <p style="padding-top: 8px;padding-bottom: 8px;font-size: 15px;color: black;line-height: 26px;">对于技术人而言,没有永远正确的技术,只有最适合于当下的技术选型。</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">京东白条业务诞生之初正是互联网金融与消费行业的高速发展期,经历这些年的发展,从草根走向专业,从弱小走向规模,从分散走向统一,从杂乱走向规范。京东白条的发展,正是一步步见证了国内互联网消费金融产业的快速迭代。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">同样,京东白条的技术选型历程,也可作为国内互联网消费金融产业发展过程的一个缩影。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">从技术架构的角度来看,并没有绝对的好与不好,需要放在彼时的背景下来看,要考虑业务的时效价值、团队的规模和能力、环境基础设施等等方面。只有架构演进的生命周期适时匹配好业务的生命周期,才能发挥最好的效果。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">2014~2015</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">Solr + HBase 的方案解决了核心、非核心业务系统对关键数据库的访问问题,Solr 作为被检索字段的索引,HBase 用作全量的数据存储。</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 通过 Solr 集群分担部分读和写的业务,缓解核心库的压力; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Solr 扩展体验上欠佳,对业务也存在较大的入侵。 </section></li> </ul> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">2015~2016</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">引入 NoSQL 方案,业务数据以月份进行分表存储在 MongoDB 集群中,阶段性满足了结算处理场景中海量数据导入导出的需求。</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 查询热点数据效率高,非结构化的存储方式易于修改表结构; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 依然面对着扩展差、对业务入侵强的局面,而且耗内存。 </section></li> </ul> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">2016~2017</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">随着业务快速发展,数据量突破百亿大关,此时 MongoDB 面临着容量和性能的双重考验。京东白条大数据平台通过 DBRep 以 MySQL Slave 的形式采集变动信息并存储到消息中心,最后落盘到 ES 和 HBase 中。</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 该方案具有较强的数据实时性,扩展性良好; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 基于业务框架的数据分片难以降低代码维护成本。 </section></li> </ul> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">2、为了让你能够更痛快的剁手,他们先『分解』了自己的后台架构</span></h2> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(255, 177, 27);background: rgb(255, 245, 227);"> <p style="padding-top: 8px;padding-bottom: 8px;font-size: 15px;color: black;line-height: 26px;">网购,贵在手速,但也在于钱包的厚度。京东白条的诞生就是为了解决用户钱包的厚度问题。如今,京东白条也打起了“闪电战”。为了保证用户在消费过程中的体验,后台数据库的稳定性与规律性,就成为了京东白条技术侧亟待考虑和平衡的问题。</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">为保证业务系统在数据激增情况下始终能保持高效运行,京东白条技术团队在设计初期使用了数据分片数据架构,发挥极致性能的同时也兼顾代码的可控性,采用基于应用框架的数据拆分方案完成了数据拆分工作。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">其实说来说去,本质上就是一个问题,即随着产品的升级迭代,早期的解决方案逐渐演变为了阻碍今天前进的绊脚石。通过业务框架实现的数据分片方案导致业务代码复杂度增加、维护成本不断攀升,紧耦合的弊端逐渐显露,应用每次升级都需要投入较多的精力对分片做相应调整,研发人员难以专注于业务本身。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">于是,解耦成了京东白条技术突围的唯一关键。在京东白条而言,主要从以下这四个方面开始解耦:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 数据架构解耦,降低架构之间的耦合度,确保不会因单独业务线变更而导致多个后端架构的调整; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 技术架构解耦,简化业务系统升级工作所带来的复杂研发流程; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 业务关系解耦,需要让用户在使用过程中每个动作都不受影响,不另外产生新的学习成本,为系统提供良好的扩展能力,从容应对“618”和“11.11”等平台大促活动; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 研发流程解耦,解放后端研发生产力,减少业务代码的复杂度。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">因后台数据库与业务之间的耦合度过高,为整个业务的发展埋下了增速放缓的隐患。面对如上诉求,京东白条技术团队经权衡后开始考虑使用成熟的分库分表组件来承担这部分工作,让业务系统升级和架构调整不再复杂。但京东白条业务体量巨大,是名副其实的金融级高并发、海量数据的业务场景,因此在选择分库分表组件时应具备以下 4 个特点:</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">产品成熟稳定。</span>只有成熟且稳定维护的产品,才能够给京东白条这样一款体量的金融产品予以稳定性的保证。使用数据分片来进行架构解耦,本身就是为了确保稳定性; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">极致性能表现。</span>金融场景下的应用,对于数据响应、实时反馈等性能的要求非常高。尤其在交易这种敏感且特殊的场景下,对于性能的表现,一点也不能马虎; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">处理海量数据。</span>京东白条需要处理海量的用户数据,尤其在“618”、“11.11”等大促节日下,面对蜂拥而至海量交易数据与请求,要能够在短时间内快速处理; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">架构灵活扩展。</span>业务灵活多变是当前互联网产品的共性。 </section></li> </ol> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">对此,京东白条从多个方面考虑自研框架与成熟分库分表中间件 ShardingSphere 优劣性,性能对比图如下:</p> <section data-tool="mdnice编辑器" style="overflow-x: auto;"> <table> <thead> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"> <th style="border-top-width: 1px;border-color: rgb(204, 204, 204);text-align: left;font-size: 16px;background-color: rgb(219, 217, 216);min-width: 85px;"><br></th> <th style="border-top-width: 1px;border-color: rgb(204, 204, 204);text-align: left;font-size: 16px;background-color: rgb(219, 217, 216);min-width: 85px;">基于自研框架分片</th> <th style="border-top-width: 1px;border-color: rgb(204, 204, 204);text-align: left;font-size: 16px;background-color: rgb(219, 217, 216);min-width: 85px;">基于 ShardingSphere 分片</th> </tr> </thead> <tbody style="border-width: 0px;border-style: initial;border-color: initial;"> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"> <td style="border-color: rgb(204, 204, 204);font-size: 16px;color: rgb(100, 86, 71);min-width: 85px;">性能</td> <td style="border-color: rgb(204, 204, 204);font-size: 16px;color: rgb(100, 86, 71);min-width: 85px;">高</td> <td style="border-color: rgb(204, 204, 204);font-size: 16px;color: rgb(100, 86, 71);min-width: 85px;">高</td> </tr> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"> <td style="border-color: rgb(204, 204, 204);font-size: 16px;color: rgb(100, 86, 71);min-width: 85px;">代码耦合度</td> <td style="border-color: rgb(204, 204, 204);font-size: 16px;color: rgb(100, 86, 71);min-width: 85px;">高</td> <td style="border-color: rgb(204, 204, 204);font-size: 16px;color: rgb(100, 86, 71);min-width: 85px;">低</td> </tr> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"> <td style="border-color: rgb(204, 204, 204);font-size: 16px;color: rgb(100, 86, 71);min-width: 85px;">业务入侵程度</td> <td style="border-color: rgb(204, 204, 204);font-size: 16px;color: rgb(100, 86, 71);min-width: 85px;">高</td> <td style="border-color: rgb(204, 204, 204);font-size: 16px;color: rgb(100, 86, 71);min-width: 85px;">低</td> </tr> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"> <td style="border-color: rgb(204, 204, 204);font-size: 16px;color: rgb(100, 86, 71);min-width: 85px;">升级难度</td> <td style="border-color: rgb(204, 204, 204);font-size: 16px;color: rgb(100, 86, 71);min-width: 85px;">高</td> <td style="border-color: rgb(204, 204, 204);font-size: 16px;color: rgb(100, 86, 71);min-width: 85px;">低</td> </tr> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"> <td style="border-color: rgb(204, 204, 204);font-size: 16px;color: rgb(100, 86, 71);min-width: 85px;">扩展性</td> <td style="border-color: rgb(204, 204, 204);font-size: 16px;color: rgb(100, 86, 71);min-width: 85px;">一般</td> <td style="border-color: rgb(204, 204, 204);font-size: 16px;color: rgb(100, 86, 71);min-width: 85px;">良好</td> </tr> </tbody> </table> </section> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">最终,京东白条选择采用 Apache ShardingSphere 来进行金融级别的数据库分片任务。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">3、场景趋于融合,但数据库却无法相容:Apache ShardingSphere 解决方案</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">京东白条采用 Apache ShardingSphere-JDBC 解决方案处理在线应用。ShardingSphere-JDBC 是 Apache ShardingSphere 的第一款产品,它定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务。它使用客户端直连数据库,以 jar 包形式提供服务,无需额外部署和依赖,可理解为增强版的 JDBC 驱动,完全兼容 JDBC 和各种 ORM 框架。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">ShardingSphere-JDBC 的以下特点能够很好地满足白条业务场景:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">产品成熟:</span> 经数年打磨产品成熟度高,且社区活跃; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">性能良好:</span> 微内核、轻量化的设计,性能损耗极小; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">改造量小:</span> 支持原生的 JDBC 接口,研发工作量小; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">扩展灵活:</span> 搭配使用迁移同步组件轻松实现数据扩展。 </section></li> </ul> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.8379310344827586" src="/upload/4cdc11b573b8e89e048329f141e6d99d.png" data-type="png" data-w="580" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;"> img </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">经内部大量系统性验证之后,Apache ShardingSphere 成为了京东白条数据分片中间件的首选方案,2018 年底正式开始对接。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">产品适配</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">为全面支撑白条业务、提供更好的业务体验,Apache ShardingSphere 在京东白条业务落地过程中对产品的功能和性能方面进行了更多的支持和提升,产品再一次经历典型案例的打磨。</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 升级 SQL 引擎 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">白条的业务逻辑非常复杂且庞大,多样化场景的需求对 SQL 的兼容程度有着较高要求,Apache ShardingSphere 重构了 SQL 解析模块,并支持了更多的 SQL。经两团队通力合作,京东白条业务与 Apache ShardingSphere 相结合的各项指标满足预期,性能与原生 JDBC 几乎一致。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.773224043715847" src="/upload/29f2b339c3b1cb356567328db17e6100.png" data-type="png" data-w="732" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;"> img </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">关于对接过程中的问题详情及方案,请通过《Apache ShardingSphere 对接京东白条实战》一文来了解。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">业务割接</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">Apache ShardingSphere 使用定制化 HASH 策略对数据进行分片,有效避免了热点数据问题,<span style="font-weight: 700;color: rgb(248, 57, 41);">拆分后的数据节点数达近万个</span>,整个割接过程大约持续了 4 周左右的时间。</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> DBRep 读取数据,通过 Apache ShardingSphere 将数据同步至目标数据库集群; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 两套集群并行运行,数据迁移后再使用自研工具对业务和数据进行校验。 </section></li> </ol> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">DBRep 是 ShardingSphere-Scaling 产品设计的基石,Scaling 具备的自动化能力为后续的迁移扩容工作提供了更多的便利。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">配好业务的生命周期,才能发挥最好的效果。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">价值收益</span><span style="display: none;"></span></h3> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 简化升级路径 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">通过架构解耦,业务系统升级所涉及技术栈得到有效缩短,研发团队不再需要关注分表设计,精力全部聚焦于业务本身,升级路径得到大幅度优化;</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 节省研发力量 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">引入成熟的 Apache ShardingSphere 无需重新开发分表组件,在简化业务升级路径的基础上节省了大量研发力量;</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 架构灵活扩展 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">搭配使用 Scaling 同步迁移组件从容面对“618”和“11.11”等大型活动,系统灵活扩容。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">4、面对新的不稳定业态,需要相对稳定的标准来应对</span></h2> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(255, 177, 27);background: rgb(255, 245, 227);"> <p style="padding-top: 8px;padding-bottom: 8px;font-size: 15px;color: black;line-height: 26px;">如何理解不稳定,并平衡这种不稳定。</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">随着数据的重要性日益凸显,以及终端场景领域的持续细化,业务线『开枝散叶』已是常态,市场上的数据库产品层出不穷。某种意义上,发展了许多年的京东白条,早已不再是当年的数据体量,其金融消费场景已经是一个相对稳定和成熟的场景而言,京东白条仍然是一个快速生长的互联网巨量头部产品,用户和数据体量还远没有达到接近天花板级别。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">这也意味着,随着业务数据量的增长,未来京东白条还需要经历多次具备『阵痛期』的架构转型。而每一次转型,无疑都是一次冒险,这对于追求稳定和体验的金融级产品而言,无疑是需要慎重考虑的。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">而在现阶段通用的数据架构体系下,整个行业都在经历一种新的不稳定业态。面对这种不稳定的业态,京东白条需要一种相对稳定的标准和生态,来『对抗』这种不稳定的趋势。基于此,张栋芳提到了 Database Plus 的概念。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">2018 年,Apache ShardingSphere 作者张亮就曾提出过 Database Plus 的概念。彼时数据库已经呈现出碎片化的趋势,企业在后端数据库管理层面,已经开始产生不小的成本。如果能够在数据库上层重新建设起具备统一管理底层数据的中间层生态,对于企业以及工程师而言,都会极大提高研发与管理的效率。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">所以,Sharding-JDBC 在京东内部,正式升级为 ShardingSphere,<span style="font-weight: 700;color: rgb(248, 57, 41);">寓意打造一个新的生态,并在张亮和社区需求的引导下,逐步确立起了 Database Plus 的发展方向。伴随着近日 Apache ShardingSphere 5.0.0 正式版的更新,Database Plus 理念已正式在 Apache ShardingSphere 生态中得到践行。</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">目前,Apache ShardingSphere 通过可插拔架构,已能够在数据库上层构建起一套全新的数据治理生态,如让传统关系型数据库同时具备水平扩展和数据加密的功能,或在传统关系型数据库的基础上单独打造分布式数据库解决方案等,而无需调整底层数据库架构。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">而这种技术,无疑是应对数据库碎片化趋势的最好方案之一。</span> 而对于未来数据库发展的理解,张栋芳认为,在多样化的数据库上层,构建起统一的数据管理平台,将数据库能力分布在中间层并实现可插拔化,追求功能与业务诉求的高度匹配,筛去冗余的能力,并能够在需要时进行快速变动,始终保证数据架构的整洁、专一。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">5、事物终归需要回归到它的本质</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">从市场和用户规模来看,中国有着全球最广泛的互联网用户群体,产生着最大的数据体量,诞生了一系列成长最快速的互联网科技公司....但是与庞大需求所不匹配的是,国内数据服务市场却始终处于同质化竞争之下,没能有颠覆海外数据库巨头的产品出现。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">张栋芳认为,各家厂商专注于各自的应用场景之下,缺少一个抬头环顾四周的过程。我们始终在谈新技术,始终在追求业务的最高效化。但对于一些需要实现“大象起舞”的金融、证券、制造、零售等领域而言,最新的技术不一定是最适合他们的,在现有技术基础上,提供增量能力的中间件,打造适配于当下业务场景的技术体系,而不是颠覆。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">“<span style="font-weight: 700;color: rgb(248, 57, 41);">事物需要回归它的本质。</span>”对于数据治理方式而言,同样如此。</p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="outline: 0px;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.8px;text-align: left;white-space: normal;word-spacing: 0.8px;background-color: rgb(255, 255, 255);line-height: 1.6;word-break: break-word;border-radius: 16px;visibility: visible;"> <p data-tool="mdnice编辑器" style="margin-top: 0em;margin-bottom: 0em;padding-top: 8px;padding-bottom: 8px;outline: 0px;line-height: 1.75;">我今天跟大家的分享到这里。谢谢大家。</p> </section> <p data-tool="mdnice编辑器" style="margin-top: 0em;margin-bottom: 0em;padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.8px;text-align: left;white-space: normal;word-spacing: 0.8px;background-color: rgb(255, 255, 255);line-height: 1.75;">我是悟空,期待与你一起打怪升级变强!</p> </section> <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);"> <section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzU3NzU5NTg5Mg==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/GfOyjHGwCoN5Ky9IZgsdyZgM3lbEC5Ixe3ZgxBu5MdzvjWFyC7uqrsffcyhtrD8r8t0qicxbGmNxKYr4l4mANKQ/0?wx_fmt=png" data-nickname="面试突击" data-alias="PassJava1" data-signature="大厂面试突击,专注分享面试题,如计算机基础、计算机网络、Java后端、前端Vue。" data-from="0"></mpprofile> <br> </section>

对比7种分布式事务方案,还是偏爱阿里开源的Seata,真香!(原理+实战)

作者:微信小助手

<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="padding: 0px 0.5em;line-height: 1.6;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.05em;color: rgb(89, 89, 89);"> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">这篇文章主要介绍一些目前主流的几种分布式解决方案以及阿里开源的一站式分布式解决方案Seata。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><strong style="letter-spacing: 0.05em;color: rgb(119, 48, 152);">文章有点长,耐心看完,看完你还不懂分布式事务,欢迎来捶我......</strong></p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">文章目录如下:<br></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;padding: 0px 0.5em;"> <img data-fileid="100015719" data-ratio="0.44015696533682147" src="/upload/c212012e7a5033037922402bb2898afc.png" data-type="png" data-w="1529" style="display: block;margin-right: auto;margin-left: auto;border-radius: 3px;box-shadow: rgb(210, 210, 210) 0em 0em 0.5em 0px;font-size: 17px;"> </figure> <h2 data-tool="mdnice编辑器" style="min-height: 32px;line-height: 28px;color: rgb(119, 48, 152);border-bottom: 1px solid rgb(119, 48, 152);border-top-color: rgb(119, 48, 152);border-right-color: rgb(119, 48, 152);border-left-color: rgb(119, 48, 152);font-size: 22px;margin: 1em auto;padding-top: 0.5em;padding-bottom: 0.5em;text-align: center;width: 85%;font-weight: bold;display: flex;flex-direction: column;justify-content: center;"><span style="display: none;"></span>什么是分布式事务?</h2> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">分布式对应的是单体架构,互联网早起单体架构是非常流行的,好像是一个家族企业,大家在一个家里劳作,单体架构如下图:</p> <img data-fileid="100015718" data-ratio="0.9118993135011442" src="/upload/685cd3e95a757f39cd95b9badbbc3c5b.png" data-type="png" data-w="874" style="display: block;margin-right: auto;margin-left: auto;zoom: 70%;border-radius: 3px;box-shadow: rgb(210, 210, 210) 0em 0em 0.5em 0px;font-size: 17px;"> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">但是随着业务的复杂度提高,大家族人手不够,此时不得不招人,这样逐渐演变出了分布式服务,互相协作,每个服务负责不同的业务,架构如下图:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;padding: 0px 0.5em;"> <img data-fileid="100015720" data-ratio="0.563858695652174" src="/upload/40664cfccfbb0036f96deec976c77b75.png" data-type="png" data-w="736" style="display: block;margin-right: auto;margin-left: auto;border-radius: 3px;box-shadow: rgb(210, 210, 210) 0em 0em 0.5em 0px;font-size: 17px;"> <figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"> 分布式架构 </figcaption> </figure> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">因此需要服务与服务之间的远程协作才能完成事务,这种分布式系统环境下由不同的服务之间通过网络远程协作完成事务称之为分布式事务,例如用户注册送积分 事务、创建订单减库存事务,银行转账事务等都是分布式事务。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">典型的场景就是微服务架构 微服务之间通过远程调用完成事务操作。比如:<strong style="color: rgb(119, 48, 152);">订单微服务</strong>和<strong style="color: rgb(119, 48, 152);">库存微服务</strong>,下单的同时订单微服务请求库存微服务减库存。简言之:<strong style="color: rgb(119, 48, 152);">跨JVM进程产生分布式事务</strong>。</p> <h2 data-tool="mdnice编辑器" style="min-height: 32px;line-height: 28px;color: rgb(119, 48, 152);border-bottom: 1px solid rgb(119, 48, 152);border-top-color: rgb(119, 48, 152);border-right-color: rgb(119, 48, 152);border-left-color: rgb(119, 48, 152);font-size: 22px;margin: 1em auto;padding-top: 0.5em;padding-bottom: 0.5em;text-align: center;width: 85%;font-weight: bold;display: flex;flex-direction: column;justify-content: center;"><span style="display: none;"></span>什么是CAP原则?</h2> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">CAP原则又叫CAP定理,同时又被称作布鲁尔定理(Brewer's theorem),指的是在一个分布式系统中,<strong style="color: rgb(119, 48, 152);">不可能同时满足以下三点</strong>。</p> <img data-fileid="100015721" data-ratio="0.9375" src="/upload/6f1493ac49f40227b0f508735e26269b.jpg" data-type="jpeg" data-w="720" style="display: block;margin-right: auto;margin-left: auto;zoom: 70%;border-radius: 3px;box-shadow: rgb(210, 210, 210) 0em 0em 0.5em 0px;font-size: 17px;"> <h3 data-tool="mdnice编辑器" style="font-size: 20px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(119, 48, 152);"><span style="display: none;"></span>一致性(Consistency)<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">指强一致性,在写操作完成后开始的任何读操作都必须返回该值,或者后续写操作的结果。</p> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-bottom: none;font-size: 0.9em;overflow: auto;padding: 10px 10px 10px 20px;margin: 10px 5px;border-left-color: rgb(150, 84, 181);border-right: 1px solid rgb(150, 84, 181);color: rgb(97, 97, 97);quotes: none;background: rgb(251, 249, 253);"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">也就是说,在一致性系统中,一旦客户端将值写入任何一台服务器并获得响应,那么之后client从其他任何服务器读取的都是刚写入的数据</p> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">一致性保证了不管向哪台服务器写入数据,其他的服务器能实时同步数据</p> </blockquote> <h3 data-tool="mdnice编辑器" style="font-size: 20px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(119, 48, 152);"><span style="display: none;"></span>可用性(Availability)<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">可用性(高可用)是指:每次向未崩溃的节点发送请求,总能保证收到响应数据(允许不是最新数据)</p> <h3 data-tool="mdnice编辑器" style="font-size: 20px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(119, 48, 152);"><span style="display: none;"></span>分区容忍性(Partition tolerance)<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">分布式系统在遇到任何网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务,也就是说,服务器<strong style="color: rgb(119, 48, 152);">A</strong>和<strong style="color: rgb(119, 48, 152);">B</strong>发送给对方的任何消息都是可以放弃的,也就是说A和B可能因为各种意外情况,导致无法成功进行同步,分布式系统要能容忍这种情况。除非整个网络环境都发生了故障。</p> <h3 data-tool="mdnice编辑器" style="font-size: 20px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(119, 48, 152);"><span style="display: none;"></span>为什么只能在A和C之间做出取舍?<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">分布式系统中,必须满足 CAP 中的 P,此时只能在 C/A 之间作出取舍。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">如果选择了<strong style="color: rgb(119, 48, 152);">CA</strong>,舍弃了P,说白了就是一个单体架构。</p> <h2 data-tool="mdnice编辑器" style="min-height: 32px;line-height: 28px;color: rgb(119, 48, 152);border-bottom: 1px solid rgb(119, 48, 152);border-top-color: rgb(119, 48, 152);border-right-color: rgb(119, 48, 152);border-left-color: rgb(119, 48, 152);font-size: 22px;margin: 1em auto;padding-top: 0.5em;padding-bottom: 0.5em;text-align: center;width: 85%;font-weight: bold;display: flex;flex-direction: column;justify-content: center;"><span style="display: none;"></span>一致性有几种分类?</h2> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">CAP理论告诉我们只能在C、A之间选择,在分布式事务的最终解决方案中一般选择牺牲一致性来获取可用性和分区容错性。</p> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-bottom: none;font-size: 0.9em;overflow: auto;padding: 10px 10px 10px 20px;margin: 10px 5px;border-left-color: rgb(150, 84, 181);border-right: 1px solid rgb(150, 84, 181);color: rgb(97, 97, 97);quotes: none;background: rgb(251, 249, 253);"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">这里的 “牺牲一致性” 并不是完全放弃数据的一致性,而是放弃<strong style="color: rgb(119, 48, 152);">强一致性</strong>而换取<strong style="color: rgb(119, 48, 152);">弱一致性</strong>。</p> </blockquote> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">一致性可以分为以下三种:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-2"> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 强一致性 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 弱一致性 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 最终一致性 </section></li> </ul> <h3 data-tool="mdnice编辑器" style="font-size: 20px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(119, 48, 152);"><span style="display: none;"></span>强一致性<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">系统中的某个数据被成功更新后,后续任何对该数据的读取操作都将得到更新后的值。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">也称为:原子一致性(Atomic Consistency)、线性一致性(Linearizable Consistency)</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">简言之,在任意时刻,所有节点中的数据是一样的。例如,对于关系型数据库,要求更新过的数据能被后续的访问都能看到,这是强一致性。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><strong style="color: rgb(119, 48, 152);">总结</strong>:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-2"> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 一个集群需要对外部提供强一致性,所以只要集群内部某一台服务器的数据发生了改变,那么就需要等待集群内其他服务器的数据同步完成后,才能正常的对外提供服务。 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 保证了强一致性,务必会损耗 <strong style="color: rgb(119, 48, 152);">可用性</strong>。 </section></li> </ul> <h3 data-tool="mdnice编辑器" style="font-size: 20px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(119, 48, 152);"><span style="display: none;"></span>弱一致性<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">系统中的某个数据被更新后,后续对该数据的读取操作<strong style="color: rgb(119, 48, 152);">可能</strong>得到更新后的值,也可能是更改前的值。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">但即使过了<strong style="color: rgb(119, 48, 152);">不一致时间窗口</strong>这段时间后,后续对该数据的读取也不一定是最新值。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">所以说,可以理解为数据更新后,如果能容忍后续的访问只能访问到部分或者全部访问不到,则是弱一致性。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">例如12306买火车票,虽然最后看到还剩下几张余票,但是只要选择购买就会提示没票了,这就是弱一致性。</p> <h3 data-tool="mdnice编辑器" style="font-size: 20px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(119, 48, 152);"><span style="display: none;"></span>最终一致性<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">是弱一致性的<strong style="color: rgb(119, 48, 152);">特殊</strong>形式,存储系统保证在没有新的更新的条件下,最终所有的访问都是最后更新的值。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">不保证在任意时刻任意节点上的同一份数据都是相同的,但是随着时间的迁移,不同节点上的同一份数据总是在向趋同的方向变化。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">简单说,就是在一段时间后,节点间的数据会最终达到一致状态。</p> <h3 data-tool="mdnice编辑器" style="font-size: 20px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(119, 48, 152);"><span style="display: none;"></span>总结<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16

聊聊 Sharding-JDBC 分库分表

作者:微信小助手

<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="line-height: 1.6;word-break: break-word;text-align: left;padding: 5px;font-size: 16px;color: rgb(53, 53, 53);word-spacing: 0.8px;letter-spacing: 0.8px;border-radius: 16px;font-family: Roboto, Oxygen, Ubuntu, Cantarell, PingFangSC-light, PingFangTC-light, &quot;Open Sans&quot;, &quot;Helvetica Neue&quot;, sans-serif;" data-mpa-powered-by="yiban.io"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">大家好,我是不才陈某~</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">这是<a target="_blank" href="https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzU3MDAzNDg1MA==&amp;action=getalbum&amp;album_id=2389616635193393153#wechat_redirect" textvalue="《ShardingSphere 进阶》" linktype="text" imgurl="" imgdata="null" tab="innerlink" style="color: rgb(255, 41, 65);" data-linktype="2"><span style="color: rgb(255, 41, 65);"><strong>《ShardingSphere 进阶》</strong></span></a>专栏的第一篇文章,介绍一下Sharding-JDBC实现分库分表的详细配置。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">分库分表带来的问题</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">关于什么是分库分表这里不再细说了,相信大家都知道,有不清楚的可以看我之前的文章:<a href="https://mp.weixin.qq.com/s?__biz=MzU3MDAzNDg1MA==&amp;mid=2247508005&amp;idx=1&amp;sn=28a097eb76f423610575a3503617bb16&amp;chksm=fcf77fe8cb80f6fe5e6bf86d1d2978a3996df7842c937376bf81f22e32cf6ffa76ab37ac4558&amp;token=1838352427&amp;lang=zh_CN&amp;scene=21#wechat_redirect" style="color: rgb(248, 57, 41);border-bottom: 1px solid rgb(248, 57, 41);" data-linktype="2">聊聊分库分表</a></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">从单一表、单一库切分成多库、多表对于性能的提升是必然的,但是同时也带来了一些问题。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">1. 分布式事务问题</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">由于垂直分库、水平分库,将数据分摊在不同库中,甚至不同的服务器上,势必带来了分布式事务的问题。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">对于单库单表的事务很好控制,分布式事务的控制却是非常头疼,但是好在现在已经有成熟的解决方案,想要了解的可以看我之前的文章:<a href="https://mp.weixin.qq.com/s?__biz=MzU3MDAzNDg1MA==&amp;mid=2247499421&amp;idx=1&amp;sn=a55797652284bafd9216ea981f4125e0&amp;chksm=fcf72150cb80a846e62beecc2a9f1e251bcd0e23136175504a7e28f1cce2ff5f5a26da1960a2&amp;token=1838352427&amp;lang=zh_CN&amp;scene=21#wechat_redirect" style="color: rgb(248, 57, 41);border-bottom: 1px solid rgb(248, 57, 41);" data-linktype="2">七种分布式事务解决方案</a></p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">2. 跨节点关联join问题</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">在切分之前关联查询非常简单,直接SQL JOIN便能解决,但是切分之后数据分摊在不同的节点上,此时JOIN就比较麻烦了,因此切分之后尽量避免JOIN。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">解决这一问题的有些方法:</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">1、全局表</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">这种很好理解,对于一些全局需要关联的表可以在每个数据节点上都存储一份,一般是一些<span style="font-weight: 700;color: rgb(248, 57, 41);">数据字典表</span>。</p> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 15px;padding-right: 10px;padding-bottom: 15px;line-height: 1.75;border-radius: 13px;color: rgb(53, 53, 53);background: rgb(245, 245, 245);"> <span style="display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">“</span> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;font-size: 16px;margin-right: 10px;margin-left: 10px;">全局表在Sharding-JDBC称之为广播表</p> <span style="float: right;display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">”</span> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">2、字段冗余</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">这是一种典型的反范式设计,为了避免关联JOIN,可以将一些冗余字段保存,比如订单表保存<span style="font-weight: 700;color: rgb(248, 57, 41);">userId</span>时,可以将<span style="font-weight: 700;color: rgb(248, 57, 41);">userName</span>也一并保存,这样就避免了和<span style="font-weight: 700;color: rgb(248, 57, 41);">User</span>表的关联JOIN了。</p> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 15px;padding-right: 10px;padding-bottom: 15px;line-height: 1.75;border-radius: 13px;color: rgb(53, 53, 53);background: rgb(245, 245, 245);"> <span style="display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">“</span> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;font-size: 16px;margin-right: 10px;margin-left: 10px;">字段冗余这种方案存在数据一致性问题</p> <span style="float: right;display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">”</span> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">3、数据组装</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">这种还是比较好理解的,直接不使用JOIN关联,分两次查询,从第一次的结果集中找出关联数据的唯一标识,然后再次去查询,最后对得到的数据进行组装</p> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 15px;padding-right: 10px;padding-bottom: 15px;line-height: 1.75;border-radius: 13px;color: rgb(53, 53, 53);background: rgb(245, 245, 245);"> <span style="display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">“</span> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;font-size: 16px;margin-right: 10px;margin-left: 10px;">需要进行手动组装,数据很大的情况对CPU、内存有一定的要求</p> <span style="float: right;display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">”</span> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">4、绑定表</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">对于相互关联的数据节点,通过<span style="font-weight: 700;color: rgb(248, 57, 41);">分片规则</span>将其切分到同一个库中,这样就可以直接使用SQL的JOIN 进行关联查询。</p> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 15px;padding-right: 10px;padding-bottom: 15px;line-height: 1.75;border-radius: 13px;color: rgb(53, 53, 53);background: rgb(245, 245, 245);"> <span style="display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">“</span> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;font-size: 16px;margin-right: 10px;margin-left: 10px;">Sharding-JDBC中称之为绑定表,比如订单表和用户表的绑定</p> <span style="float: right;display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">”</span> </blockquote> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">3. 跨节点分页、排序、函数问题</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">对于跨数据节点进行分页、排序或者一些聚合函数,筛选出来的仅仅是针对当前节点,比如排序,仅仅能够保证在单一数据节点上是有序,并不能保证在所有节点上都是有序的,需要将各个节点的数据的进行汇总重新手动排序。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;padding: 0px 0.5em;"> <img class="rich_pages wxw-img" data-ratio="1.2725225225225225" src="/upload/b2467e7686209df934d71e75a8331192.png" data-type="png" data-w="444" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;box-shadow: rgb(210, 210, 210) 0em 0em 0.5em 0px;font-size: 17px;"> </figure> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 15px;padding-right: 10px;padding-bottom: 15px;line-height: 1.75;border-radius: 13px;color: rgb(53, 53, 53);background: rgb(245, 245, 245);"> <span style="display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">“</span> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;font-size: 16px;margin-right: 10px;margin-left: 10px;">Sharding-JDBC 正是 按照上述流程进行分页、排序、聚合</p> <span style="float: right;display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">”</span> </blockquote> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">4. 全局主键避重问题</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">单库单表一般都是使用的自增主键,但是在切分之后每个自增主键将无法使用,因为这样会导致数据主键重复,因此必须重新设计主键。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">目前主流的分布式主键生成方案如下:</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">1、UUID</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">UUID应该是大家最为熟悉的一种方案,优点非常明显本地生成,性能高,缺点也很明显,太长了存储耗空间,查询也非常耗性能,另外UUID的无序性将会导致InnoDB下的数据位置变动。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">2、Snowflake</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">Twitter开源的由64位整数组成分布式ID,性能较高,并且在单机上<span style="font-weight: 700;color: rgb(248, 57, 41);">递增</span>。</p> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 15px;padding-right: 10px;padding-bottom: 15px;line-height: 1.75;border-radius: 13px;color: rgb(53, 53, 53);background: rgb(245, 245, 245);"> <span style="display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">“</span> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;font-size: 16px;margin-right: 10px;margin-left: 10px;">不再详细介绍,更多信息自行查找资料</p> <span style="float: right;display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">”</span> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">3、UidGenerator</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">UidGenerator是百度开源的分布式ID生成器,其基于雪花算法实现。具体参考:</p> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 15px;padding-right: 10px;padding-bottom: 15px;line-height: 1.75;border-radius: 13px;color: rgb(53, 53, 53);background: rgb(245, 245, 245);"> <span style="display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">“</span> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;font-size: 16px;margin-right: 10px;margin-left: 10px;">https://github.com/baidu/uid-generator/blob/master/README.zh_cn.md</p> <span style="float: right;display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">”</span> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">4、Leaf</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">Leaf是美团开源的分布式ID生成器,能保证全局唯一,趋势递增,但需要依赖关系数据库、Zookeeper等中间件。具体参考:</p> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 15px;padding-right: 10px;padding-bottom: 15px;line-height: 1.75;border-radius: 13px;color: rgb(53, 53, 53);background: rgb(245, 245, 245);"> <span style="display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">“</span> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;font-size: 16px;margin-right: 10px;margin-left: 10px;">https://tech.meituan.com/2017/04/21/mt-leaf.html</p> <span style="float: right;display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">”</span> </blockquote> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">5. 数据迁移、扩容问题</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">当业务高速发展,面临性能和存储的瓶颈时,才会考虑分片设计,此时就不可避免的需要考虑历史数据迁移的问题。一般做法是先读出历史数据,然后按指定的分片规则再将数据写入到各个分片节点中。此外还需要根据当前的数据量和QPS,以及业务发展的速度,进行容量规划,推算出大概需要多少分片。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">如果采用数值范围分片,只需要添加节点就可以进行扩容了,不需要对分片数据迁移。如果采用的是数值取模分片,则考虑后期的扩容问题就相对比较麻烦。</p> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 15px;padding-right: 10px;padding-bottom: 15px;line-height: 1.75;border-radius: 13px;color: rgb(53, 53, 53);background: rgb(245, 245, 245);"> <span style="display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">“</span> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;font-size: 16px;margin-right: 10px;margin-left: 10px;">分库分表虽然提升了性能,但是在切分过程中一定要考虑上述总结的5种问题。</p> <span style="float: right;display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">”</span> </blockquote> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">Sharding-JDBC 介绍</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">Sharding-JDBC 是当当网研发的开源分布式数据库中间件,从 3.0 开始Sharding-JDBC被包含在 <span style="font-weight: 700;color: rgb(248, 57, 41);">Sharding-Sphere</span> 中,之后该项目进入进入Apache孵化器,4.0版本之后的版本为Apache版本。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈,由Sharding-JDBC、Sharding-Proxy、Sharding-Sidecar(规划中)组成。</p> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 15px;padding-right: 10px;padding-bottom: 15px;line-height: 1.75;border-radius: 13px;color: rgb(53, 53, 53);background: rgb(245, 245, 245);"> <span style="display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">“</span> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;font-size: 16px;margin-right: 10px;margin-left: 10px;">官网:https://shardingsphere.apache.org</p> <span style="float: right;display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">”</span> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">目前我们只需要关注Sharding-JDBC,后面的两种组件后文介绍。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">Sharding-JDBC 的定位是一款轻量级JAVA框架,基于JDBC实现分库分表,通过Sharding-JDBC可以透明的访问已经经过分库、分表的数据源。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">Sharding-JDBC的特性如下:</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 适用于任何基于Java的ORM框架,如:Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 基于任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 支持任意实现JDBC规范的数据库。目前支持MySQL,Oracle,SQLServer和PostgreSQL。 </section></li> </ol> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">Sharding-JDBC 中的一些概念</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">在介绍Sharding-JDBC 实战之前需要了解其中的一些概念,如下:</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">1. 逻辑表</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">在对表进行分片后,一张表分成了n个表,比如订单表<span style="font-weight: 700;color: rgb(248, 57, 41);">t_order</span>分成如下三张表:t_order_1,t_order_2,t_order_3。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">此时订单表的逻辑表就是<span style="font-weight: 700;color: rgb(248, 57, 41);">t_order</span>,Sharding-JDBC在进行分片规则配置时针对的就是这张逻辑表</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">2. 真实表</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">上述t_ordr_1,t_order_2,t_order_3 称之为 真实表</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">3. 数据节点</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">数据分片的最小单元,由数据源名称和表名称组成,比如:<span style="font-weight: 700;color: rgb(248, 57, 41);">ds1.t_order_1</span></p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">4. 分片键</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">用于分片的数据库字段,是将数据库(表)水平拆分的关键字段。例:将订单表中的订单主键的尾数取模分片,则订</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">单主键为分片字段。SQL中如果无分片字段,将执行全路由,性能较差。除了对单分片字段的支持,Sharding- Jdbc也支持根据多个字段进行分片。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">5. 分片算法</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">通过分片算法将数据分片,支持通过 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">=</code> 、 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">BETWEEN</code> 和 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">IN</code> 分片。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">分片算法需要应用方开发者自行实现,可实现的灵 活度非常高。包括:<span style="font-weight: 700;color: rgb(248, 57, 41);">精确分片算法</span> 、<span style="font-weight: 700;color: rgb(248, 57, 41);">范围分片算法</span> ,<span style="font-weight: 700;color: rgb(248, 57, 41);">复合分片算法</span> 等。例如:<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">where order_id = ?</code> 将采用精确分片算法,<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">where order_id in (?,?,?)</code>将采用精确分片算法,<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">where order_id BETWEEN ? and ? </code>将采用范围分片算 法,复合分片算法用于分片键有多个复杂情况。</p> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 15px;padding-right: 10px;padding-bottom: 15px;line-height: 1.75;border-radius: 13px;color: rgb(53, 53, 53);background: rgb(245, 245, 245);"> <span style="display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">“</span> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;font-size: 16px;margin-right: 10px;margin-left: 10px;">Sharding-JDBC 中的分片算法需要开发者根据业务自定义</p> <span style="float: right;display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">”</span> </blockquote> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">6. 分片策略</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">包含分片键和分片算法,由于分片算法的独立性,将其独立抽离。真正可用于分片操作的是分片键 + 分片算法,也 就是分片策略。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">内置的分片策略大致可分为尾数取模、哈希、范围、标签、时间等。由用户方配置的分片策略则更加灵活,常用的使用行表达式配置分片策略,它采用Groovy表达式表示,如: t_user_$-&gt;{u_id % 8} 表示t_user 表根据u_id模8,而分成8张表,表名称为 t_user_0 到 t_user_7 。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">1、标准分片策略</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">标准分片策略适用于单分片键,此策略支持 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">PreciseShardingAlgorithm</code> 和 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">RangeShardingAlgorithm</code> 两个分片算法。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">其中 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">PreciseShardingAlgorithm</code> 是必选的,用于处理 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">=</code> 和 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">IN</code> 的分片。<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">RangeShardingAlgorithm</code> 是可选的,用于处理<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">BETWEEN AND</code>, <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">&gt;</code>, <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">&lt;</code>,<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">&gt;=</code>,<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">&lt;=</code> 条件分片,如果不配置<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">RangeShardingAlgorithm</code>,SQL中的条件等将按照全库路由处理。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">2、复合分片策略</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">复合分片策略,同样支持对 SQL语句中的 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">=</code>,<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">&gt;</code>, <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">&lt;</code>, <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">&gt;=</code>, <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">&lt;=</code>,<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">IN</code>和 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">BETWEEN AND</code> 的分片操作。不同的是它支持多分片键,具体分配片细节完全由应用开发者实现。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">3、行表达式分片策略</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">行表达式分片策略,支持对 SQL语句中的 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">=</code> 和 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">IN</code> 的分片操作,但只支持单分片键。这种策略通常用于简单的分片,不需要自定义分片算法,可以直接在配置文件中接着写规则。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">t_order_$-&gt;{t_order_id % 4}</code> 代表 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">t_order</code> 对其字段 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">t_order_id</code>取模,拆分成4张表,而表名分别是<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">t_order_0</code> 到 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">t_order_3</code>。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">4、Hint分片策略</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">Hint分片策略,对应上边的Hint分片算法,通过指定分片健而非从 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">SQL</code>中提取分片健的方式进行分片的策略。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">7. 分布式主键生成策略</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">通过在客户端生成自增主键替换以数据库原生自增主键的方式,做到分布式主键无重复。</p> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 15px;padding-right: 10px;padding-bottom: 15px;line-height: 1.75;border-radius: 13px;color: rgb(53, 53, 53);background: rgb(245, 245, 245);"> <span style="display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">“</span> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;font-size: 16px;margin-right: 10px;margin-left: 10px;">Sharding-JDBC 内部支持UUID和Snowflake生成分布式主键</p> <span style="float: right;display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">”</span> </blockquote> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">Sharding-JDBC 实战</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">上述内容基本介绍了Sharding-JDBC的基本知识点,下面通过 <span style="font-weight: 700;color: rgb(248, 57, 41);">Spring Boot + Sharding-JDBC</span> 的方式实战演示一下。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">1. Sharding-JDBC 的 pom 依赖</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">想要使用Sharding-JDBC只需要添加一个maven依赖即可,如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oexqmcDw0weKQVqVVibabjK56ibz9hnV66mfibr6qKVf6ib6WLcNGosGib9L1EwAm3VyMkY6Y9X2uE7z4BGf0zHZkeAmA/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(250, 250, 250);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #383a42;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fafafa;border-radius: 5px;"><span style="line-height: 26px;">&lt;<span style="color: #e45649;line-height: 26px;">dependency</span>&gt;</span><br>&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e45649;line-height: 26px;">groupId</span>&gt;</span>org.apache.shardingsphere<span style="line-height: 26px;">&lt;/<span style="color: #e45649;line-height: 26px;">groupId</span>&gt;</span><br>&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e45649;line-height: 26px;">artifactId</span>&gt;</span>sharding-jdbc-spring-boot-starter<span style="line-height: 26px;">&lt;/<span style="color: #e45649;line-height: 26px;">artifactId</span>&gt;</span><br>&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e45649;line-height: 26px;">version</span>&gt;</span>${sharding-sphere.version}<span style="line-height: 26px;">&lt;/<span style="color: #e45649;line-height: 26px;">version</span>&gt;</span><br><span style="line-height: 26px;">&lt;/<span style="color: #e45649;line-height: 26px;">dependency</span>&gt;</span><br></code></pre> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 15px;padding-right: 10px;padding-bottom: 15px;line-height: 1.75;border-radius: 13px;color: rgb(53, 53, 53);background: rgb(245, 245, 245);"> <span style="display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">“</span> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;font-size: 16px;margin-right: 10px;margin-left: 10px;">笔者这里使用的版本为:<span style="font-weight: 700;color: rgb(248, 57, 41);">4.1.1</span></p> <span style="float: right;display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">”</span> </blockquote> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 15px;padding-right: 10px;padding-bottom: 15px;line-height: 1.75;border-radius: 13px;color: rgb(53, 53, 53);background: rgb(245, 245, 245);"> <span style="display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">“</span> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;font-size: 16px;margin-right: 10px;margin-left: 10px;">源码已经上传GitHub,关注公众号:码猿技术专栏,回复关键词:<span style="font-weight: 700;color: rgb(248, 57, 41);">9532</span> 获取!</p> <span style="float: right;display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">”</span> </blockquote> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">2. 垂直分表、分库</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">垂直切分一般针对数据行数不大,但是单行的某些字段数据很大,表占用空间很大,检索的时候需要执行大量的IO,严重降低性能,此时需要将拆分到另外一张表,且与原表是一对一的关系,这就是<span style="font-weight: 700;color: rgb(248, 57, 41);">垂直分表</span>。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">比如商品表中的商品描述数据很大,严重影响查询性能,可以将商品描述这个字段单独抽离出来存储,这样就拆分成了两张表(垂直分表),如下图:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;padding: 0px 0.5em;"> <img class="rich_pages wxw-img" data-ratio="0.673407482305359" src="/upload/b24fad45fe516d4145498a0060500c38.png" data-type="png" data-w="989" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;box-shadow: rgb(210, 210, 210) 0em 0em 0.5em 0px;font-size: 17px;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;"> 垂直分表 </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">通过垂直分表性能得到了一定程度的提升,但是还没有达到要求,并且磁盘空间也快不够了,因为数据还是始终限 制在一台服务器,库内垂直分表只解决了单一表数据量过大的问题,但没有将表分布到不同的服务器上,因此每个 表还是竞争同一个物理机的CPU、内存、网络IO、磁盘。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">此时就需要进行垂直分库,如下之前是在单独的卖家库存储的,现在需要将商品的信息给垂直切分出去,分成了两个库:商品库<span style="font-weight: 700;color: rgb(248, 57, 41);">product_db</span>、店铺库<span style="font-weight: 700;color: rgb(248, 57, 41);">shop_db</span>:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;padding: 0px 0.5em;"> <img class="rich_pages wxw-img" data-ratio="0.5478793178836904" src=

一行代码解决缓存击穿的问题

作者:微信小助手

<section style="font-size: 15px;color: rgb(62, 62, 62);line-height: 1.8;word-spacing: 2px;letter-spacing: 2px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;background-image: linear-gradient(90deg, rgba(50, 0, 0, 0.05) 3%, rgba(0, 0, 0, 0) 3%), linear-gradient(360deg, rgba(50, 0, 0, 0.05) 3%, rgba(0, 0, 0, 0) 3%);background-size: 20px 20px;background-position: center center;"> <h2 style="color: inherit;line-height: inherit;margin-top: 1.6em;margin-bottom: 1.6em;font-weight: bold;font-size: 1.4em;"><span style="font-size: inherit;color: inherit;line-height: inherit;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">引言</span></h2> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">今天,重新回顾一下缓存击穿这个问题!<br>之所以写这个文章呢,因为目前网上流传的文章落地性太差(什么布隆过滤器啊,布谷过滤器啊,嗯,你们懂的),其实这类方案并不适合在项目中直接落地。</span></p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">那么,我们在项目中落地代码的时候,其实只需要一个注解就能解决这些问题,并不需要搞的那么复杂。</span></p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">本文有一个前提,读者必须是</span><code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(248, 35, 117);background: rgb(248, 248, 248);"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">java</span></code><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">栈,且是用</span><code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(248, 35, 117);background: rgb(248, 248, 248);"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">Springboot</span></code><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">构建自己的项目,如果是</span><code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(248, 35, 117);background: rgb(248, 248, 248);"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">go</span></code><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">技术栈或者</span><code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(248, 35, 117);background: rgb(248, 248, 248);"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">python</span></code><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">技术栈的,可能介绍的思路仅供大家参考!</span></p> <h2 style="color: inherit;line-height: inherit;margin-top: 1.6em;margin-bottom: 1.6em;font-weight: bold;font-size: 1.4em;"><span style="font-size: inherit;color: inherit;line-height: inherit;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">正文</span></h2> <h3 style="color: inherit;line-height: inherit;margin-top: 1.6em;margin-bottom: 1.6em;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"><span style="font-size: inherit;line-height: inherit;display: inline-block;font-weight: normal;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">目前缺陷</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid rgb(239, 235, 233);border-right: 20px solid transparent;"> </span></span></h3> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">首先,为什么说目前网上流传的方案,落地性差呢,因为都缺乏一个可以和</span><code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(248, 35, 117);background: rgb(248, 248, 248);"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">SpringBoot</span></code><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">结合起来的真实场景,基本上都脱离了</span><code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(248, 35, 117);background: rgb(248, 248, 248);"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">SpringBoot</span></code><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">,只站在</span><code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(248, 35, 117);background: rgb(248, 248, 248);"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">Java</span></code><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">这个层级去分析。那问题就来了,现在还有不用</span><code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(248, 35, 117);background: rgb(248, 248, 248);"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">SpringBoot</span></code><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">的公司么?因此,本文尝试将该方案和</span><code style="font-size: inherit;line-height: inh

你管这破玩意叫 B+ 树?

作者:微信小助手

<section style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.8;word-spacing: 2px;letter-spacing: 2px;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;" data-mpa-powered-by="yiban.io"> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;"><span style="color: inherit;font-size: inherit;">索引可以说是每个工程师的必备技能点,明白索引的原理对于写出高质量的 SQL 至关重要,今天我们就从 0 到 1 来理解下索引的原理,相信大家看完不光对索引还会对 MySQL 中 InnoDB 存储引擎的最小存储单位「页」会有更深刻的认识</span><br></p> <h3 style="color: inherit;line-height: inherit;margin-top: 1.6em;margin-bottom: 1.6em;font-weight: bold;border-bottom: 2px solid rgb(65, 105, 225);font-size: 1.3em;text-align: justify;"><span style="font-size: inherit;line-height: inherit;display: inline-block;font-weight: normal;background: rgb(65, 105, 225);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">从实际需求出发</span></h3> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">假设有如下用户表:</p> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;word-spacing: 0px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;text-align: justify;"><span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">CREATE</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">TABLE</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">`user`</span>&nbsp;(<br>&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">`id`</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">int</span>(<span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">11</span>)&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">unsigned</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">NOT</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">NULL</span>&nbsp;AUTO_INCREMENT,<br>&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">`name`</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">int</span>(<span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">11</span>)&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">DEFAULT</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">NULL</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">COMMENT</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">'姓名'</span>,<br>&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">`age`</span>&nbsp;tinyint(<span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">3</span>)&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">unsigned</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">DEFAULT</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">NULL</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">COMMENT</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">'年龄'</span>,<br>&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">`height`</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">int</span>(<span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">11</span>)&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">DEFAULT</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">NULL</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">COMMENT</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">'身高'</span>,<br>&nbsp;&nbsp;PRIMARY&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">KEY</span>&nbsp;(<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">`id`</span>)<br>)&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">ENGINE</span>=<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">InnoDB</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">DEFAULT</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">CHARSET</span>=utf8&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">COMMENT</span>=<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">'用户表'</span>;<br></code></pre> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">可以看到存储引擎使用的是 InnoDB,我们先来看针对此表而言工作中比较常用的 SQL 语句都有哪此,毕竟技术是要为业务需求服务的,</p> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;word-spacing: 0px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;text-align: justify;">1.&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">select</span>&nbsp;*&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">from</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">user</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">where</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">id</span>&nbsp;=&nbsp;xxx<br><span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">2.</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">select</span>&nbsp;*&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">from</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">user</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">order</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">by</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">id</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">asc</span>/<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">desc</span><br><span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">3.</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">select</span>&nbsp;*&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">from</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">user</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">where</span>&nbsp;age&nbsp;=&nbsp;xxx<br><span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">4.</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">select</span>&nbsp;age&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">from</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">user</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">where</span>&nbsp;age&nbsp;=&nbsp;xxx<br><span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">5.</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">select</span>&nbsp;age&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">from</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">user</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">order</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">by</span>&nbsp;age&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">asc</span>/<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">desc</span><br></code></pre> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">既然要查询那我们首先插入一些数据吧,毕竟没有数据何来查询</p> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;word-spacing: 0px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;text-align: justify;"><span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">insert</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">into</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">user</span>&nbsp;(<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">'name'</span>,&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">'age'</span>,&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">'height'</span>)&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">values</span>&nbsp;(<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">'张三'</span>,&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">20</span>,&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">170</span>);<br><span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">insert</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">into</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">user</span>&nbsp;(<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">'name'</span>,&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">'age'</span>,&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">'height'</span>)&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">values</span>&nbsp;(<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">'李四'</span>,&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">21</span>,&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">171</span>);<br><span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">insert</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">into</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">user</span>&nbsp;(<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">'name'</span>,&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">'age'</span>,&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">'height'</span>)&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">values</span>&nbsp;(<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">'王五'</span>,&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">22</span>,&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">172</span>);<br><span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">insert</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">into</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">user</span>&nbsp;(<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">'name'</span>,&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">'age'</span>,&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">'height'</span>)&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">values</span>&nbsp;(<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">'赵六'</span>,&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">23</span>,&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">173</span>);<br><span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">insert</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">into</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">user</span>&nbsp;(<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">'name'</span>,&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">'age'</span>,&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">'height'</span>)&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">values</span>&nbsp;(<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">'钱七'</span>,&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">24</span>,&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">174</span>);<br></code></pre> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">插入后表中的数据如下:</p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img class="rich_pages wxw-img" data-ratio="0.6779661016949152" src="/upload/4c733b15f92630e3188546b73e310033.jpg" data-type="jpeg" data-w="354" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" title=""> </figure> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">不知你有没发现我们在插入的时候并没有指定 id 值,但 InnoDB 为每条记录默认添加了一个 id 值,而且这个 id 值是递增的,每插入一条记录,id 递增 1,id 为什么要递增呢,主要是为了查询方便,每条记录按 id 由小到大的顺序用链表连接起来,这样每次查找 id = xxx 的值就从 id = 1 开始依次往后查找即可</p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img class="rich_pages wxw-img" data-ratio="0.15805022156573117" src="/upload/45e6ad745d3734c7809862a6acee0b8d.jpg" data-type="jpeg" data-w="677" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" title=""> </figure> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">现在假设我们要执行以下 SQL 语句,MySQL 会怎么查询呢</p> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;word-spacing: 0px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;text-align: justify;"><span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">select</span>&nbsp;*&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">from</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">user</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">where</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">id</span>&nbsp;=&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">3</span><br></code></pre> <h3 style="color: inherit;line-height: inherit;margin-top: 1.6em;margin-bottom: 1.6em;font-weight: bold;border-bottom: 2px solid rgb(65, 105, 225);font-size: 1.3em;text-align: justify;"><span style="font-size: inherit;line-height: inherit;display: inline-block;font-weight: normal;background: rgb(65, 105, 225);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">页</span></h3> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">如前所述,首先从 id 最小的记录也就是 id = 1 读起,每次读一条记录,将其 id 值与要查询的值比较,连续读三次记录于是找到了记录 3,注意这个读的操作,是首先需要把存储在磁盘的记录读取到内存然后再比较 id 的,从磁盘读到内存算一次 IO,也就是说此过程中产生了三次 IO,如果只是几条记录还好,但如果要比较的条数多的话对性能是非常严重的挑战,如果我要查询为 id = 100 的记录那岂不是要产生 100 次 IO?既然瓶颈在 IO,那该怎么改进呢,很简单,我们现在的设计一次 IO 只能读一条记录,那改为一次 IO 能读取 100 条甚至更多不就只产生一次 IO 了吗,这背后的思想就是<strong style="font-size: inherit;line-height: inherit;color: rgb(48, 79, 254);">程序局部性原理</strong>:当用到了某项数据时,很可能会用到与之相邻的数据,所以干脆把相依的数据一起加载进去(你从 id = 1 开始读,那很可能用到 id = 1 紧随其后的元素,于是干脆把 id = 1 ~ id = 100 的记录都加载进去)</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">当然一次 IO 的读取记录也并不是多多益善,总不能为了一条查询记录而把很多无关的数据都加载到内存吧,那会造成资源的极大浪费,于是我们采用了一个比较折中的方案,我们规定一次 IO 读取 16 K 的数据,假设为 100 条数据好了,这样如果我们要查询 id = 100 的记录,只产生了一次 IO 读(id=1~id=100 的记录),比起原来的 100 次 IO 提升了 100 倍的性能</p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img class="rich_pages wxw-img" data-ratio="2.2944162436548226" src="/upload/307a24a589f90c102bd1cf5f5a7901b5.jpg" data-type="jpeg" data-w="197" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" title=""> </figure> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">我们把这 16KB 的记录组合称为一个<strong style="font-size: inherit;line-height: inherit;color: rgb(48, 79, 254);">页</strong></p> <h3 style="color: inherit;line-height: inherit;margin-top: 1.6em;margin-bottom: 1.6em;font-weight: bold;border-bottom: 2px solid rgb(65, 105, 225);font-size: 1.3em;text-align: justify;"><span style="font-size: inherit;line-height: inherit;display: inline-block;font-weight: normal;background: rgb(65, 105, 225);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">页目录</span></h3> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">一次 IO 会读取一个页,然后再在内存里查找页里的记录,在内存里查找确实比磁盘快多了,但我们仍不满意,因为如果要查找 id = 100 的记录,要先从 &nbsp;id = 1 的记录比较起,然后是id=2,…,id=100,需要比较 100 次,能否更快一点?</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">可以参照二分查找,先查找 id = (1+100)/2 &nbsp;= 50,由于 50 &lt; 100,接着在 &nbsp;50~100 的记录中查,然后再在 75~100 中查,这样经过 7 次就可找到 id = 100 次的记录,比起原来的 100 次比较又提升了不少性能。但现在问题来了,第一次要找到 id = &nbsp;50 的记录又得从 id = 1 开始遍历 50 次才能找到,能否一下就定位到 id=50 的记录呢,如果不能,哪怕第一次从 id = 30 或 40 开始查找也行啊</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">有什么数据结构能满足这种需求呢,还记得跳表不,每隔 n 个元素抽出一个组成一级索引,每隔 2*n 个元素组成二级索引。。。</p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img class="rich_pages wxw-img" data-ratio="0.2016376663254862" src="/upload/9470480848d629d4dbe01c5b50c502f0.jpg" data-type="jpeg" data-w="977" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" title=""> </figure> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">如图示,以建立一级索引为例,我们在查找的时候先在一级索引查找,在一级索引里定位到了再到链表里查找,比如我们要找 7 这个数字,如果不用跳表直接在链表里查,需要比较 7 次,而如果用了跳表我们先在一级索引查找,发现只要比较 3 次,减少了四次,所以我们可以利用跳表的思想来减少查询次数,具体操作如下,每 4 个元素为一组组成一个槽(slot),槽只记录本组元素最大的那条记录以及记录本组有几条记录</p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img class="rich_pages wxw-img" data-ratio="0.9525316455696202" src="/upload/dfd308b3f86ce4bffc367035d3f3ea3.jpg" data-type="jpeg" data-w="632" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" title=""> </figure> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">现在假设我们想要定位 id = 9 的那条记录,该怎么做呢,很简单:<strong style="font-size: inherit;line-height: inherit;color: rgb(48, 79, 254);">首先定位记录在哪个槽,然后遍历此槽中的元素</strong></p> <ol style="font-size: inherit;color: inherit;line-height: inherit;padding-left: 32px;" class="list-paddingleft-1"> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p style="text-align: justify;"><span style="font-size: inherit;color: inherit;line-height: inherit;">定位在哪个槽,首先取最小槽和最大槽对应的 id(分别为 4, 12),先通过二分查找取它们的中间值为 (4+12)/2 = 8,8 小于 9,且槽 2 的最大 id 为 12,所以可知 id = 9 的记录在槽 2 里</span></p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p style="text-align: justify;"><span style="font-size: inherit;color: inherit;line-height: inherit;">遍历槽 2 中的元素,现在问题来了,我们知道每条记录都构成了一个单链表,而每个槽指向的是此分组中的最大 id 值,该怎么从此槽的第一个元素开始遍历呢,很简单,从槽 1 开始遍历不就行了,因为它指向元素的下一个元素即为槽 2 的起始元素,遍历后发现槽 2 的 第一个元素即为我们找到的 id 为 9 的元素</span></p></li> </ol> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">可以看到通过这种方式在页内很快把我们的元素定位出来了,MySQL 规定每个槽中的元素在 1~8 条,所以只要定位了在哪个槽,剩下的比较就不是什么问题了,当然一个页装的记录终究是有限的,如果页满了,就要要开辟另外的页来装记录了,页与页之间通过链表连接起来,但注意看下图,为啥要用双向链表连接起来呢,别忘了最开头我们列出的 「order by id asc 」和「order by id desc 」这两个查询条件,也就是说记录需要同时支持正序与逆序查找,这就是为什么要使用双向链表的原因</p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img class="rich_pages wxw-img" data-ratio="0.694206008583691" src="/upload/c589ff6877483044f8312c867d3bd072.jpg" data-type="jpeg" data-w="932" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" title=""> </figure> <h3 style="color: inherit;line-height: inherit;margin-top: 1.6em;margin-bottom: 1.6em;font-weight: bold;border-bottom: 2px solid rgb(65, 105, 225);font-size: 1.3em;text-align: justify;"><span style="font-size: inherit;line-height: inherit;display: inline-block;font-weight: normal;background: rgb(65, 105, 225);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">B+ 树的诞生</span></h3> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">现在问题来了,如果有很多页,该怎么定位元素呢,如果元素刚好在前几个页还好,大不了遍历前几个页也很快,但如果要查 id = 100w 这样的元素一页页遍历的话就要遍历 1w 页(假设每页 100 条记录),那显然是不可接受的,如何改进呢,其实之前建的页内目录已经给了我们启发,既然在页内我们可以通过为记录建页目录的形式来先定位元素在哪个槽然后再找,那针对多页,能否先定位元素在哪个页呢,也就是说我们可以为页也建立一个目录,这个目录里的每一条记录都对应着页及页中的最小记录,当然这个目录也是以页的形式存在的,为了便于区分 ,我们把针对页生成的目录对应的页称为<strong style="font-size: inherit;line-height: inherit;color: rgb(48, 79, 254);">目录页</strong>,而之前存储<strong style="font-size: inherit;line-height: inherit;color: rgb(48, 79, 254);">完整记录</strong>的页称为<strong style="font-size: inherit;line-height: inherit;color: rgb(48, 79, 254);">数据页</strong></p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img class="rich_pages wxw-img" data-ratio="0.9722792607802875" src="/upload/1e53bb1596ff15a3fc479df79dd57a41.jpg" data-type="jpeg" data-w="974" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" title=""> </figure> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;"><strong style="font-size: inherit;line-height: inherit;color: rgb(48, 79, 254);">画外音</strong>:目录页与数据页一样,内部也是有槽的,上文为了方便展示,没有画出,目录页和数据除了记录数据不一样,其他结构都是一致的</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">现在如果要查找 id = xxx 的记录就很简单了,只要先到目录页中定位它的起始页然后再依次查找即可,由于不管是目录页还是数据页里面都有槽,所以无论是定位目录页的页码还是定位数据页中的记录都是非常快的。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">当然了,随着页的增多,目录页存放的记录也越来越多,目录页也终归会满的,那就再建一个目录页吧,于是现在问题来了,怎么定位要找的 id 是在哪个目录页呢,再次制定针对目录页的目录页不就行了,如下</p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img class="rich_pages wxw-img" data-ratio="0.7497360084477297" src="/upload/b8cd6ce59ea26dfa492159f05ee32d01.jpg" data-type="jpeg" data-w="947" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" title=""> </figure> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">看到上面这个结构你想到了什么?没错,这就是一颗 B+ 树!到此相信你已经明白了 B+ 树的演进之路,也明白了它的原理,可以看到这颗 B+ 树有三层,我们把最顶层的目录页称为<strong style="font-size: inherit;line-height: inherit;color: rgb(48, 79, 254);">根节点</strong>,最下层的存储完整记录的页称为<strong style="font-size: inherit;line-height: inherit;color: rgb(48, 79, 254);">叶子节点</strong>,</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">现在我们再来看一下如何查找 &nbsp;id = 55 的记录,首先会加载根节点,发现应该在页码 30 的页中去找,于是加载页 30,在页 30 中又发现应该在页 4 中查中,于是再次把页 4 加载进内存中,然后在页 4 中依次遍历查找,可以看到总共经历了 3 次 IO(B+树有几层就会有几次 IO),页读取之后会缓存在内存中,再读的话如果命中内存中的页就会直接从内存中获取。有人可能会问,如果 B+ 树层数很多,那岂不是可能会有很多次 IO,我们简单的算一下,假设数据页可以存储 100 条记录,目录页可以存储 1000 条记录(目录页由于只存储了主键,不存储完整的数据,所以可以存储更多的记录),那么</p> <ul style="font-size: inherit;color: inherit;line-height: inherit;padding-left: 32px;" class="list-paddingleft-1"> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p style="text-align: justify;">如果<code style="font-size: inherit;line-height: inherit;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(248, 35, 117);background: rgb(248, 248, 248);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">B+</code>树只有 1 层,也就是只有 1 个用于存放用户记录的节点,最多能存放<code style="font-size: inherit;line-height: inherit;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(248, 35, 117);background: rgb(248, 248, 248);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">100</code>条记录。</p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p style="text-align: justify;">如果<code style="font-size: inherit;line-height: inherit;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(248, 35, 117);background: rgb(248, 248, 248);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">B+</code>树有 2 层,最多能存放<code style="font-size: inherit;line-height: inherit;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(248, 35, 117);background: rgb(248, 248, 248);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">1000×100=100000</code>条记录。</p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p style="text-align: justify;">如果<code style="font-size: inherit;line-height: inherit;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(248, 35, 117);background: rgb(248, 248, 248);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">B+</code>树有 3 层,最多能存放<code style="font-size: inherit;line-height: inherit;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(248, 35, 117);background: rgb(248, 248, 248);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">1000×1000×100=100000000</code>条记录。</p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p style="text-align: justify;">如果<code style="font-size: inherit;line-height: inherit;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(248, 35, 117);background: rgb(248, 248, 248);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">B+</code>树有 4 层,最多能存放<code style="font-size: inherit;line-height: inherit;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(248, 35, 117);background: rgb(248, 248, 248);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">1000×1000×1000×100=100000000000</code>条记录!</p></li> </ul> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">所以一般3~4 层的 B+ 树足以满足我们的要求,而且每次读取后会缓存在内存中(当然也会根据一定的算法被换出内存),所以整体来看 3~4 层 B+ 树足以满足我们需求</p> <h3 style="color: inherit;line-height: inherit;margin-top: 1.6em;margin-bottom: 1.6em;font-weight: bold;border-bottom: 2px solid rgb(65, 105, 225);font-size: 1.3em;text-align: justify;"><span style="font-size: inherit;line-height: inherit;display: inline-block;font-weight: normal;background: rgb(65, 105, 225);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">聚簇索引与非聚簇索引</span></h3> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">相信你已经发现了,上文中我们举的 B+ 树的例子针对的是 id 也就是主键的索引,不难发现主键索引中的叶子结点存储了完整的 SQL 记录,我们把这种存储了完整记录的索引称为聚簇索引,<strong style="font-size: inherit;line-height: inherit;color: rgb(48, 79, 254);">只要你定义了主键,那么主键索引就是聚簇索引</strong>。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">那么如果是非主键的列创建的索引又是怎样的形式呢,非叶子节点的形式完全一样,但叶子节点的存储则有些不同,非主键列索引叶子节点上存储的是<strong style="font-size: inherit;line-height: inherit;color: rgb(48, 79, 254);">索引列及主键值</strong>,比如我们假设对 age 这个列建立了索引,那么它的索引树如下</p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img data-ratio="0.7497360084477297" src="/upload/54007870a0a699333ac9d3b1f06230e9.jpg" data-type="jpeg" data-w="947" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" title=""> </figure> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">可以看到非叶子节点保存的是「age 值 + 页码」,而叶子节点保存的是 「age 值+主键值」,那么你可能就会疑惑了,如下 SQL 是怎么取出完整记录的呢</p> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;word-spacing: 0px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;text-align: justify;"><span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">select</span>&nbsp;*&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">from</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">user</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">where</span>&nbsp;age&nbsp;=&nbsp;xxx<br></code></pre> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">第一步大家都知道,上述 SQL 可以命中 age 列对应的索引,然后找到叶子节点上对应的记录(如果有的话),但叶子节点上的记录只有 age 和 id 这两列,而你用的是 select *,意味着要查找 user 的所有列信息,该怎么办呢,答案是根据拿到的 id 再到聚簇索引找 id 对应的完整记录,这就是我们所说的<strong style="font-size: inherit;line-height: inherit;color: rgb(48, 79, 254);">回表</strong>,如果回表多的话显然会造成一定的性能问题,因为 id 可能分布在不同的页中,这意味着要将不同的页从磁盘读入内存,这些页很可能不是相邻的,也就意味着会造成大量的<strong style="font-size: inherit;line-height: inherit;color: rgb(48, 79, 254);">随机 IO</strong>,会严重地影响性能,看到这相信大家不难明白一道高频面试题:<strong style="font-size: inherit;line-height: inherit;color: rgb(48, 79, 254);">为什么设置了命中了索引但还是造成了全表扫描</strong>,其中一个原因就是虽然命中了索引但在叶子节点查询到记录后还要大量的回表,导致优化器认为这种情况还不如全表扫描会更快些</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">有人可能会问,为啥都二级索引不存储完整的记录呢,当然是为了节省空间,毕竟完整的数据是很耗空间的,如果每加一个索引都要额外存储完整的记录,那会造成很多数据冗余。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">怎么避免这种情况呢?<strong style="font-size: inherit;line-height: inherit;color: rgb(48, 79, 254);">索引覆盖</strong>,如果如下 SQL 满足你的需求,那么就建议采用如下形式</p> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;word-spacing: 0px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;text-align: justify;"><span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">select</span>&nbsp;age&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">from</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">user</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">where</span>&nbsp;age&nbsp;=&nbsp;xxx<br><span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">select</span>&nbsp;age,<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">id</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">from</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">user</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">where</span>&nbsp;age&nbsp;=&nbsp;xxx<br></code></pre> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">不难发现这种 SQL 的特点是要获取的列(age)就是索引列本身(包括 id),这样在根据 age 的索引查到叶子节上对应的记录后,由于记录本身就包含了这些列,就不需要回表了,能提升性能</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;"><strong style="font-size: inherit;line-height: inherit;color: rgb(48, 79, 254);">磁盘预读</strong></p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">接下来我们讨论一个网上很多人搞不拎清的一个问题,我们知道操作系统是以页为单位来管理内存的,在 Linux 中,一页的大小默认为 4 KB,也就是说无论是从磁盘载入数据到内存还是将内存写回磁盘,操作系统都会以页为单位进行操作,哪怕你只对一个空文件只写入了一个字节,操作系统也会为其分配一个页的大小( 4 KB)</p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img class="rich_pages wxw-img" data-ratio="0.8689138576779026" src="/upload/ce13dc6d4803a8537fe9991780b5d9ab.jpg" data-type="jpeg" data-w="267" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" title=""> </figure> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;"><code style="font-size: inherit;line-height: inherit;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(248, 35, 117);background: rgb(248, 248, 248);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">如图示,向磁盘写入了两个 byte ,但操作系统依然为其分配了一个页(4 KB)的大小</code></p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">innoDB 也是以页为单位来存储与读取的,而 innoDB 页的默认大小为 16 KB,那么网上很多人的疑问是这是否意味着它需要执行 4 次 IO 才能把 innoDB 的页读完呢?不是的,只需要一次 IO,为什么?这需要理解一点磁盘读取数据的工作原理</p> <h4 style="color: inherit;line-height: inherit;margin-top: 1.6em;margin-bottom: 1.6em;font-weight: bold;font-size: 1.2em;text-align: justify;"><span style="font-size: inherit;color: inherit;line-height: inherit;">磁盘的构造</span></h4> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">首先我们来看看磁盘的物理结构</p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img class="rich_pages wxw-img" data-ratio="0.6759259259259259" src="/upload/fa7f5afb387c5696ea65852c515b8d46.jpg" data-type="jpeg" data-w="1080" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" title=""> </figure> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">硬盘内部主要部件为磁盘盘片、传动磁臂、读写磁头和转轴,数据主要写入磁盘的盘片上的,盘片又是由若干个<strong style="font-size: inherit;line-height: inherit;color: rgb(48, 79, 254);">扇区</strong>构成的,数据写入读取都是以扇区为基本单位的,另外以盘片中心为圆心,把盘片分成若干个同心圆,那每一个划分圆的“线条”,就称为<strong style="font-size: inherit;line-height: inherit;color: rgb(48, 79, 254);">磁道</strong></p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">那么数据是如何读取与写入的呢,主要有三步</p> <ol style="font-size: inherit;color: inherit;line-height: inherit;padding-left: 32px;" class="list-paddingleft-1"> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p style="text-align: justify;"><strong style="font-size: inherit;line-height: inherit;color: rgb(48, 79, 254);">寻道</strong>:既然数据是保存在扇区上的,那我首先我们需要知道它到底是在哪个扇区上吧,这就需要先让磁头移动到扇区所在的磁道上,我们把它称为寻道时间,平均寻道时间一般在3-15ms</p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p style="text-align: justify;"><strong style="font-size: inherit;line-height: inherit;color: rgb(48, 79, 254);">旋转延迟</strong>: 磁盘移动到扇区所在的磁盘上时,此时的磁头对准的还不一定我们想要的数据对应的扇区,所以需要等待盘片旋转片刻,等到我们想要的数据对应的扇区落到磁头下,旋转延迟取决于磁盘转速,通常用磁盘旋转一周所需时间的1/2表示。比如:7200rpm的磁盘平均旋转延迟大约为60*1000/7200/2 = 4.17ms,而转速为15000rpm的磁盘其平均旋转延迟为2ms</p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p style="text-align: justify;"><strong style="font-size: inherit;line-height: inherit;color: rgb(48, 79, 254);">数据传输</strong>:经过前面的两步,磁头终于开始读写数据了,目前IDE/ATA能达到133MB/s,SATA II可达到300MB/s的接口数据传输率,<strong style="font-size: inherit;line-height: inherit;color: rgb(48, 79, 254);">数据传输时间通常远小于前两部分消耗时间</strong>。可忽略不计</p></li> </ol> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">注意数据传输中的忽略不计是有前提的,即是需要读取<strong style="font-size: inherit;line-height: inherit;color: rgb(48, 79, 254);">连续相邻</strong>的扇区,也就是我们常说的顺序 IO,磁盘顺序 IO 的读写速度可以媲美甚至超越内存的随机 IO,所以这部分时间可以忽略不计,(大家熟知的 Kafka 之所以性能强悍,有一个重要原因就是利用了磁盘的顺序读写),但如果要读取的数据是分布在不同的扇区的话,也就变成了随机 IO,随机 IO 毫无疑问增大了寻道时间和旋转延迟,性能是非常堪忧的(典型代表就是上文提到的 回表时大量 id 分布在不同的页上,造成了大量的随机 IO)</p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img class="rich_pages wxw-img" data-ratio="0.5504273504273505" src="/upload/1bc1dd969682c333df15613fbbe44d49.jpg" data-type="jpeg" data-w="585" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" title=""> </figure> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;"><strong style="font-size: inherit;line-height: inherit;color: rgb(48, 79, 254);">如图示</strong>:图片来自著名学术期刊 ACM Queue 上的性能对比图,可以看到磁盘顺序 IO(Sequential Disk)的速度比内存随机读写(Random memory)还快</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">那读取 innoDB 中的一个页为啥算一次 IO 呢,相信你已经猜到了,因为这一个页是连续分配的,也即意味着它们的扇区是相邻的,所以它是顺序 IO</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">操作系统是以页为单位来管理内存的,它可以一次加载整数倍的页,而 innoDB 的页大小为 16KB,刚好是操作系统页(4KB)的 4 倍,所以可以指定在读取的起始地址连续读取 4 个操作系统页,即 16 KB,这就是我们说的<strong style="font-size: inherit;line-height: inherit;color: rgb(48, 79, 254);">磁盘预读</strong>,至此相信大家不难明白为啥说读取一页其实只是一次 IO 而不是 4 次了</p> <h3 style="color: inherit;line-height: inherit;margin-top: 1.6em;margin-bottom: 1.6em;font-weight: bold;border-bottom: 2px solid rgb(65, 105, 225);font-size: 1.3em;text-align: justify;"><span style="font-size: inherit;line-height: inherit;display: inline-block;font-weight: normal;background: rgb(65, 105, 225);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">总结</span></h3> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.7em;margin-bottom: 1.7em;text-align: justify;">看完本文相信大家能明白索引的由来了,此外对页以及磁盘预读对性能的提升应该也有不少了解,其实 MySQL 的页结构与我们推演的结构有些许出入,不过不影响整体的理解,如果大家有兴趣深入了解 MySQL 的页结构,强烈建议大家看看文末的&lt; <mysql mysql="" style="font-size: inherit;color: inherit;line-height: inherit;"> MySQL是怎样运行的&gt;这本书,讲解得非常细致 </mysql></p> <ul style="font-size: inherit;color: inherit;line-height: inherit;padding-left: 32px;" class="list-paddingleft-1"> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p style="text-align: justify;"><span style="font-size: inherit;color: inherit;line-height: inherit;">巨人的肩膀</span></p></li> </ul> <ol style="font-size: inherit;color: inherit;line-height: inherit;padding-left: 32px;" class="list-paddingleft-1"> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p style="text-align: justify;"><span style="font-size: inherit;color: inherit;line-height: inherit;">磁盘I/O那些事: https://tech.meituan.com/2017/05/19/about-desk-io.html</span></p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p style="text-align: justify;"><span style="font-size: inherit;color: inherit;line-height: inherit;">带你从头到尾捋一遍MySQL索引结构: https://blog.51cto.com/u_12302929/3290492</span></p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p style="text-align: justify;"><span style="font-size: inherit;color: inherit;line-height: inherit;">MySQL 是怎样运行的:从根儿上理解 MySQL</span></p><p style="text-align: justify;"><span style="font-size: inherit;color: inherit;line-height: inherit;"></span></p></li> </ol> </section> <section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="Mzg4NjYyODc4OA==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/J4jTHmo8Xh6qM32ASOtVbXNoiaegrI26qLRw6r6FTI7dZw6TMT7vecvnjd1O8xSsM5MiajIuQZicxSC6KFK8TMpbg/0?wx_fmt=png" data-nickname="java突击队" data-alias="" data-signature="技术经验分享" data-from="0"></mpprofile> </section>

聊聊 MQ 技术选型

作者:微信小助手

<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="line-height: 1.6;word-break: break-word;text-align: left;padding: 5px;font-size: 16px;color: rgb(53, 53, 53);word-spacing: 0.8px;letter-spacing: 0.8px;border-radius: 16px;font-family: Roboto, Oxygen, Ubuntu, Cantarell, PingFangSC-light, PingFangTC-light, &quot;Open Sans&quot;, &quot;Helvetica Neue&quot;, sans-serif;" data-mpa-powered-by="yiban.io"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">消息队列中间件是分布式系统中重要的组件,主要解决应用耦合、异步消息、流量削锋等问题。它可以实现高性能、高可用、可伸缩和最终一致性架构,是大型分布式系统不可缺少的中间件。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">消息队列在电商系统、消息通讯、日志收集等应用中扮演着关键作用,以阿里为例,其研发的消息队列(RocketMQ)在历次天猫 “双十一” 活动中支撑了万亿级的数据洪峰,为大规模交易提供了有力保障。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">作为提升应用性能的重要手段,分布式消息队列技术在互联网领域得到了越来越广泛的关注 。本文将介绍四种常用的分布式消息队列开源软件:<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">Kafka</code>、<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">ActiveMQ</code>、<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">RabbitMQ</code> 及 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">RocketMQ</code>。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">文章目录如下:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Kafka </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> ActiveMQ </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> RabbitMQ </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> RocketMQ </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 几种消息队列的比较 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 参考文献 </section></li> </ul> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">1. Kafka</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">在分布式消息队列的江湖里,Kafka 凭借其优秀的性能占据重要一席。它最初由 LinkedIn 公司开发,Linkedin 于 2010 年贡献给了 Apache基金会,之后成为顶级开源项目。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">Kafka简介</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">关于 Kafka,网上有很多介绍,经过不断地复制、洗稿、演绎后,难免背离原意,因此,我们还是来看一下官网给出的定义:</p> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 15px;padding-right: 10px;padding-bottom: 15px;line-height: 1.75;border-radius: 13px;color: rgb(53, 53, 53);background: rgb(245, 245, 245);"> <span style="display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">“</span> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;font-size: 16px;margin-right: 10px;margin-left: 10px;">Apache Kafka is a distributed streaming platform.</p> <span style="float: right;display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">”</span> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">Kafka 作为流平台具有以下三种能力:</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 发布和订阅记录流,类似于消息队列或企业消息系统; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 具有容错能力,且可以持久化的方式存储记录流; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 当记录流产生时(发生时),可及时对其进行处理。 </section></li> </ol> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">Kafka 适用于两类应用:</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 建立实时流数据管道,在系统或应用之间可靠地获取数据; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 建立对数据流进行转换或反应的实时流应用程序。 </section></li> </ol> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">kafka 包含四种核心 API。</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Producer API:基于该 API,应用程序可以将记录流发布到一个或多个 Kafka 主题(Topics); </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Consumer API:基于该 API,应用程序可以订阅一个或多个主题,并处理主题对应的记录流; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Streams API:基于该 API,应用程序可以充当流处理器,从一个或多个主题消费输入流,并生成输出流输出一个或多个主题,从而有效地将输入流转换为输出流; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Connector API:允许构建和运行将 Kafka 主题连接到现有应用程序或数据系统的可重用生产者或消费者。例如,关系数据库的连接器可能会捕获表的每一个更改。 </section></li> </ul> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">Kafka 特点</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">作为一种高吞吐量的分布式发布订阅消息系统,Kafka 具有如下特性:</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 快速持久化,可以在 O(1) 的系统开销下进行消息持久化; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 高吞吐,在一台普通的服务器上可以达到 10W/s 的吞吐速率; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 完全的分布式系统,Broker、Producer、Consumer 都原生自动支持分布式,自动实现负载均衡; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 支持同步和异步复制两种 HA; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 支持数据批量发送和拉取; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Zero-Copy,减少 IO 操作步骤; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 数据迁移、扩容对用户透明; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 无需停机即可扩展机器; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 其他特性还包括严格的消息顺序、丰富的消息拉取模型、高效订阅者水平扩展、实时的消息订阅、亿级的消息堆积能力、定期删除机制。 </section></li> </ol> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">Kafka 部署环境</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">操作系统</span></p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Windows:虽然 Kafka 可以在部分 Windows 系统运行,但官方并不推荐; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Unix:支持所有版本的 Unix 系统,以及 Linux 和 Solaris系统。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">环境要求</span></p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> JDK:Kafka 的最新版本为 2.0.0,JDK 版本需 1.8 及以上; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> ZooKeeper:Kafka 集群依赖 ZooKeeper,需根据 Kafka 的版本选择安装对应的 ZooKeeper 版本(未来的 Kafka 即将脱离 ZooKeeper)。 </section></li> </ul> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">Kafka 架构</span><span style="display: none;"></span></h3> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;padding: 0px 0.5em;"> <img class="rich_pages wxw-img" data-ratio="0.4890625" src="/upload/2798a724b4f6b2becd5647462af34613.jpg" data-type="jpeg" data-w="640" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;box-shadow: rgb(210, 210, 210) 0em 0em 0.5em 0px;font-size: 17px;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;"> kafka架构 </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">如上图所示,一个典型的 Kafka 体系架构包括若干 Producer(消息生产者),若干 Broker(Kafka 支持水平扩展,一般 Broker 数量越多,集群吞吐率越高),若干 Consumer(Group),以及一个 Zookeeper 集群。Kafka 通过 Zookeeper 管理集群配置,选举 Leader,以及在 Consumer Group 发生变化时进行 Rebalance。Producer 使用 Push(推)模式将消息发布到 Broker,Consumer 使用 Pull(拉)模式从 Broker 订阅并消费消息。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">各个名词的解释请见下表:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;padding: 0px 0.5em;"> <img class="rich_pages wxw-img" data-ratio="0.396875" src="/upload/ca624d20dff32357eb1b087b8946e65d.jpg" data-type="jpeg" data-w="640" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;box-shadow: rgb(210, 210, 210) 0em 0em 0.5em 0px;font-size: 17px;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;"> Kafka 核心组件 </figcaption> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">Kafka 高可用方案</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">Kafka 高可用性的保障来源于其健壮的副本(Replication)策略。为了提高吞吐能力,Kafka 中每一个 Topic 分为若干 Partitions;为了保证可用性,每一个 Partition 又设置若干副本(Replicas);为了保障数据的一致性,Zookeeper 机制得以引入。基于 Zookeeper,Kafka 为每一个 Partition 找一个节点作为 Leader,其余备份作为 Follower,只有 Leader 才能处理客户端请求,而 Follower 仅作为副本同步 Leader 的数据,如下示意图:TopicA 分为两个 Partition,每个 Partition 配置两个副本。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;padding: 0px 0.5em;"> <img class="rich_pages wxw-img" data-ratio="0.572" src="/upload/ef7c973a85e2a20ae1f61d7a260a76a9.jpg" data-type="jpeg" data-w="500" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;box-shadow: rgb(210, 210, 210) 0em 0em 0.5em 0px;font-size: 17px;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;"> Kafka 高可用方案 </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">基于上图的架构,当 Producer Push 的消息写入 Partition(分区) 时,Leader 所在的 Broker(Kafka 节点)会将消息写入自己的分区,同时还会将此消息复制到各个 Follower,实现同步。如果某个 Follower 挂掉,Leader 会再找一个替代并同步消息;如果 Leader 挂了,将会从 Follower 中选举出一个新的 Leader 替代,继续业务,这些都是由 ZooKeeper 完成的。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">Kafka 优缺点</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">优点主要包括以下几点:</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 客户端语言丰富,支持 Java、.NET、PHP、Ruby、Python、Go 等多种语言; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 性能卓越,单机写入 TPS 约在百万条/秒,消息大小 10 个字节; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 提供完全分布式架构,并有 Replica 机制,拥有较高的可用性和可靠性,理论上支持消息无限堆积; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 支持批量操作; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 消费者采用 Pull 方式获取消息,消息有序,通过控制能够保证所有消息被消费且仅被消费一次; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 有优秀的第三方 Kafka Web 管理界面 Kafka-Manager; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 在日志领域比较成熟,被多家公司和多个开源项目使用。 </section></li> </ol> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">缺点主要有:</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Kafka 单机超过 64 个队列/分区,Load 会发生明显的飙高现象,队列越多,Load 越高,发送消息响应时间越长; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 使用短轮询方式,实时性取决于轮询间隔时间; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 消费失败不支持重试; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 支持消息顺序,但是一台代理宕机后,就会产生消息乱序; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 社区更新较慢。 </section></li> </ol> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">2. ActiveMQ</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">ActiveMQ 是 Apache 下的一个子项目。之所以把它放在第二位介绍,是因为它官网上的说明:</p> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 15px;padding-right: 10px;padding-bottom: 15px;line-height: 1.75;border-radius: 13px;color: rgb(53, 53, 53);background: rgb(245, 245, 245);"> <span style="display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">“</span> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;font-size: 16px;margin-right: 10px;margin-left: 10px;">Apache ActiveMQ is the most popular and powerful open source messaging and Integration Patterns server.</p> <span style="float: right;display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">”</span> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">居然没有“之一”,不太谦虚呀,放在第二位,以示“诫勉”。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">ActiveMQ 简介</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">ActiveMQ 由 Apache 出品,据官网介绍,它是最流行和最强大的开源消息总线。ActiveMQ 是一个完全支持 JMS1.1 和 J2EE 1.4 规范的 JMS Provider 实现,非常快速,支持多种语言的客户端和协议,而且可以非常容易地嵌入到企业的应用环境中,并有许多高级功能。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">ActiveMQ 基于 Java 语言开发,目前最新版本为 5.1.5.6。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">ActiveMQ 特点</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">ActiveMQ 的特点,官网在 Features 一栏中做了非常详细的说明,我做了下翻译,如下:</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 支持多种语言和协议编写客户端。语言包括 Java、C、C++、C#、Ruby、Perl、Python、PHP。应用协议包括 OpenWire、Stomp REST、WS Notification、XMPP、AMQP; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 完全支持 JMS1.1 和 J2EE 1.4 规范(持久化、XA 消息、事务); </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 完全支持 JMS 客户端和消息代理中的企业集成模式; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 支持许多高级特性,例如消息组、虚拟目的地、通配符和复合目的地; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 支持 Spring,ActiveMQ 可以很容易地嵌入 Spring 应用程序中,并使用 Spring 的 XML 配置机制进行配置; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 通过了常见 J2EE 服务器(如 Geronimo、JBoss4、GlassFish、WebLogic)的测试,其中通过 JCA 1.5 Resource Adaptors 的配置,可以让 ActiveMQ 自动部署到任何兼容 J2EE 1.4 商业服务器上; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 支持多种传输协议,如 VM、TCP、SSL、NIO、UDP、Multicast、JGroups 以及 JXTA; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 支持通过 JDBC 和 Journal 提供高速的消息持久化; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 从设计上保证了高性能的集群,客户端-服务器,点对点; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> REST API 为消息提供技术无关和基于语言的 Web API; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> AJAX 允许使用纯 DHTML 实现 Web 流对 Web 浏览器的支持,允许 Web 浏览器成为消息传递结构的一部分; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 获得 CXF 和 Axes 的支持,使得 ActiveMQ 可以很容易地嵌入 Web 服务栈中的任何一个,以提供可靠的消息传递; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 很容易调用内嵌 JMS Provider,进行测试。 </section></li> </ol> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">ActiveMQ 部署环境</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">相较于 Kafka,ActiveMQ 的部署简单很多,支持多个版本的 Windows 和 Unix 系统,此外,ActiveMQ 由 Java 语言开发而成,因此需要 JRE 支持。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">硬件要求:</span></p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 如果以二进制文件安装,ActiveMQ 5.x 需要 60M 空间。当然,需要额外的磁盘空间来持久化消息; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 如果下载 ActiveMQ 5.x 源文件,自行编译构建, 则需要 300M 空间。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">操作系统:</span></p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Windows:支持 Windows XP SP2、Windows 2000、Windows Vista、Windows 7; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Unix:支持 Ubuntu Linux、Powerdog Linux、MacOS、AIX、HP-UX、Solaris,或者其它任何支持 Java 的 Unix 平台。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">环境要求:</span></p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Java 运行环境(JRE),版本 1.7 及以上,如果以源码自行编译构建,则还需要安装 JDK; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 需要为 JRE 配置环境变量,通常命名为 JAVA_HOME; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 如果以源文件自行编译构建,需安装 Maven 3.0.0 及以上版本,同时,依赖的 JAR 包需要添加到 classpath 中。 </section></li> </ul> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">ActiveMQ 架构</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">ActiveMQ 的主体架构如下图所示。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;padding: 0px 0.5em;"> <img class="rich_pages wxw-img" data-ratio="0.33867735470941884" src="/upload/872a5e0413a4904d9dd6a6f69d44dfa.jpg" data-type="jpeg" data-w="499" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;box-shadow: rgb(210, 210, 210) 0em 0em 0.5em 0px;font-size: 17px;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;"> ActiveMQ 架构 </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">传输协议</code>:消息之间的传递,无疑需要协议进行沟通,启动一个 ActiveMQ 便打开一个监听端口。ActiveMQ 提供了广泛的连接模式,主要包括 SSL、STOMP、XMPP。ActiveMQ 默认的使用协议为 OpenWire,端口号为 61616。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">通信方式</code>:ActiveMQ 有两种通信方式,Point-to-Point Model(点对点模式),Publish/Subscribe Model (发布/订阅模式),其中在 Publich/Subscribe 模式下又有持久化订阅和非持久化订阅两种消息处理方式。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">消息存储</code>:在实际应用中,重要的消息通常需要持久化到数据库或文件系统中,确保服务器崩溃时,信息不会丢失。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">Cluster(集群)</code>:最常见到集群方式包括 Network of Brokers 和 Master Slave。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">Monitor(监控)</code>:ActiveMQ 一般由 JMX 进行监控。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">默认配置下的 ActiveMQ 只适合学习而不适用于实际生产环境,ActiveMQ 的性能需要通过配置挖掘,其性能提高包括代码级性能、规则性能、存储性能、网络性能以及多节点协同方法(集群方案),所以我们优化 ActiveMQ 的中心思路也是这样的:</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 优化 ActiveMQ 单个节点性能,包括 NIO 模型选择和存储选择。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 配置 ActiveMQ 集群(ActiveMQ 的高性能和高可用需要通过集群表现出来)。 </section></li> </ol> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">在生产环境中,ActiveMQ 集群的部署方式主要有下面两种。</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Master Slave 模式:实现高可用,当主服务器宕机时,备用服务器可以升主,以保证服务的继续。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Broker Clusters 模式:实现负载均衡,多个 Broker 之间同步消息,以达到服务器负载的可能。 </section></li> </ul> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">ActiveMQ 高可用方案</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding: 0px 0.5em;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><img class="rich_pages wxw-img" data-ratio="0.4609375" src="/upload/91aece82a446fae129d6e33d27bb8aa8.jpg" data-type="jpeg" data-w="640" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;box-shadow: rgb(210, 210, 210) 0em 0em 0.5em 0px;font-size: 17px;">案</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">在生产环境中,高可用(High Availability,HA)可谓 “刚需”, ActiveMQ 的高可用性架构基于 Master/Slave 模型。ActiveMQ 总共提供了四种配置方案来配置 HA,其中 Shared Nothing Master/Slave 在 5.8 版本之后不再使用了,并在 ActiveMQ 5.9 版本中引入了基于 Zookeeper 的 Replicated LevelDB Store HA 方案。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">关于几种 HA 方案的详细介绍,读者可查看官网说明,在此,我仅做简单介绍。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-

40个SpringBoot常用注解:让生产力爆表!

作者:微信小助手

<section class="channels_iframe_wrp" data-mpa-powered-by="yiban.io"> <mpvideosnap class="js_uneditable custom_select_card channels_iframe videosnap_video_iframe" data-pluginname="videosnap" data-id="export/UzFfAgtgekIEAQAAAAAAjEQGtobUAAAAAAstQy6ubaLX4KHWvLEZgBPEyKI0EUk-G4j8zNPgMIuboStNG2fE4dn-13QvcMQL" data-url="https://findermp.video.qq.com/251/20304/stodownload?encfilekey=rjD5jyTuFrIpZ2ibE8T7YmwgiahniaXswqzLnDApDFPicLUYFQyMZGibqnl1bouAwflejO2rPfgnedQpM40VjKeeTvt94icBTCdyL1dPI3xicXTw7e9YFtwW4AwLQ&amp;adaptivelytrans=0&amp;bizid=1023&amp;dotrans=0&amp;hy=SH&amp;idx=1&amp;m=&amp;scene=0&amp;token=x5Y29zUxcibCDyujicq6hV2t16DX7Ee2bJuksAjOYboadjY1GEzZqOEoYic7vcClo3HzepLq09N13s" data-headimgurl="http://wx.qlogo.cn/finderhead/Q3auHgzwzM5nv7YHhmhvPsGGX04JCIgibK2x2Ru0TOY9HeZTGSIL1KQ/0" data-username="v2_060000231003b20faec8c5e08a1fc3d5c807ec30b07756771265bc6b6234fb9e05062ae69ab4@finder" data-nickname="儒猿IT" data-desc="一步一步带大家理解SpringCloudAlibaba都包含哪些技术组件,在系统里都是用来干什么的,以及这些技术底层的原理。#SpringCloud #SpringCloudAlibaba #Dubbo #Java面试 @微信时刻 " data-nonceid="17087319968872828207" data-type="video" data-width="2048" data-height="1080"></mpvideosnap> </section> <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="outline: 0px;max-width: 100%;color: rgb(34, 34, 34);font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: right;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="color: rgb(178, 178, 178);letter-spacing: 0.544px;font-size: 13px;font-family: Optima-Regular, PingFangTC-light;">来源:cnblogs.com/mask-xiexie/p/16017230.html</span></p> <p style="margin-bottom: 8px;"><span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;"><strong>目录</strong></span></p> <ul class="list-paddingleft-1" style="outline: 0px;color: rgb(34, 34, 34);font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);visibility: visible;"> <li style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;font-weight: bold;"><p style="margin-bottom: 8px;"><span style="font-family: Optima-Regular, PingFangTC-light;"><strong><span style="font-size: 15px;">Spring Web MVC注解</span></strong></span></p></li> <li style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;font-weight: bold;"><p style="margin-bottom: 8px;"><span style="font-family: Optima-Regular, PingFangTC-light;"><strong><span style="font-size: 15px;">Spring Bean 注解</span></strong></span></p></li> <li style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;font-weight: bold;"><p style="margin-bottom: 8px;"><span style="font-family: Optima-Regular, PingFangTC-light;"><strong><span style="font-size: 15px;">Spring Dependency Inject</span></strong></span></p></li> <li style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;font-weight: bold;"><p style="margin-bottom: 8px;"><span style="font-family: Optima-Regular, PingFangTC-light;"><strong><span style="font-size: 15px;">总 结</span></strong></span></p></li> </ul> <section style="outline: 0px;color: rgb(34, 34, 34);font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;visibility: visible;"> <section powered-by="xiumi.us" style="outline: 0px;visibility: visible;"> <section style="margin-top: 10px;margin-bottom: 10px;outline: 0px;text-align: justify;justify-content: center;display: flex;flex-flow: row nowrap;visibility: visible;"> <section style="outl

Spring Boot 日期时间处理总结,写的太好了,建议收藏!

作者:微信小助手

<section data-mpa-powered-by="yiban.io"> <br> </section> <section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzA5MTU0OTY0Ng==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/zc3KLDBfJlmPt0J5PXYOoiaG8wsQPZrLevbxMZSfgQ0YypNYaicnbS0P9UicluuOySLSP4CjTcRUVHCZzYeXQ9WlA/0?wx_fmt=png" data-nickname="Java派" data-alias="javapai" data-signature="专注Java相关技术栈:Spring全家筒、Docker、k8s、Mysql、集群、微服务、中间件等知识。" data-from="0"></mpprofile> </section> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="padding-right: 10px;padding-left: 10px;line-height: 1.6;word-break: break-word;text-align: left;font-size: 15px;letter-spacing: 0.05em;color: rgb(89, 89, 89);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;"> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><span style="font-size: 13px;color: rgb(136, 136, 136);">来源:juejin.im/post/5e62817fe51d4526d05962a2</span></p> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-bottom: none;font-size: 0.9em;overflow: auto;padding: 10px 10px 10px 20px;margin: 10px 5px;border-left-color: rgb(53, 179, 120);border-right: 0px solid rgb(53, 179, 120);color: rgb(97, 97, 97);quotes: none;background: rgb(251, 249, 253);"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">项目中使用LocalDateTime系列作为DTO中时间的数据类型,但是SpringMVC收到参数后总报错,为了配置全局时间类型转换,尝试了如下处理方式。</p> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;"><strong style="color: rgb(53, 179, 120);">注:本文基于Springboot2.x测试,如果无法生效可能是spring版本较低导致的。</strong>Spring Boot 基础就不介绍了,推荐下这个实战教程:https://github.com/javastacks/spring-boot-best-practice</p> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;"><strong style="color: rgb(53, 179, 120);">PS:如果你的Controller中的LocalDate类型的参数啥注解(RequestParam、PathVariable等)都没加,也是会出错的,因为默认情况下,解析这种参数是使用<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">ModelAttributeMethodProcessor</code>进行处理,而这个处理器要通过反射实例化一个对象出来,然后再对对象中的各个参数进行convert,但是LocalDate类没有构造函数,无法反射实例化因此会报错!!!</strong></p> </blockquote> <h2 data-tool="mdnice编辑器" style="line-height: 32px;color: rgb(53, 179, 120);display: inline-block;border-bottom: 0px solid rgb(53, 179, 120);border-top-color: rgb(53, 179, 120);border-right-color: rgb(53, 179, 120);border-left-color: rgb(53, 179, 120);font-size: 23px;margin-top: 1em;margin-bottom: 0rem;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;">完成目标</h2> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-1"> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 请求入参为 String(指定格式)转 Date,支持get、post(content-type=application/json) </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 返回数据为Date类型转为指定的日期时间格式字符创 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 支持Java8 日期 API,如: <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">LocalTime</code>、 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">localDate</code> 和 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">LocalDateTime</code> </section></li> </ul> <h2 data-tool="mdnice编辑器" style="line-height: 32px;color: rgb(53, 179, 120);display: inline-block;border-bottom: 0px solid rgb(53, 179, 120);border-top-color: rgb(53, 179, 120);border-right-color: rgb(53, 179, 120);border-left-color: rgb(53, 179, 120);font-size: 23px;margin-top: 1em;margin-bottom: 0rem;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;">GET请求及POST表单日期时间字符串格式转换</h2> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-bottom: none;font-size: 0.9em;overflow: auto;padding: 10px 10px 10px 20px;margin: 10px 5px;border-left-color: rgb(53, 179, 120);border-right: 0px solid rgb(53, 179, 120);color: rgb(97, 97, 97);quotes: none;background: rgb(251, 249, 253);"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">这种情况要和时间作为Json字符串时区别对待,因为前端json转后端pojo底层使用的是Json序列化Jackson工具(<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">HttpMessgeConverter</code>);而时间字符串作为普通请求参数传入时,转换用的是<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">Converter</code>,两者在处理方式上是有区别。</p> </blockquote> <h3 data-tool="mdnice编辑器" style="font-size: 20px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(53, 179, 120);">使用自定义参数转换器(Converter)</h3> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzUyNDc0NjM0Nw==&amp;mid=2247492574&amp;idx=2&amp;sn=f27a39ad8bf4540785d08d7d4be889df&amp;chksm=fa2a08dacd5d81cc3b043fcf01b6b0d9f12e0ed43f02a97c0941c5d325d989c6af5fb0276dc7&amp;scene=21#wechat_redirect" textvalue="实现 org.springframework.core.convert.converter.Converter,自定义参数转换器,如下:@Configurationpublic&nbsp;class&nbsp;DateConverterConfig&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;@Bean&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;Converter<String,&nbsp;LocalDate>&nbsp;localDateConverter()&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;Converter<String,&nbsp;LocalDate>()&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;LocalDate&nbsp;convert(String&nbsp;source)&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;LocalDate.parse(source,&nbsp;DateTimeFormatter.ofPattern('yyyy-MM-dd'));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;@Bean&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;Converter<String,&nbsp;LocalDateTime>&nbsp;localDateTimeConverter()&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;Converter<String,&nbsp;LocalDateTime>()&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;LocalDateTime&nbsp;convert(String&nbsp;source)&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;LocalDateTime.parse(source,&nbsp;DateTimeFormatter.ofPattern('yyyy-MM-dd&nbsp;HH:mm:ss'));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};&nbsp;&nbsp;&nbsp;&nbsp;}}点评:以上两个bean会注入到spring mvc的参数解析器" linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" style="color: rgb(58, 58, 58);" data-linktype="2">实现 org.springframework.core.convert.converter.Converter,自定义参数转换器,如下:</a></p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzUyNDc0NjM0Nw==&amp;mid=2247492574&amp;idx=2&amp;sn=f27a39ad8bf4540785d08d7d4be889df&amp;chksm=fa2a08dacd5d81cc3b043fcf01b6b0d9f12e0ed43f02a97c0941c5d325d989c6af5fb0276dc7&amp;scene=21#wechat_redirect" textvalue="实现 org.springframework.core.convert.converter.Converter,自定义参数转换器,如下:@Configurationpublic&nbsp;class&nbsp;DateConverterConfig&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;@Bean&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;Converter<String,&nbsp;LocalDate>&nbsp;localDateConverter()&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;Converter<String,&nbsp;LocalDate>()&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;LocalDate&nbsp;convert(String&nbsp;source)&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;LocalDate.parse(source,&nbsp;DateTimeFormatter.ofPattern('yyyy-MM-dd'));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;@Bean&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;Converter<String,&nbsp;LocalDateTime>&nbsp;localDateTimeConverter()&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;Converter<String,&nbsp;LocalDateTime>()&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;LocalDateTime&nbsp;convert(String&nbsp;source)&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;LocalDateTime.parse(source,&nbsp;DateTimeFormatter.ofPattern('yyyy-MM-dd&nbsp;HH:mm:ss'));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};&nbsp;&nbsp;&nbsp;&nbsp;}}点评:以上两个bean会注入到spring mvc的参数解析器" linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" data-linktype="2"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">@Configuration<br>public&nbsp;class&nbsp;DateConverterConfig&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;@Bean<br>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;Converter&lt;String,&nbsp;LocalDate&gt;&nbsp;<span style="color: rgb(97, 174, 238);line-height: 26px;">localDateConverter</span>()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #e6c07b;line-height: 26px;">return</span>&nbsp;new&nbsp;Converter&lt;String,&nbsp;LocalDate&gt;()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;LocalDate&nbsp;convert(String&nbsp;<span style="color: #e6c07b;line-height: 26px;">source</span>)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #e6c07b;line-height: 26px;">return</span>&nbsp;LocalDate.parse(<span style="color: #e6c07b;line-height: 26px;">source</span>,&nbsp;DateTimeFormatter.ofPattern(<span style="color: #98c379;line-height: 26px;">"yyyy-MM-dd"</span>));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;@Bean<br>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;Converter&lt;String,&nbsp;LocalDateTime&gt;&nbsp;<span style="color: rgb(97, 174, 238);line-height: 26px;">localDateTimeConverter</span>()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #e6c07b;line-height: 26px;">return</span>&nbsp;new&nbsp;Converter&lt;String,&nbsp;LocalDateTime&gt;()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;LocalDateTime&nbsp;convert(String&nbsp;<span style="color: #e6c07b;line-height: 26px;">source</span>)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #e6c07b;line-height: 26px;">return</span>&nbsp;LocalDateTime.parse(<span style="color: #e6c07b;line-height: 26px;">source</span>,&nbsp;DateTimeFormatter.ofPattern(<span style="color: #98c379;line-height: 26px;">"yyyy-MM-dd&nbsp;HH:mm:ss"</span>));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br></code></a></pre> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzUyNDc0NjM0Nw==&amp;mid=2247492574&amp;idx=2&amp;sn=f27a39ad8bf4540785d08d7d4be889df&amp;chksm=fa2a08dacd5d81cc3b043fcf01b6b0d9f12e0ed43f02a97c0941c5d325d989c6af5fb0276dc7&amp;scene=21#wechat_redirect" textvalue="实现 org.springframework.core.convert.converter.Converter,自定义参数转换器,如下:@Configurationpublic&nbsp;class&nbsp;DateConverterConfig&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;@Bean&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;Converter<String,&nbsp;LocalDate>&nbsp;localDateConverter()&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;Converter<String,&nbsp;LocalDate>()&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;LocalDate&nbsp;convert(String&nbsp;source)&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;LocalDate.parse(source,&nbsp;DateTimeFormatter.ofPattern('yyyy-MM-dd'));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;@Bean&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;Converter<String,&nbsp;LocalDateTime>&nbsp;localDateTimeConverter()&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;Converter<String,&nbsp;LocalDateTime>()&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;LocalDateTime&nbsp;convert(String&nbsp;source)&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;LocalDateTime.parse(source,&nbsp;DateTimeFormatter.ofPattern('yyyy-MM-dd&nbsp;HH:mm:ss'));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};&nbsp;&nbsp;&nbsp;&nbsp;}}点评:以上两个bean会注入到spring mvc的参数解析器" linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" style="color: rgb(58, 58, 58);" data-linktype="2">点评:以上两个bean会注入到spring mvc的参数解析器</a><span style="color: rgb(58, 58, 58);">(</span>好像叫做<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">ParameterConversionService</code>),当传入的字符串要转为LocalDateTime类时,spring会调用该Converter对这个入参进行转换。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><strong style="color: rgb(53, 179, 120);">注意:</strong><code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">关于自定义的参数转换器 Converter,这里我遇到了一个坑,我再这里详细记录下</code>,本来我的想法是为了代码精简,将上面匿名内部类的写法精简成lambda表达式的方式:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">&nbsp;&nbsp;&nbsp;&nbsp;@Bean<br>&nbsp;&nbsp;&nbsp;&nbsp;@ConditionalOnBean(name&nbsp;=&nbsp;<span style="color: #98c379;line-height: 26px;">"requestMappingHandlerAdapter"</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;Converter&lt;String,&nbsp;LocalDate&gt;&nbsp;<span style="color: rgb(97, 174, 238);line-height: 26px;">localDateConverter</span>()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #e6c07b;line-height: 26px;">return</span>&nbsp;<span style="color: #e6c07b;line-height: 26px;">source</span>&nbsp;-&gt;&nbsp;LocalDate.parse(<span style="color: #e6c07b;line-height: 26px;">source</span>,&nbsp;DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT));<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">当我再次启动项目时却出现了异常:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">Caused&nbsp;by:&nbsp;java.lang.IllegalArgumentException:&nbsp;Unable&nbsp;to&nbsp;determine&nbsp;<span style="color: #e6c07b;line-height: 26px;">source</span>&nbsp;<span style="color: #e6c07b;line-height:

微服务中使用阿里开源的TTL,优雅的实现身份信息的线程间复用

作者:微信小助手

<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="line-height: 1.6;word-break: break-word;text-align: left;padding: 5px;font-size: 16px;color: rgb(53, 53, 53);word-spacing: 0.8px;letter-spacing: 0.8px;border-radius: 16px;font-family: Roboto, Oxygen, Ubuntu, Cantarell, PingFangSC-light, PingFangTC-light, &quot;Open Sans&quot;, &quot;Helvetica Neue&quot;, sans-serif;" data-mpa-powered-by="yiban.io"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">前面在介绍分布式链路追踪时讲过异步调用会丢失链路信息,最终的解决方案是使用对应的包装类重新包装一下,如下:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">RunnableWrapper</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">CallableWrapper</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">SupplierWrapper</span> </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">还有openFeign异步请求丢失上文的问题,这些问题追根究底都是<span style="font-weight: 700;color: rgb(248, 57, 41);">ThreadLocal</span>惹得祸。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">由于ThreadLocal只能保存当前线程的信息,不能实现父子线程的继承。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">说到这,很多人想到了<span style="font-weight: 700;color: rgb(248, 57, 41);">InheritableThreadLocal</span>,确实InheritableThreadLocal能够实现父子线程间传递本地变量,但是.....</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">但是你的程序如果采用线程池,则存在着线程复用的情况,这时就不一定能够实现父子线程间传递了,因为在线程在线程池中的存在不是每次使用都会进行创建,<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">InheritableThreadlocal</code>是在线程初始化时<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">intertableThreadLocals=true</code>才会进行拷贝传递。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">所以若本次使用的子线程是已经被池化的线程,从线程池中取出线下进行使用,是没有经过初始化的过程,也就不会进行父子线程的本地变量拷贝。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">由于在日常应用场景中,绝大多数都是会采用线程池的方式进行资源的有效管理。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">今天就来聊一聊阿里的<span style="font-weight: 700;color: rgb(248, 57, 41);">ThansmittableThreadLocal</span>是如何解决线程池中父子线程本地变量传递。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><strong style="color: rgb(255, 41, 65);font-family: Roboto, Oxygen, Ubuntu, Cantarell, PingFangSC-light, PingFangTC-light, &quot;Open Sans&quot;, &quot;Helvetica Neue&quot;, sans-serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;white-space: normal;word-spacing: 0.8px;">B站链接:https://b23.tv/RI06iZl</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="color: rgb(255, 41, 65);"><strong mpa-from-tpl="t" style="outline: 0px;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;word-spacing: 0.8px;background-color: rgb(255, 255, 255);letter-spacing: 0.544px;text-size-adjust: auto;color: rgb(73, 73, 73);font-size: 14.6667px;text-align: center;visibility: visible;"><span style="letter-spacing: 0.544px;color: rgb(255, 41, 65);outline: 0px;visibility: visible;">下方是本篇文章视频教程,讲解更加详细!<span style="letter-spacing: 0.544px;color: rgb(255, 41, 65);outline: 0px;visibility: visible;"><img class="__bg_gif rich_pages wxw-img" data-ratio="1.5925925925925926" src="/upload/f7ea01370aaef1656a1805dd28a0f8b1.png" data-type="gif" data-w="135" style="outline: 0px;font-size: 17px;line-height: 27.2px;letter-spacing: 1px;box-sizing: border-box !important;visibility: visible !important;width: 21px !important;"></span></span></strong></span></p> <section> <iframe class="video_iframe rich_pages" data-vidtype="2" data-mpvid="wxv_2424301428933722116" data-cover="http%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2F19cc2hfD2rCyOQzgYD6L5PcRRtkcbEJ67ecmuJ3QSTGAoOAdhOSAZZEnbsRpwdnkrjnEHIdmarOdZIgRVol10Q%2F0%3Fwx_fmt%3Djpeg" allowfullscreen frameborder="0" data-ratio="1.7777777777777777" data-w="1920" style="border-radius: 4px;" src="https://mp.weixin.qq.com/mp/readtemplate?t=pages/video_player_tmpl&amp;action=mpvideo&amp;auto=0&amp;vid=wxv_2424301428933722116"></iframe> </section> <section> <br> </section> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="line-height: 1.6;word-break: break-word;text-align: left;padding: 5px;font-size: 16px;color: rgb(53, 53, 53);word-spacing: 0.8px;letter-spacing: 0.8px;border-radius: 16px;font-family: Roboto, Oxygen, Ubuntu, Cantarell, PingFangSC-light, PingFangTC-light, &quot;Open Sans&quot;, &quot;Helvetica Neue&quot;, sans-serif;"> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 15px;padding-right: 10px;padding-bottom: 15px;line-height: 1.75;border-radius: 13px;color: rgb(53, 53, 53);background: rgb(245, 245, 245);"> <span style="display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">“</span> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;font-size: 16px;margin-right: 10px;margin-left: 10px;"><span style="font-weight: 700;color: rgb(248, 57, 41);">帅气的人都点赞了~</span></p> <span style="float: right;display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">”</span> </blockquote> </section> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">InheritableThreadLocal 的问题</span><br></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">在介绍<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">ThansmittableThreadLocal</code>之前先来看一下<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">InheritableThreadLocal </code>在线程池中的问题,如下代码:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oexqmcDw0weKQcAVzy0RhPISC2cQglodtwgEzQ89De8HMoCx9A4jbdrprjMPO8R7QIhC2ywI7yKmKiaZVjNeRrmLf/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(250, 250, 250);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #383a42;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fafafa;border-radius: 5px;"><span style="color: #4078f2;line-height: 26px;">@Test</span><br><span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">public</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">void</span>&nbsp;<span style="color: #4078f2;line-height: 26px;">test</span><span style="line-height: 26px;">()</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">throws</span>&nbsp;Exception&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a0a1a7;font-style: italic;line-height: 26px;">//单一线程池</span><br>&nbsp;&nbsp;&nbsp;&nbsp;ExecutorService&nbsp;executorService&nbsp;=&nbsp;Executors.newSingleThreadExecutor();<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a0a1a7;font-style: italic;line-height: 26px;">//InheritableThreadLocal存储</span><br>&nbsp;&nbsp;&nbsp;&nbsp;InheritableThreadLocal&lt;String&gt;&nbsp;username&nbsp;=&nbsp;<span style="color: #a626a4;line-height: 26px;">new</span>&nbsp;InheritableThreadLocal&lt;&gt;();<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a626a4;line-height: 26px;">for</span>&nbsp;(<span style="color: #a626a4;line-height: 26px;">int</span>&nbsp;i&nbsp;=&nbsp;<span style="color: #986801;line-height: 26px;">0</span>;&nbsp;i&nbsp;&lt;&nbsp;<span style="color: #986801;line-height: 26px;">10</span>;&nbsp;i++)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;username.set(<span style="color: #50a14f;line-height: 26px;">"公众号:码猿技术专栏—"</span>+i);<br>&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(<span style="color: #986801;line-height: 26px;">3000</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;CompletableFuture.runAsync(()-&gt;&nbsp;System.out.println(username.get()),executorService);<br>&nbsp;&nbsp;&nbsp;}<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">上述代码中创建了一个单一线程池,循环异步调用,打印一下username,由于核心线程数是1,势必存在线程的复用。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">打印信息如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oexqmcDw0weKQcAVzy0RhPISC2cQglodtwgEzQ89De8HMoCx9A4jbdrprjMPO8R7QIhC2ywI7yKmKiaZVjNeRrmLf/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(250, 250, 250);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #383a42;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fafafa;border-radius: 5px;">公众号:码猿技术专栏—<span style="color: #986801;line-height: 26px;">0</span><br>公众号:码猿技术专栏—<span style="color: #986801;line-height: 26px;">0</span><br>公众号:码猿技术专栏—<span style="color: #986801;line-height: 26px;">0</span><br>公众号:码猿技术专栏—<span style="color: #986801;line-height: 26px;">0</span><br>公众号:码猿技术专栏—<span style="color: #986801;line-height: 26px;">0</span><br>公众号:码猿技术专栏—<span style="color: #986801;line-height: 26px;">0</span><br>公众号:码猿技术专栏—<span style="color: #986801;line-height: 26px;">0</span><br>公众号:码猿技术专栏—<span style="color: #986801;line-height: 26px;">0</span><br>公众号:码猿技术专栏—<span style="color: #986801;line-height: 26px;">0</span><br>公众号:码猿技术专栏—<span style="color: #986801;line-height: 26px;">0</span><br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">看到了吗?这里并没有实现父子线程间的变量传递,这也就是InheritableThreadLocal 的局限性。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">TransmittableThreadLocal 使用</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">TransmittableThreadLocal</code>(<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">TTL</code>):在使用线程池等会池化复用线程的执行组件情况下,提供<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">ThreadLocal</code>值的传递功能,解决异步执行时上下文传递的问题。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">整个<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">TransmittableThreadLocal</code>库的核心功能(用户<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">API</code>与框架/中间件的集成<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">API</code>、线程池<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">ExecutorService</code>/<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">ForkJoinPool</code>/<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">TimerTask</code>及其线程工厂的<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">Wrapper</code>)。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">需求场景</span>:</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 分布式跟踪系统 或 全链路压测(即链路打标) </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 日志收集记录系统上下文 </section></li> </ol> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 15px;padding-right: 10px;padding-bottom: 15px;line-height: 1.75;border-radius: 13px;color: rgb(53, 53, 53);background: rgb(245, 245, 245);"> <span style="display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">“</span> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;font-size: 16px;margin-right: 10px;margin-left: 10px;">官网地址:https://github.com/alibaba/transmittable-thread-local</p> <span style="float: right;display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">”</span> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">下面就以上面的例子改造成<span style="font-weight: 700;color: rgb(248, 57, 41);">TransmittableThreadLocal</span>试一下效果。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">首选需要引入对应的依赖,如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oexqmcDw0weKQcAVzy0RhPISC2cQglodtwgEzQ89De8HMoCx9A4jbdrprjMPO8R7QIhC2ywI7yKmKiaZVjNeRrmLf/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(250, 250, 250);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #383a42;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fafafa;border-radius: 5px;"><span style="line-height: 26px;">&lt;<span style="color: #e45649;line-height: 26px;">dependency</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e45649;line-height: 26px;">groupId</span>&gt;</span>com.alibaba<span style="line-height: 26px;">&lt;/<span style="color: #e45649;line-height: 26px;">groupId</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e45649;line-height: 26px;">artifactId</span>&gt;</span>transmittable-thread-local<span style="line-height: 26px;">&lt;/<span style="color: #e45649;line-height: 26px;">artifactId</span>&gt;</span><br><span style="line-height: 26px;">&lt;/<span style="color: #e45649;line-height: 26px;">dependency

盘点MySQL慢查询的12个原因

作者:微信小助手

<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">日常开发中,我们经常会遇到<strong style="font-weight: border;color: #0e88eb;">数据库慢查询</strong> 。那么导致数据慢查询都有哪些常见的原因呢?今天田螺哥就跟大家聊聊导致MySQL慢查询的12个常见原因,以及对应的解决方法。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-family: STHeitiSC-Light;color: rgb(14, 136, 235);font-weight: bolder;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(14, 136, 235);"><a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;scene=21#wechat_redirect" style="color: rgb(14, 136, 235);border-bottom: 0px solid rgb(255, 53, 2);" data-linktype="2">1. SQL没加索引</a></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">很多时候,我们的慢查询,都是因为<strong style="font-weight: border;color: #0e88eb;">没有加索引</strong> 。如果没有加索引的话,会导致全表扫描的。因此,应考虑在<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">where</code>的条件列,<strong style="font-weight: border;color: #0e88eb;">建立索引</strong> ,尽量避免全表扫描。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><strong style="font-weight: border;color: #0e88eb;">反例:</strong></p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/hzVGicX27IG2kREVLZKwAStcgicmt6cEicVs6NxtecqXBu0vaibqJWWTzRtkRVwFum8Af1gQoPtzV2arZZnvaLVL2JeV1WN2Okmd/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(30, 30, 30);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #DCDCDC;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #1E1E1E;border-radius: 5px;">select&nbsp;*&nbsp;from&nbsp;user_info&nbsp;where&nbsp;name&nbsp;=<span style="color: #D69D85;line-height: 26px;">'捡田螺的小男孩'</span>&nbsp;;<br></code></pre> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;scene=21#wechat_redirect" textvalue="你已选中了添加链接的内容" linktype="text" imgurl="" imgdata="null" tab="innerlink" data-linktype="1"><span class="js_jump_icon h5_image_link" data-positionback="static" style="top: auto;left: auto;margin: 20px 41.8542px;right: auto;bottom: auto;"><img class="rich_pages wxw-img" data-ratio="0.2212962962962963" src="/upload/a82ffb26d5ceadc3619b57b08f322482.png" data-type="png" data-w="1080" style="border-radius: 0px 0px 5px 5px;display: block;margin: 0px;width: 85%;height: 100%;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;"></span></a> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><strong style="font-weight: border;color: #0e88eb;">正例:</strong></p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/hzVGicX27IG2kREVLZKwAStcgicmt6cEicVs6NxtecqXBu0vaibqJWWTzRtkRVwFum8Af1gQoPtzV2arZZnvaLVL2JeV1WN2Okmd/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(30, 30, 30);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #DCDCDC;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #1E1E1E;border-radius: 5px;"><span style="color: #57A64A;font-style: italic;line-height: 26px;">//添加索引</span><br><span style="line-height: 26px;">alter&nbsp;table&nbsp;user_info&nbsp;add&nbsp;index&nbsp;<span style="line-height: 26px;">idx_name</span>&nbsp;<span style="line-height: 26px;">(name)</span></span>;<br></code></pre> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;scene=21#wechat_redirect" textvalue="你已选中了添加链接的内容" linktype="text" imgurl="" imgdata="null" tab="innerlink" data-linktype="1"><span class="js_jump_icon h5_image_link" data-positionback="static" style="top: auto;left: auto;margin: 20px 41.8542px;right: auto;bottom: auto;"><img class="rich_pages wxw-img" data-ratio="0.20185185185185187" src="/upload/d6616bdc9e8565d46eaf1462abde3e73.png" data-type="png" data-w="1080" style="border-radius: 0px 0px 5px 5px;display: block;margin: 0px;width: 85%;height: 100%;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;"></span></a> </figure> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 10px;padding-right: 10px;padding-bottom: 10px;line-height: 1.8;border-radius: 0px 0px 10px 10px;color: rgb(14, 136, 235);background: rgb(255, 255, 255);box-shadow: rgb(132, 161, 168) 0px 10px 15px;"> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.2em;word-spacing: 0.1em;line-height: 26px;font-size: 15px;">基于 Spring Boot + MyBatis Plus + Vue &amp; Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能。</p> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.2em;word-spacing: 0.1em;line-height: 26px;font-size: 15px;">项目地址:https://github.com/YunaiV/ruoyi-vue-pro</p> </blockquote> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-family: STHeitiSC-Light;color: rgb(14, 136, 235);font-weight: bolder;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(14, 136, 235);"><a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;scene=21#wechat_redirect" style="color: rgb(14, 136, 235);border-bottom: 0px solid rgb(255, 53, 2);" data-linktype="2">2. SQL 索引不生效</a></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">有时候我们明明加了索引了,但是索引却不生效。在哪些场景,索引会不生效呢?主要有以下十大经典场景:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;scene=21#wechat_redirect" textvalue="你已选中了添加链接的内容" linktype="text" imgurl="" imgdata="null" tab="innerlink" data-linktype="1"><span class="js_jump_icon h5_image_link" data-positionback="static" style="top: auto;left: auto;margin: 20px 0px;right: auto;bottom: auto;"><img class="rich_pages wxw-img" src="/upload/12b14d455dd7c614c715847111dd0923.png" data-cropx1="455.6962025316456" data-cropx2="1080" data-cropy1="0" data-cropy2="774.6835443037975" data-ratio="1.2384" src="https://mmbiz.qpic.cn/mmbiz_jpg/JdLkEI9sZffSk33LibOoDLJ052pM7fSPJOEAQ6YIGxpgsUxwaiaoDtp8r2ZSlKuIF5uuoxERVCVibLPnkYzaiaVZlA/640?wx_fmt=jpeg" data-type="jpeg" data-w="625" style="border-radius: 0px 0px 5px 5px;display: block;margin: 0px;width: 274px;height: 340px;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;"></span></a> </figure> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span><a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;scene=21#wechat_redirect" style="color: rgb(14, 136, 235);border-bottom: 0px solid rgb(255, 53, 2);font-family: STHeitiSC-Light;" data-linktype="2">2.1 隐式的类型转换,索引失效</a><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">我们创建一个用户user表</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/hzVGicX27IG2kREVLZKwAStcgicmt6cEicVs6NxtecqXBu0vaibqJWWTzRtkRVwFum8Af1gQoPtzV2arZZnvaLVL2JeV1WN2Okmd/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(30, 30, 30);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #DCDCDC;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #1E1E1E;border-radius: 5px;"><span style="color: #569CD6;line-height: 26px;">CREATE</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">TABLE</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">user</span>&nbsp;(<br>&nbsp;&nbsp;<span style="color: #569CD6;line-height: 26px;">id</span>&nbsp;<span style="color: #4EC9B0;line-height: 26px;">int</span>(<span style="color: #B8D7A3;line-height: 26px;">11</span>)&nbsp;<span style="color: #569CD6;line-height: 26px;">NOT</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">NULL</span>&nbsp;AUTO_INCREMENT,<br>&nbsp;&nbsp;userId&nbsp;<span style="color: #4EC9B0;line-height: 26px;">varchar</span>(<span style="color: #B8D7A3;line-height: 26px;">32</span>)&nbsp;<span style="color: #569CD6;line-height: 26px;">NOT</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">NULL</span>,<br>&nbsp;&nbsp;age&nbsp;&nbsp;<span style="color: #4EC9B0;line-height: 26px;">varchar</span>(<span style="color: #B8D7A3;line-height: 26px;">16</span>)&nbsp;<span style="color: #569CD6;line-height: 26px;">NOT</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">NULL</span>,<br>&nbsp;&nbsp;<span style="color: #569CD6;line-height: 26px;">name</span>&nbsp;<span style="color: #4EC9B0;line-height: 26px;">varchar</span>(<span style="color: #B8D7A3;line-height: 26px;">255</span>)&nbsp;<span style="color: #569CD6;line-height: 26px;">NOT</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">NULL</span>,<br>&nbsp;&nbsp;PRIMARY&nbsp;<span style="color: #569CD6;line-height: 26px;">KEY</span>&nbsp;(<span style="color: #569CD6;line-height: 26px;">id</span>),<br>&nbsp;&nbsp;<span style="color: #569CD6;line-height: 26px;">KEY</span>&nbsp;idx_userid&nbsp;(userId)&nbsp;<span style="color: #569CD6;line-height: 26px;">USING</span>&nbsp;BTREE<br>)&nbsp;<span style="color: #569CD6;line-height: 26px;">ENGINE</span>=<span style="color: #569CD6;line-height: 26px;">InnoDB</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">DEFAULT</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">CHARSET</span>=utf8;<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">userId</code>字段为<strong style="font-weight: border;color: #0e88eb;">字串类型</strong> ,是B+树的普通索引,如果查询条件传了一个<strong style="font-weight: border;color: #0e88eb;">数字</strong> 过去,会导致索引失效。如下:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;scene=21#wechat_redirect" textvalue="你已选中了添加链接的内容" linktype="text" imgurl="" imgdata="null" tab="innerlink" data-linktype="1"><span class="js_jump_icon h5_image_link" data-positionback="static" style="top: auto;left: auto;margin: 20px 41.8542px;right: auto;bottom: auto;"><img class="rich_pages wxw-img" data-ratio="0.20185185185185187" src="/upload/9df1bcccf57df121e1d623ab7ed42893.png" data-type="png" data-w="1080" style="border-radius: 0px 0px 5px 5px;display: block;margin: 0px;width: 85%;height: 100%;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;"></span></a> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">如果给数字加上<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">''</code>,也就是说,传的是一个字符串呢,<strong style="font-weight: border;color: #0e88eb;">当然是走索引</strong> ,如下图:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;scene=21#wechat_redirect" textvalue="你已选中了添加链接的内容" linktype="text" imgurl="" imgdata="null" tab="innerlink" data-linktype="1"><span class="js_jump_icon h5_image_link" data-positionback="static" style="top: auto;left: auto;margin: 20px 41.8542px;right: auto;bottom: auto;"><img class="rich_pages wxw-img" data-ratio="0.18518518518518517" src="/upload/8dcb37c99d8c6f178a34155eefcdc523.png" data-type="png" data-w="1080" style="border-radius: 0px 0px 5px 5px;display: block;margin: 0px;width: 85%;height: 100%;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;"></span></a> </figure> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 10px;padding-right: 10px;padding-bottom: 10px;line-height: 1.8;border-radius: 0px 0px 10px 10px;color: rgb(14, 136, 235);background: rgb(255, 255, 255);box-shadow: rgb(132, 161, 168) 0px 10px 15px;"> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.2em;word-spacing: 0.1em;line-height: 26px;font-size: 15px;">为什么第一条语句<strong>未加单引号就不走索引</strong> 了呢?这是因为不加单引号时,是字符串跟数字的比较,它们类型不匹配,MySQL会做<strong>隐式的类型转换</strong> ,把它们转换为浮点数再做比较。隐式的类型转换,索引会失效。</p> </blockquote> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span><a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;scene=21#wechat_redirect" style="color: rgb(14, 136, 235);border-bottom: 0px solid rgb(255, 53, 2);font-family: STHeitiSC-Light;" data-linktype="2">2.2 查询条件包含or,可能导致索引失效</a><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">我们还是用这个表结构:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/hzVGicX27IG2kREVLZKwAStcgicmt6cEicVs6NxtecqXBu0vaibqJWWTzRtkRVwFum8Af1gQoPtzV2arZZnvaLVL2JeV1WN2Okmd/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(30, 30, 30);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #DCDCDC;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #1E1E1E;border-radius: 5px;"><span style="line-height: 26px;">CREATE&nbsp;TABLE&nbsp;<span style="line-height: 26px;">user</span>&nbsp;<span style="line-height: 26px;">(<br>&nbsp;&nbsp;id&nbsp;<span style="color: #569CD6;line-height: 26px;">int</span>(<span style="color: #B8D7A3;line-height: 26px;">11</span>)</span>&nbsp;NOT&nbsp;NULL&nbsp;AUTO_INCREMENT,<br>&nbsp;&nbsp;userId&nbsp;<span style="line-height: 26px;">varchar</span><span style="line-height: 26px;">(<span style="color: #B8D7A3;line-height: 26px;">32</span>)</span>&nbsp;NOT&nbsp;NULL,<br>&nbsp;&nbsp;age&nbsp;&nbsp;<span style="line-height: 26px;">varchar</span><span style="line-height: 26px;">(<span style="color: #B8D7A3;line-height: 26px;">16</span>)</span>&nbsp;NOT&nbsp;NULL,<br>&nbsp;&nbsp;name&nbsp;<span style="line-height: 26px;">varchar</span><span style="line-height: 26px;">(<span style="color: #B8D7A3;line-height: 26px;">255</span>)</span>&nbsp;NOT&nbsp;NULL,<br>&nbsp;&nbsp;PRIMARY&nbsp;<span style="line-height: 26px;">KEY</span>&nbsp;<span style="line-height: 26px;">(id)</span>,<br>&nbsp;&nbsp;KEY&nbsp;<span style="line-height: 26px;">idx_userid</span>&nbsp;<span style="line-height: 26px;">(userId)</span>&nbsp;USING&nbsp;BTREE<br>)&nbsp;ENGINE</span>=InnoDB&nbsp;DEFAULT&nbsp;CHARSET=utf8;<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">其中<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">userId</code>加了索引,但是<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">age</code>没有加索引的。我们使用了<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">or</code>,以下SQL是不走索引的,如下:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;scene=21#wechat_redirect" textvalue="你已选中了添加链接的内容" linktype="text" imgurl="" imgdata="null" tab="innerlink" data-linktype="1"><span class="js_jump_icon h5_image_link" data-positionback="static" style="top: auto;left: auto;margin: 20px 41.8542px;right: auto;bottom: auto;"><img class="rich_pages wxw-img" data-ratio="0.19166666666666668" src="/upload/146e0b779f409119b5628c1c41461fb0.png" data-type="png" data-w="1080" style="border-radius: 0px 0px 5px 5px;display: block;margin: 0px;width: 85%;height: 100%;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;"></span></a> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">对于<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">or</code>+没有索引的<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">age</code>这种情况,假设它走了<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">userId</code>的索引,但是走到<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">age</code>查询条件时,它还得全表扫描,也就是需要三步过程:<strong style="font-weight: border;color: #0e88eb;">全表扫描+索引扫描+合并</strong> 。如果它一开始就走<strong style="font-weight: border;color: #0e88eb;">全表扫描</strong> ,直接一遍扫描就完事。Mysql优化器出于效率与成本考虑,遇到<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">or</code>条件,让索引失效,看起来也合情合理嘛。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><strong style="font-weight: border;color: #0e88eb;">注意</strong> :如果<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">or</code>条件的列都加了索引,<strong style="font-weight: border;color: #0e88eb;">索引可能会走也可能不走</strong> ,大家可以自己试一试哈。但是平时大家使用的时候,还是要注意一下这个<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">or</code>,学会用<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">explain</code>分析。遇到不走索引的时候,考虑拆开两条SQL。</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span><a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;scene=21#wechat_redirect" style="color: rgb(14, 136, 235);border-bottom: 0px solid rgb(255, 53, 2);font-family: STHeitiSC-Light;" data-linktype="2">2.3. like通配符可能导致索引失效。</a><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">并不是用了<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">like</code>通配符,索引一定会失效,而是like查询是以<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">%</code>开头,才会导致索引失效。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">like查询以<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">%</code>开头,索引失效</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/hzVGicX27IG2kREVLZKwAStcgicmt6cEicVs6NxtecqXBu0vaibqJWWTzRtkRVwFum8Af1gQoPtzV2arZZnvaLVL2JeV1WN2Okmd/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(30, 30, 30);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #DCDCDC;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #1E1E1E;border-radius: 5px;"><span style="color: #569CD6;line-height: 26px;">explain</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">select</span>&nbsp;*&nbsp;<span style="color: #569CD6;line-height: 26px;">from</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">user</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">where</span>&nbsp;userId&nbsp;<span style="color: #569CD6;line-height: 26px;">like</span>&nbsp;<span style="color: #D69D85;line-height: 26px;">'%123'</span>;<br></code></pre> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;scene=21#wechat_redirect" textvalue="你已选中了添加链接的内容" linktype="text" imgurl="" imgdata="null" tab="innerlink" data-linktype="1"><span class="js_jump_icon h5_image_link" data-positionback="static" style="top: auto;left: auto;margin: 20px 41.8542px;right: auto;bottom: auto;"><img class="rich_pages wxw-img" data-ratio="0.17314814814814813" src="/upload/b11126cc2a1e290001ee77cc559be4c4.png" data-type="png" data-w="1080" style="border-radius: 0px 0px 5px 5px;display: block;margin: 0px;width: 85%;height: 100%;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;"></span></a> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">把<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">%</code>放后面,发现索引还是正常走的,如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/hzVGicX27IG2kREVLZKwAStcgicmt6cEicVs6NxtecqXBu0vaibqJWWTzRtkRVwFum8Af1gQoPtzV2arZZnvaLVL2JeV1WN2Okmd/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(30, 30, 30);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #DCDCDC;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #1E1E1E;border-radius: 5px;"><span style="color: #569CD6;line-height: 26px;">explain</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">select</span>&nbsp;*&nbsp;<span style="color: #569CD6;line-height: 26px;">from</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">user</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">where</span>&nbsp;userId&nbsp;<span style="color: #569CD6;line-height: 26px;">like</span>&nbsp;<span style="color: #D69D85;line-height: 26px;">'123%'</span>;<br></code></pre> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;scene=21#wechat_redirect" textvalue="你已选中了添加链接的内容" linktype="text" imgurl="" imgdata="null" tab="innerlink" data-linktype="1"><span class="js_jump_icon h5_image_link" data-positionback="static" style="top: auto;left: auto;margin: 20px 41.8542px;right: auto;bottom: auto;"><img class="rich_pages wxw-img" data-ratio="0.15555555555555556" src="/upload/67e4b5f551fb342d261acc1ccc443498.png" data-type="png" data-w="1080" style="border-radius: 0px 0px 5px 5px;display: block;margin: 0px;width: 85%;height: 100%;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;"></span></a> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">既然<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">like</code>查询以<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">%</code>开头,会导致索引失效。我们如何优化呢?</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 使用覆盖索引 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 把 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">%</code>放后面 </section></li> </ul> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span><a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;scene=21#wechat_redirect" style="color: rgb(14, 136, 235);border-bottom: 0px solid rgb(255, 53, 2);font-family: STHeitiSC-Light;" data-linktype="2">2.4 查询条件不满足联合索引的最左匹配原则</a><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">MySQl建立联合索引时,会遵循最左前缀匹配的原则,即最左优先。如果你建立一个<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">(a,b,c)</code>的联合索引,相当于建立了<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">(a)、(a,b)、(a,b,c)</code>三个索引。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">假设有以下表结构:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/hzVGicX27IG2kREVLZKwAStcgicmt6cEicVs6NxtecqXBu0vaibqJWWTzRtkRVwFum8Af1gQoPtzV2arZZnvaLVL2JeV1WN2Okmd/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(30, 30, 30);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #DCDCDC;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #1E1E1E;border-radius: 5px;"><span style="color: #569CD6;line-height: 26px;">CREATE</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">TABLE</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">user</span>&nbsp;(<br>&nbsp;&nbsp;<span style="color: #569CD6;line-height: 26px;">id</span>&nbsp;<span style="color: #4EC9B0;line-height: 26px;">int</span>(<span style="color: #B8D7A3;line-height: 26px;">11</span>)&nbsp;<span style="color: #569CD6;line-height: 26px;">NOT</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">NULL</span>&nbsp;AUTO_INCREMENT,<br>&nbsp;&nbsp;user_id&nbsp;<span style="color: #4EC9B0;line-height: 26px;">varchar</span>(<span style="color: #B8D7A3;line-height: 26px;">32</span>)&nbsp;<span style="color: #569CD6;line-height: 26px;">NOT</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">NULL</span>,<br>&nbsp;&nbsp;age&nbsp;&nbsp;<span style="color: #4EC9B0;line-height: 26px;">varchar</span>(<span style="color: #B8D7A3;line-height: 26px;">16</span>)&nbsp;<span style="color: #569CD6;line-height: 26px;">NOT</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">NULL</span>,<br>&nbsp;&nbsp;<span style="color: #569CD6;line-height: 26px;">name</span>&nbsp;<span style="color: #4EC9B0;line-height: 26px;">varchar</span>(<span style="color: #B8D7A3;line-height: 26px;">255</span>)&nbsp;<span style="color: #569CD6;line-height: 26px;">NOT</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">NULL</span>,<br>&nbsp;&nbsp;PRIMARY&nbsp;<span style="color: #569CD6;line-height: 26px;">KEY</span>&nbsp;(<span style="color: #569CD6;line-height: 26px;">id</span>),<br>&nbsp;&nbsp;<span style="color: #569CD6;line-height: 26px;">KEY</span>&nbsp;idx_userid_name&nbsp;(user_id,<span style="color: #569CD6;line-height: 26px;">name</span>)&nbsp;<span style="color: #569CD6;line-height: 26px;">USING</span>&nbsp;BTREE<br>)&nbsp;<span style="color: #569CD6;line-height: 26px;">ENGINE</span>=<span style="color: #569CD6;line-height: 26px;">InnoDB</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">DEFAULT</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">CHARSET</span>=utf8;<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">有一个联合索引<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">idx_userid_name</code>,我们执行这个SQL,查询条件是<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">name</code>,索引是无效:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/hzVGicX27IG2kREVLZKwAStcgicmt6cEicVs6NxtecqXBu0vaibqJWWTzRtkRVwFum8Af1gQoPtzV2arZZnvaLVL2JeV1WN2Okmd/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(30, 30, 30);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #DCDCDC;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #1E1E1E;border-radius: 5px;">explain&nbsp;select&nbsp;*&nbsp;from&nbsp;user&nbsp;where&nbsp;name&nbsp;=<span style="color: #D69D85;line-height: 26px;">'捡田螺的小男孩'</span>;<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">因为查询条件列<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">name</code>不是联合索引<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">idx_userid_name</code>中的第一个列,索引不生效</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;scene=21#wechat_redirect" textvalue="你已选中了添加链接的内容" linktype="text" imgurl="" imgdata="null" tab="innerlink" data-linktype="1"><span class="js_jump_icon h5_image_link" data-positionback="static" style="top: auto;left: auto;margin: 20px 41.8542px;right: auto;bottom: auto;"><img class="rich_pages wxw-img" data-ratio="0.1685185185185185" src="/upload/32e1d74e8be344fb4dae63cc7187653f.png" data-type="png" data-w="1080" style="border-radius: 0px 0px 5px 5px;display: block;margin: 0px;width: 85%;height: 100%;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;"></span></a> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">在联合索引中,查询条件满足<strong style="font-weight: border;color: #0e88eb;">最左匹配原则</strong> 时,索引才正常生效。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;scene=21#wechat_redirect" textvalue="你已选中了添加链接的内容" linktype="text" imgurl="" imgdata="null" tab="innerlink" data-linktype="1"><span class="js_jump_icon h5_image_link" data-positionback="static" style="top: auto;left: auto;margin: 20px 41.8542px;right: auto;bottom: auto;"><img class="rich_pages wxw-img" data-ratio="0.20462962962962963" src="/upload/2b4720f6d6c541cea4ff0610596764a8.png" data-type="png" data-w="1080" style="border-radius: 0px 0px 5px 5px;display: block;margin: 0px;width: 85%;height: 100%;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;"></span></a> </figure> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span><a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;scene=21#wechat_redirect" style="color: rgb(14, 136, 235);border-bottom: 0px solid rgb(255, 53, 2);font-family: STHeitiSC-Light;" data-linktype="2">2.5 在索引列上使用mysql的内置函数</a><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">表结构:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/hzVGicX27IG2kREVLZKwAStcgicmt6cEicVs6NxtecqXBu0vaibqJWWTzRtkRVwFum8Af1gQoPtzV2arZZnvaLVL2JeV1WN2Okmd/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(30, 30, 30);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #DCDCDC;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #1E1E1E;border-radius: 5px;"><span style="color: #569CD6;line-height: 26px;">CREATE</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">TABLE</span>&nbsp;<span style="color: #D69D85;line-height: 26px;">`user`</span>&nbsp;(<br>&nbsp;&nbsp;<span style="color: #D69D85;line-height: 26px;">`id`</span>&nbsp;<span style="color: #4EC9B0;line-height: 26px;">int</span>(<span style="color: #B8D7A3;line-height: 26px;">11</span>)&nbsp;<span style="color: #569CD6;line-height: 26px;">NOT</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">NULL</span>&nbsp;AUTO_INCREMENT,<br>&nbsp;&nbsp;<span style="color: #D69D85;line-height: 26px;">`userId`</span>&nbsp;<span style="color: #4EC9B0;line-height: 26px;">varchar</span>(<span style="color: #B8D7A3;line-height: 26px;">32</span>)&nbsp;<span style="color: #569CD6;line-height: 26px;">NOT</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">NULL</span>,<br>&nbsp;&nbsp;<span style="color: #D69D85;line-height: 26px;">`login_time`</span>&nbsp;datetime&nbsp;<span style="color: #569CD6;line-height: 26px;">NOT</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">NULL</span>,<br>&nbsp;&nbsp;PRIMARY&nbsp;<span style="color: #569CD6;line-height: 26px;">KEY</span>&nbsp;(<span style="color: #D69D85;line-height: 26px;">`id`</span>),<br>&nbsp;&nbsp;<span style="color: #569CD6;line-height: 26px;">KEY</span>&nbsp;<span style="color: #D69D85;line-height: 26px;">`idx_userId`</span>&nbsp;(<span style="color: #D69D85;line-height: 26px;">`userId`</span>)&nbsp;<span style="color: #569CD6;line-height: 26px;">USING</span>&nbsp;BTREE,<br>&nbsp;&nbsp;<span style="color: #569CD6;line-height: 26px;">KEY</span>&nbsp;<span style="color: #D69D85;line-height: 26px;">`idx_login_time`</span>&nbsp;(<span style="color: #D69D85;line-height: 26px;">`login_Time`</span>)&nbsp;<span style="color: #569CD6;line-height: 26px;">USING</span>&nbsp;BTREE<br>)&nbsp;<span style="color: #569CD6;line-height: 26px;">ENGINE</span>=<span style="color: #569CD6;line-height: 26px;">InnoDB</span>&nbsp;AUTO_INCREMENT=<span style="color: #B8D7A3;line-height: 26px;">2</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">DEFAULT</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">CHARSET</span>=utf8;<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">虽然<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">login_time</code>加了索引,但是因为使用了<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">mysql</code>的内置函数<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Date_ADD()</code>,索引直接GG,如图:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;scene=21#wechat_redirect" textvalue="你已选中了添加链接的内容" linktype="text" imgurl="" imgdata="null" tab="innerlink" data-linktype="1"><span class="js_jump_icon h5_image_link" data-positionback="static" style="top: auto;left: auto;margin: 20px 41.8542px;right: auto;bottom: auto;"><img class="rich_pages wxw-img" data-ratio="0.17685185185185184" src="/upload/43bfe212e53f633bcef6a82ab263b36b.png" data-type="png" data-w="1080" style="border-radius: 0px 0px 5px 5px;display: block;margin: 0px;width: 85%;height: 100%;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;"></span></a> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">一般这种情况怎么优化呢?可以把<strong style="font-weight: border;color: #0e88eb;">内置函数的逻辑转移到右边</strong> ,如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/hzVGicX27IG2kREVLZKwAStcgicmt6cEicVs6NxtecqXBu0vaibqJWWTzRtkRVwFum8Af1gQoPtzV2arZZnvaLVL2JeV1WN2Okmd/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(30, 30, 30);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #DCDCDC;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #1E1E1E;border-radius: 5px;">explain&nbsp;&nbsp;select&nbsp;*&nbsp;from&nbsp;user&nbsp;where&nbsp;login_time&nbsp;=&nbsp;DATE_ADD(<span style="color: #D69D85;line-height: 26px;">'2022-05-22&nbsp;00:00:00'</span>,INTERVAL&nbsp;-<span style="color: #B8D7A3;line-height: 26px;">1</span>&nbsp;DAY);<br></code></pre> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;scene=21#wechat_redirect" textvalue="你已选中了添加链接的内容" linktype="text" imgurl="" imgdata="null" tab="innerlink" data-linktype="1"><span class="js_jump_icon h5_image_link" data-positionback="static" style="top: auto;left: auto;margin: 20px 41.8542px;right: auto;bottom: auto;"><img class="rich_pages wxw-img" data-ratio="0.1712962962962963" src="/upload/a0012f6bd0081b0ce55d0907162bffcb.png" data-type="png" data-w="1080" style="border-radius: 0px 0px 5px 5px;display: block;margin: 0px;width: 85%;height: 100%;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;"></span></a> </figure> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span><a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;scene=21#wechat_redirect" style="color: rgb(14, 136, 235);border-bottom: 0px solid rgb(255, 53, 2);font-family: STHeitiSC-Light;" data-linktype="2">2.6 对索引进行列运算(如,+、-、*、/),索引不生效</a><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">表结构:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/hzVGicX27IG2kREVLZKwAStcgicmt6cEicVs6NxtecqXBu0vaibqJWWTzRtkRVwFum8Af1gQoPtzV2arZZnvaLVL2JeV1WN2Okmd/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(30, 30, 30);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #DCDCDC;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #1E1E1E;border-radius: 5px;"><span style="color: #569CD6;line-height: 26px;">CREATE</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">TABLE</span>&nbsp;<span style="color: #D69D85;line-height: 26px;">`user`</span>&nbsp;(<br>&nbsp;&nbsp;<span style="color: #D69D85;line-height: 26px;">`id`</span>&nbsp;<span style="color: #4EC9B0;line-height: 26px;">int</span>(<span style="color: #B8D7A3;line-height: 26px;">11</span>)&nbsp;<span style="color: #569CD6;line-height: 26px;">NOT</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">NULL</span>&nbsp;AUTO_INCREMENT,<br>&nbsp;&nbsp;<span style="color: #D69D85;line-height: 26px;">`userId`</span>&nbsp;<span style="color: #4EC9B0;line-height: 26px;">varchar</span>(<span style="color: #B8D7A3;line-height: 26px;">32</span>)&nbsp;<span style="color: #569CD6;line-height: 26px;">NOT</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">NULL</span>,<br>&nbsp;&nbsp;<span style="color: #D69D85;line-height: 26px;">`age`</span>&nbsp;<span style="color: #4EC9B0;line-height: 26px;">int</span>(<span style="color: #B8D7A3;line-height: 26px;">11</span>)&nbsp;<span style="color: #569CD6;line-height: 26px;">DEFAULT</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">NULL</span>,<br>&nbsp;&nbsp;PRIMARY&nbsp;<span style="color: #569CD6;line-height: 26px;">KEY</span>&nbsp;(<span style="color: #D69D85;line-height: 26px;">`id`</span>),<br>&nbsp;&nbsp;<span style="color: #569CD6;line-height: 26px;">KEY</span>&nbsp;<span style="color: #D69D85;line-height: 26px;">`idx_age`</span>&nbsp;(<span style="color: #D69D85;line-height: 26px;">`age`</span>)&nbsp;<span style="color: #569CD6;line-height: 26px;">USING</span>&nbsp;BTREE<br>)&nbsp;<span style="color: #569CD6;line-height: 26px;">ENGINE</span>=<span style="color: #569CD6;line-height: 26px;">InnoDB</span>&nbsp;AUTO_INCREMENT=<span style="color: #B8D7A3;line-height: 26px;">2</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">DEFAULT</span>&nbsp;<span style="color: #569CD6;line-height: 26px;">CHARSET</span>=utf8;<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">虽然<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">age</code>加了索引,但是因为它进行运算,索引直接迷路了。。。如图:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;scene=21#wechat_redirect" textvalue="你已选中了添加链接的内容" linktype="text" imgurl="" imgdata="null" tab="innerlink" data-linktype="1"><span class="js_jump_icon h5_image_link" data-positionback="static" style="top: auto;left: auto;margin: 20px 41.8542px;right: auto;bottom: auto;"><img class="rich_pages wxw-img" data-ratio="0.2074074074074074" src="/upload/caae33e4791628e98e953bc2cccb50b.png" data-type="png" data-w="1080" style="border-radius: 0px 0px 5px 5px;display: block;margin: 0px;width: 85%;height: 100%;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;"></span></a> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">所以<strong style="font-weight: border;color: #0e88eb;">不可以对索引列进行运算,可以在代码处理好,再传参进去</strong> 。</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span><a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;scene=21#wechat_redirect" style="color: rgb(14, 136, 235);border-bottom: 0px solid rgb(255, 53, 2);font-family: STHeitiSC-Light;" data-linktype="2">2.7 索引字段上使用(!= 或者 &lt; &gt;),索引可能失效</a><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">表结构:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/hzVGicX27IG2kREVLZKwAStcgicmt6cEicVs6NxtecqXBu0vaibqJWWTzRtkRVwFum8Af1gQoPtzV2arZZnvaLVL2JeV1WN2Okmd/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(30, 30, 30);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #DCDCDC;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #1E1E1E;border-radius: 5px;">CREATE&nbsp;TABLE&nbsp;`user`&nbsp;(<br>&nbsp;&nbsp;`id`&nbsp;<span style="color: #569CD6;line-height: 26px;">int</span>(<span style="color: #B8D7A3;line-height: 26px;">11</span>)&nbsp;NOT&nbsp;NULL&nbsp;AUTO_INCREMENT,<br>&nbsp;&nbsp;`userId`&nbsp;<span style="color: #569CD6;line-height: 26px;">int</span>(<span style="color: #B8D7A3;line-height: 26px;">11</span>)&nbsp;NOT&nbsp;NULL,<br>&nbsp;&nbsp;`age`&nbsp;<span style="color: #569CD6;line-height: 26px;">int</span>(<span style="color: #B8D7A3;line-height: 26px;">11</span>)&nbsp;DEFAULT&nbsp;NULL,<br>&nbsp;&nbsp;`name`&nbsp;varchar(<span style="color: #B8D7A3;line-height: 26px;">255</span>)&nbsp;NOT&nbsp;NULL,<br>&nbsp;&nbsp;<span style="line-height: 26px;">PRIMARY&nbsp;<span style="line-height: 26px;">KEY</span>&nbsp;<span style="line-height: 26px;">(`id`)</span>,<br>&nbsp;&nbsp;KEY&nbsp;`idx_age`&nbsp;<span style="line-height: 26px;">(`age`)</span>&nbsp;USING&nbsp;BTREE<br>)&nbsp;ENGINE</span>=InnoDB&nbsp;AUTO_INCREMENT=<span style="color: #B8D7A3;line-height: 26px;">2</span>&nbsp;DEFAULT&nbsp;CHARSET=utf8;<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">虽然<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">age</code>加了索引,但是使用了<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">!= </code>或者<code style="font-size: 14px;padding: 2px 4px;