作者:微信小助手
<section style="display: none;" data-tools="新媒体管家" data-label="powered by xmt.cn" data-mpa-powered-by="yiban.io"> <br> </section> <p style="text-align: center;"><span style="font-size: 13px;"><span style="color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;">点击上方蓝色“</span><span style="font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;color: rgb(0, 128, 255);">程序猿DD</span><span style="color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;">”,选择“设为星标”</span><strong style="max-width: 100%;letter-spacing: 0.544px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;font-size: 16px;white-space: pre-line;background-color: rgb(255, 255, 255);text-align: right;box-sizing: border-box !important;overflow-wrap: break-word !important;"></strong></span></p> <p style="max-width: 100%;min-height: 1em;white-space: normal;text-align: center;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="font-size: 13px;"><span style="max-width: 100%;color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;overflow-wrap: break-word !important;box-sizing: border-box !important;">回复“</span><span style="max-width: 100%;font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;color: rgb(0, 128, 255);overflow-wrap: break-word !important;box-sizing: border-box !important;">资源</span><span style="max-width: 100%;color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;overflow-wrap: break-word !important;box-sizing: border-box !important;">”获取独家整理的学习资料!</span></span></p> <p style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;min-height: 1em;white-space: normal;text-align: center;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="max-width: 100%;color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;font-size: 14px;letter-spacing: 0.544px;overflow-wrap: break-word !important;box-sizing: border-box !important;"><img data-backh="34" data-backw="540" data-ratio="0.0625" data-s="300,640" data-type="jpeg" data-w="640" width="100%" src="/upload/8c292e55ba5a23cb6ebc11f2a2c4fece.null" style="font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;overflow-wrap: break-word !important;box-sizing: border-box !important;visibility: visible !important;width: 654px !important;"></span></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.6662087912087912" data-s="300,640" src="/upload/63d2e889f673f9721c4004adc12ee0e2.jpg" data-type="jpeg" data-w="728" style=""></p> <section data-mpa-template="t" mpa-paragraph-type="ignored" style="caret-color: rgb(62, 62, 62);color: rgb(62, 62, 62);font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;background-color: rgb(255, 255, 255);"> <section style="margin-top: 5px;margin-bottom: 10px;letter-spacing: 0.544px;text-align: right;text-indent: 0em;"> <span style="color: rgb(178, 178, 178);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;white-space: pre-line;letter-spacing: 0.544px;font-size: 13px;">来源 | https://urlify.cn/2qmAju</span> </section> </section> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="margin-top: -10px;padding: 1px;white-space: normal;text-size-adjust: auto;background-color: rgb(255, 255, 255);font-size: 16px;color: black;line-height: 1.6;letter-spacing: 0px;word-break: break-word;text-align: left;font-family: PingFangSC-Light;"> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: rgb(14, 136, 235);">前言</h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;letter-spacing: 0.1em;font-size: 15px;word-spacing: 0.1em;">Insert into select请慎用。这天xxx接到一个需求,需要将表A的数据迁移到表B中去做一个备份。本想通过程序先查询查出来然后批量插入。但xxx觉得这样有点慢,需要耗费大量的网络I/O,决定采取别的方法进行实现。通过在Baidu的海洋里遨游,他发现了可以使用insert into select实现,这样就可以避免使用网络I/O,直接使用SQL依靠数据库I/O完成,这样简直不要太棒了。然后他就被开除了。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: rgb(14, 136, 235);">事故发生的经过</h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;letter-spacing: 0.1em;font-size: 15px;word-spacing: 0.1em;">由于数据数据库中order_today数据量过大,当时好像有700W了并且每天在以30W的速度增加。所以上司命令xxx将order_today内的部分数据迁移到order_record中,并将order_today中的数据删除。这样来降低order_today表中的数据量。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;letter-spacing: 0.1em;font-size: 15px;word-spacing: 0.1em;">由于考虑到会占用数据库I/O,为了不影响业务,计划是9:00以后开始迁移,但是xxx在8:00的时候,尝试迁移了少部分数据(1000条),觉得没啥问题,就开始考虑大批量迁移。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="1" data-type="jpeg" data-w="189" src="/upload/acc31cc43694172c294cce73a230586.jpg" style="margin: 20px auto;border-radius: 0px 0px 5px 5px;display: block;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;box-sizing: border-box !important;width: 173px !important;visibility: visible !important;"> </figure> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 在迁移的过程中,应急群是先反应有小部分用户出现支付失败,随后反应大批用户出现支付失败的情况,以及初始化订单失败的情况,同时腾讯也开始报警。 </section></li> </ul> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="1" data-type="png" data-w="220" src="/upload/d3586449a549da786faa27f8c397655e.png" style="margin: 20px auto;border-radius: 0px 0px 5px 5px;display: block;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;box-sizing: border-box !important;width: 178px !important;visibility: visible !important;"> </figure> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 然后xxx就慌了,立即停止了迁移。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;letter-spacing: 0.1em;font-size: 15px;word-spacing: 0.1em;">本以为停止迁移就就可以恢复了,但是并没有。后面发生的你们可以脑补一下。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: rgb(14, 136, 235);">事故还原</h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;letter-spacing: 0.1em;font-size: 15px;word-spacing: 0.1em;">在本地建立一个精简版的数据库,并生成了100w的数据。模拟线上发生的情况。</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;">建立表结构</h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;letter-spacing: 0.1em;font-size: 15px;word-spacing: 0.1em;">订单表</p> <pre style="margin-top: 10px;margin-bottom: 10px;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;overflow: auto;"><code style="padding: 16px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;display: -webkit-box;overflow-x: auto;color: rgb(51, 51, 51);background-color: rgb(248, 248, 248);border-radius: 0px;"><span style="font-weight: bold;line-height: 26px;">CREATE</span> <span style="font-weight: bold;line-height: 26px;">TABLE</span> <span style="color: rgb(221, 17, 68);line-height: 26px;">`order_today`</span> (<br><span style="color: rgb(221, 17, 68);line-height: 26px;">`id`</span> <span style="color: rgb(0, 134, 179);line-height: 26px;">varchar</span>(<span style="color: rgb(0, 128, 128);line-height: 26px;">32</span>) <span style="font-weight: bold;line-height: 26px;">NOT</span> <span style="color: rgb(0, 128, 128);line-height: 26px;">NULL</span> <span style="font-weight: bold;line-height: 26px;">COMMENT</span> <span style="color: rgb(221, 17, 68);line-height: 26px;">'主键'</span>,<br><span style="color: rgb(221, 17, 68);line-height: 26px;">`merchant_id`</span> <span style="color: rgb(0, 134, 179);line-height: 26px;">varchar</span>(<span style="color: rgb(0, 128, 128);line-height: 26px;">32</span>) <span style="color: rgb(0, 134, 179);line-height: 26px;">CHARACTER</span> <span style="font-weight: bold;line-height: 26px;">SET</span> utf8 <span style="font-weight: bold;line-height: 26px;">COLLATE</span> utf8_general_ci <span style="font-weight: bold;line-height: 26px;">NOT</span> <span style="color: rgb(0, 128, 128);line-height: 26px;">NULL</span> <span style="font-weight: bold;line-height: 26px;">COMMENT</span> <span style="color: rgb(221, 17, 68);line-height: 26px;">'商户编号'</span>,<br><span style="color: rgb(221, 17, 68);line-height: 26px;">`amount`</span> <span style="color: rgb(0, 134, 179);line-height: 26px;">decimal</span>(<span style="color: rgb(0, 128, 128);line-height: 26px;">15</span>,<span style="color: rgb(0, 128, 128);line-height: 26px;">2</span>) <span style="font-weight: bold;line-height: 26px;">NOT</span> <span style="color: rgb(0, 128, 128);line-height: 26px;">NULL</span> <span style="font-weight: bold;line-height: 26px;">COMMENT</span> <span style="color: rgb(221, 17, 68);line-height: 26px;">'订单金额'</span>,<br><span style="color: rgb(221, 17, 68);line-height: 26px;">`pay_success_time`</span> datetime <span style="font-weight: bold;line-height: 26px;">NOT</span> <span style="color: rgb(0, 128, 128);line-height: 26px;">NULL</span> <span style="font-weight: bold;line-height: 26px;">COMMENT</span> <span style="color: rgb(221, 17, 68);line-height: 26px;">'支付成功时间'</span>,<br><span style="color: rgb(221, 17, 68);line-height: 26px;">`order_status`</span> <span style="color: rgb(0, 134, 179);line-height: 26px;">varchar</span>(<span style="color: rgb(0, 128, 128);line-height: 26px;">10</span>) <span style="color: rgb(0, 134, 179);line-height: 26px;">CHARACTER</span> <span style="font-weight: bold;line-height: 26px;">SET</span> utf8 <span style="font-weight: bold;line-height: 26px;">COLLATE</span> utf8_general_ci <span style="font-weight: bold;line-height: 26px;">NOT</span> <span style="color: rgb(0, 128, 128);line-height: 26px;">NULL</span> <span style="font-weight: bold;line-height: 26px;">COMMENT</span> <span style="color: rgb(221, 17, 68);line-height: 26px;">'支付状态 S:支付成功、F:订单支付失败'</span>,<br><span style="color: rgb(221, 17, 68);line-height: 26px;">`remark`</span> <span style="color: rgb(0, 134, 179);line-height: 26px;">varchar</span>(<span style="color: rgb(0, 128, 128);line-height: 26px;">100</span>) <span style="color: rgb(0, 134, 179);line-height: 26px;">CHARACTER</span> <span style="font-weight: bold;line-height: 26px;">SET</span> utf8 <span style="font-weight: bold;line-height: 26px;">COLLATE</span> utf8_general_ci <span style="font-weight: bold;line-height: 26px;">DEFAULT</span> <span style="color: rgb(0, 128, 128);line-height: 26px;">NULL</span> <span style="font-weight: bold;line-height: 26px;">COMMENT</span> <span style="color: rgb(221, 17, 68);line-height: 26px;">'备注'</span>,<br><span style="color: rgb(221, 17, 68);line-height: 26px;">`create_time`</span> <span style="color: rgb(0, 134, 179);line-height: 26px;">timestamp</span> <span style="font-weight: bold;line-height: 26px;">NOT</span> <span style="color: rgb(0, 128, 128);line-height: 26px;">NULL</span> <span style="font-weight: bold;line-height: 26px;">DEFAULT</span> <span style="font-weight: bold;line-height: 26px;">CURRENT_TIMESTAMP</span> <span style="font-weight: bold;line-height: 26px;">COMMENT</span> <span style="color: rgb(221, 17, 68);line-height: 26px;">'创建时间'</span>,<br><span style="color: rgb(221, 17, 68);line-height: 26px;">`update_time`</span> <span style="color: rgb(0, 134, 179);line-height: 26px;">timestamp</span> <span style="font-weight: bold;line-height: 26px;">NOT</span> <span style="color: rgb(0, 128, 128);line-height: 26px;">NULL</span> <span style="font-weight: bold;line-height: 26px;">DEFAULT</span> <span style="font-weight: bold;line-height: 26px;">CURRENT_TIMESTAMP</span> <span style="font-weight: bold;line-height: 26px;">ON</span> <span style="font-weight: bold;line-height: 26px;">UPDATE</span> <span style="font-weight: bold;line-height: 26px;">CURRENT_TIMESTAMP</span> <span style="font-weight: bold;line-height: 26px;">COMMENT</span> <span style="color: rgb(221, 17, 68);line-height: 26px;">'修改时间 -- 修改时自动更新'</span>,<br> PRIMARY <span style="font-weight: bold;line-height: 26px;">KEY</span> (<span style="color: rgb(221, 17, 68);line-height: 26px;">`id`</span>) <span style="font-weight: bold;line-height: 26px;">USING</span> BTREE,<br><span style="font-weight: bold;line-height: 26px;">KEY</span> <span style="color: rgb(221, 17, 68);line-height: 26px;">`idx_merchant_id`</span> (<span style="color: rgb(221, 17, 68);line-height: 26px;">`merchant_id`</span>) <span style="font-weight: bold;line-height: 26px;">USING</span> BTREE <span style="font-weight: bold;line-height: 26px;">COMMENT</span> <span style="color: rgb(221, 17, 68);line-height: 26px;">'商户编号'</span><br>) <span style="font-weight: bold;line-height: 26px;">ENGINE</span>=<span style="font-weight: bold;line-height: 26px;">InnoDB</span> <span style="font-weight: bold;line-height: 26px;">DEFAULT</span> <span style="font-weight: bold;line-height: 26px;">CHARSET</span>=utf8;<br></code></pre> <p style="padding-top: 8px;padding-bottom: 8px;font-size: 15px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;">订单记录表</p> <pre style="margin-top: 10px;margin-bottom: 10px;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;overflow: auto;"><code style="padding: 16px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;display: -webkit-box;overflow-x: auto;color: rgb(51, 51, 51);background-color: rgb(248, 248, 248);border-radius: 0px;"><span style="font-weight: bold;line-height: 26px;">CREATE</span> <span style="font-weight: bold;line-height: 26px;">TABLE</span> order_record <span style="font-weight: bold;line-height: 26px;">like</span> order_today;<br></code></pre> <p style="padding-top: 8px;padding-bottom: 8px;font-size: 15px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;">今日订单表数据</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.5161290322580645" data-type="png" data-w="682" src="/upload/216a5e3fee06ae7e5e497ab619bd07d2.png" style="margin: 20px auto;border-radius: 0px 0px 5px 5px;display: block;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;width: 573.75px;box-sizing: border-box !important;visibility: visible !important;"> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: rgb(14, 136, 235);">模拟迁移</h3> <p style="padding-top: 8px;padding-bottom: 8px;font-size: 15px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;">把8号之前的数据都迁移到order_record表中去。</p> <pre style="margin-top: 10px;margin-bottom: 10px;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;overflow: auto;"><code style="padding: 16px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;display: -webkit-box;overflow-x: auto;color: rgb(51, 51, 51);background-color: rgb(248, 248, 248);border-radius: 0px;"><span style="font-weight: bold;line-height: 26px;">INSERT</span> <span style="font-weight: bold;line-height: 26px;">INTO</span> order_record <span style="font-weight: bold;line-height: 26px;">SELECT</span><br> * <br><span style="font-weight: bold;line-height: 26px;">FROM</span><br> order_today <br><span style="font-weight: bold;line-height: 26px;">WHERE</span><br> pay_success_time < <span style="color: rgb(221, 17, 68);line-height: 26px;">'2020-03-08 00:00:00'</span>;<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;letter-spacing: 0.1em;font-size: 15px;word-spacing: 0.1em;">在navicat中运行迁移的sql,同时开另个一个窗口插入数据,模拟下单。<br></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.5092592592592593" data-type="png" data-w="1080" src="/upload/bfeb8cdc1ec23130f37cc3ef06c32cef.png" style="margin: 20px auto;border-radius: 0px 0px 5px 5px;display: block;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;width: 573.75px;box-sizing: border-box !important;visibility: visible !important;"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.4925925925925926" data-type="png" data-w="1080" src="/upload/f62b009d31b2acf6e6b3d1c537b88efe.png" style="margin: 20px auto;border-radius: 0px 0px 5px 5px;display: block;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;width: 573.75px;box-sizing: border-box !important;visibility: visible !important;"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.4925925925925926" data-type="png" data-w="1080" src="/upload/bcefc0ad6b73963d0441ae6d6ec28500.png" style="margin: 20px auto;border-radius: 0px 0px 5px 5px;display: block;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;width: 573.75px;box-sizing: border-box !important;visibility: visible !important;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;letter-spacing: 0.1em;font-size: 15px;word-spacing: 0.1em;">从上面可以发现一开始能正常插入,但是后面突然就卡住了,并且耗费了23s才成功,然后才能继续插入。这个时候已经迁移成功了,所以能正常插入了。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: rgb(14, 136, 235);">出现的原因</h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;letter-spacing: 0.1em;font-size: 15px;word-spacing: 0.1em;">在默认的事务隔离级别下:insert into order_record select * from order_today 加锁规则是:order_record表锁,order_today逐步锁(扫描一个锁一个)。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;letter-spacing: 0.1em;font-size: 15px;word-spacing: 0.1em;">分析执行过程。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.08888888888888889" data-type="png" data-w="1080" src="/upload/2df5b9713e1bd00bfc71f6722bb945b5.png" style="margin: 20px auto;border-radius: 0px 0px 5px 5px;display: block;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;width: 573.75px;box-sizing: border-box !important;visibility: visible !important;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;letter-spacing: 0.1em;font-size: 15px;word-spacing: 0.1em;">通过观察迁移sql的执行情况你会发现order_today是全表扫描,也就意味着在执行insert into select from 语句时,mysql会从上到下扫描order_today内的记录并且加锁,这样一来不就和直接锁表是一样了。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;letter-spacing: 0.1em;font-size: 15px;word-spacing: 0.1em;">这也就可以解释,为什么一开始只有少量用户出现支付失败,后续大量用户出现支付失败,初始化订单失败等情况,因为一开始只锁定了少部分数据,没有被锁定的数据还是可以正常被修改为正常状态。由于锁定的数据越来越多,就导致出现了大量支付失败。最后全部锁住,导致无法插入订单,而出现初始化订单失败。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: rgb(14, 136, 235);">解决方案</h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;letter-spacing: 0.1em;font-size: 15px;word-spacing: 0.1em;">由于查询条件会导致order_today全表扫描,什么能避免全表扫描呢,很简单嘛,给pay_success_time字段添加一个idx_pay_suc_time索引就可以了,由于走索引查询,就不会出现扫描全表的情况而锁表了,只会锁定符合条件的记录。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: rgb(14, 136, 235);">最终的sql</h3> <pre style="margin-top: 10px;margin-bottom: 10px;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;overflow: auto;"><code style="padding: 16px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;display: -webkit-box;overflow-x: auto;color: rgb(51, 51, 51);background-color: rgb(248, 248, 248);border-radius: 0px;"><span style="font-weight: bold;line-height: 26px;">INSERT</span> <span style="font-weight: bold;line-height: 26px;">INTO</span> order_record <span style="font-weight: bold;line-height: 26px;">SELECT</span><br> * <br><span style="font-weight: bold;line-height: 26px;">FROM</span><br> order_today <span style="font-weight: bold;line-height: 26px;">FORCE</span> <span style="font-weight: bold;line-height: 26px;">INDEX</span> (idx_pay_suc_time)<br><span style="font-weight: bold;line-height: 26px;">WHERE</span><br> pay_success_time <= <span style="color: rgb(221, 17, 68);line-height: 26px;">'2020-03-08 00:00:00'</span>;<br></code></pre> <p style="padding-top: 8px;padding-bottom: 8px;font-size: 15px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;">执行过程</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.08056872037914692" data-type="png" data-w="1055" src="/upload/50636a2d93d9e7a75787874231f387f0.png" style="margin: 20px auto;border-radius: 0px 0px 5px 5px;display: block;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;width: 573.75px;box-sizing: border-box !important;visibility: visible !important;"> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: rgb(14, 136, 235);">总结</h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;letter-spacing: 0.1em;font-size: 15px;word-spacing: 0.1em;">使用insert into tablA select * from tableB语句时,一定要确保tableB后面的where,order或者其他条件,都需要有对应的索引,来避免出现tableB全部记录被锁定的情况。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: rgb(14, 136, 235);">参考</h3> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> https://blog.csdn.net/asdfsadfasdfsa/article/details/83030011 </section></li> </ul> </section> <p style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);font-size: 16px;white-space: pre-line;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;line-height: normal;overflow-wrap: break-word !important;box-sizing: border-box !important;"><br></p> <section data-recommend-type="list-title" data-mpa-template="t" style="width: 100%;display: flex;justify-content: center;align-items: center;" data-mid="" data-from="yb-recommend"> <section style="width: 100%;background: rgb(255, 255, 255);border-radius: 3px;border-width: 1px;border-style: solid;border-color: rgb(232, 232, 235);padding: 20px 14px;" data-mid=""> <section style="width: 100%;display: flex;justify-content: center;align-items: center;align-items: flex-end;" data-mid=""> <section style="display: flex;justify-content: center;align-items: center;max-width: 100%;background: #fff;margin-bottom: -10px;z-index: 10;" data-mid=""> <section style="width: 10px;height: 10px;border-radius: 50%;border-width: 1px;border-style: solid;border-color: rgb(68, 153, 231);" data-mid=""> <br> </section> <section style="margin: 0px 8px;height: 20px;font-size: 14px;font-weight: 500;color: rgb(68, 153, 231);line-height: 20px;" data-mid=""> <p data-mid="">往期推荐</p> </section> <section style="width: 10px;height: 10px;border-radius: 50%;border-width: 1px;border-style: solid;border-color: rgb(68, 153, 231);" data-mid=""> <br> </section> </section> </section> <section style="width: 100%;height: 1px;background: rgb(68, 153, 231);margin-bottom: 16px;" data-mid=""> <br> </section> <section style="width: 100%;" data-mid=""> <a href="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&mid=2247490238&idx=1&sn=032c68b1b109bd3ba4d190cdf9ba67a5&chksm=9bd0b726aca73e302e5bd7b0ecd2e29fecc29b45a7d7ae43c6ea6ab1613d537b5e0bdd1fa60b&scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" style="width: 100%;background: rgb(245, 245, 245);display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;padding: 6px 16px;font-size: 13px;font-weight: 400;color: rgb(68, 153, 231);line-height: 18px;" data-mid=""> <p style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 100%;" data-mid="">相同 SQL 下 Mybatis 查询结果和数据库竟然不一样!</p> </section></a> <a href="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&mid=2247490238&idx=2&sn=d3f44f749e170543b7d3da76fec025c0&chksm=9bd0b726aca73e3083192360ffd04114073ae83f25596dcf1d1869271242875b8e8428e7fa67&scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" style="width: 100%;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;padding: 6px 16px;font-size: 13px;font-weight: 400;color: rgb(68, 153, 231);line-height: 18px;" data-mid=""> <p style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 100%;" data-mid="">一文搞懂 ThreadLocal 原理</p> </section></a> <a href="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&mid=2247490219&idx=4&sn=b21d9ec65b8a78337de8da2842987032&chksm=9bd0b733aca73e25c9da8424ceb19b91f1630b5f152f99839f56c2f1fb713e9659a70691c020&scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" style="width: 100%;background: rgb(245, 245, 245);display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;padding: 6px 16px;font-size: 13px;font-weight: 400;color: rgb(68, 153, 231);line-height: 18px;" data-mid=""> <p style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 100%;" data-mid="">Java 14 :NullPointerException的处理新方式</p> </section></a> <a href="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&mid=2247490194&idx=1&sn=286919d0a0addf9408bdaad718c3f539&chksm=9bd0b70aaca73e1c936f8c1f22a814a9c10a68a36f7234ae17b7d787952ad4b89552cadbc385&scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" style="width: 100%;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;padding: 6px 16px;font-size: 13px;font-weight: 400;color: rgb(68, 153, 231);line-height: 18px;" data-mid=""> <p style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 100%;" data-mid="">如何画出优秀的架构图?</p> </section></a> <a href="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&mid=2247490187&idx=3&sn=2c3d846cf681d76a78e9c937f477afc3&chksm=9bd0b713aca73e05a2e253433b5574ded74acc62a15e56b7b365f71dc655583d0580acff20a8&scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" style="width: 100%;background: rgb(245, 245, 245);display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;padding: 6px 16px;font-size: 13px;font-weight: 400;color: rgb(68, 153, 231);line-height: 18px;border-bottom: none !important;" data-mid=""> <p style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 100%;" data-mid="">200余行代码,让你实时从视频中隐身</p> </section></a> </section> </section> </section> <p><br></p> <p style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);font-size: 16px;white-space: pre-line;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;line-height: normal;overflow-wrap: break-word !important;box-sizing: border-box !important;"><br></p> <p style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);font-size: 16px;white-space: pre-line;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: center;line-height: normal;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="max-width: 100%;font-size: 14px;overflow-wrap: break-word !important;box-sizing: border-box !important;">扫一扫,关注我</span><br style="max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;"></p> <p style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);font-size: 16px;white-space: pre-line;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: center;line-height: normal;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="max-width: 100%;font-size: 14px;overflow-wrap: break-word !important;box-sizing: border-box !important;">一起学习,一起进步</span></p> <p style="max-width: 100%;min-height: 1em;white-space: normal;text-align: center;overflow-wrap: break-word !important;box-sizing: border-box !important;"><img class="rich_pages" data-ratio="1" data-s="300,640" src="/upload/7d9c899a662cfacd5d6e10c875ecb76e.jpg" data-type="jpeg" data-w="258" style="overflow-wrap: break-word !important;box-sizing: border-box !important;"></p>
作者:微信小助手
<section style="font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;text-indent: 0em;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;"> <span style="font-size: 13px;color: rgb(136, 136, 136);font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;">作者:</span> <span style="font-size: 13px;color: rgb(136, 136, 136);font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;">学习园</span></section> <section style="font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;text-indent: 0em;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;"> <span style="font-size: 13px;color: rgb(136, 136, 136);font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;">https://blog.csdn.net/u010644448/article/details/59108799</span></section> <p style="margin-top: 1.1em;margin-bottom: 1.1em;white-space: normal;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;font-size: 15px;color: rgb(62, 62, 62);background-color: rgb(255, 255, 255);text-align: left;line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="">循环依赖就是N个类中循环嵌套引用,如果在日常开发中我们用new 对象的方式发生这种循环依赖的话程序会在运行时一直循环调用,直至内存溢出报错。</span></p> <p style="margin-top: 1.1em;margin-bottom: 1.1em;white-space: normal;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;font-size: 15px;color: rgb(62, 62, 62);background-color: rgb(255, 255, 255);text-align: left;line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="">下面说一下Spring是如果解决循环依赖的。</span></p> <h3 style="white-space: normal;text-align: left;line-height: 4em;"> <span style=""> <strong> <span style="color: rgb(255, 76, 65);">第一种:</span></strong> <strong> <span style="color: rgb(255, 76, 65);"></span> </strong> <strong> <span style="color: rgb(255, 76, 65);">构造器参数循环依赖</span></strong> <strong> <span style="color: rgb(255, 76, 65);"></span> </strong> </span> </h3> <section style="margin-top: 1.1em;margin-bottom: 1.1em;white-space: normal;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;font-size: 15px;color: rgb(62, 62, 62);background-color: rgb(255, 255, 255);text-align: left;line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="">Spring容器会将每一个正在创建的Bean 标识符放在一个“当前创建Bean池”中,Bean标识符在创建过程中将一直保持在这个池中。</span></section> <section style="margin-top: 1.1em;margin-bottom: 1.1em;white-space: normal;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;font-size: 15px;color: rgb(62, 62, 62);background-color: rgb(255, 255, 255);text-align: left;line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="">因此如果在创建Bean过程中发现自己已经在“当前创建Bean池”里时将抛出BeanCurrentlyInCreationException异常表示循环依赖;而对于创建完毕的Bean将从“当前创建Bean池”中清除掉。</span></section> <section style="margin-top: 1.1em;margin-bottom: 1.1em;white-space: normal;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;font-size: 15px;color: rgb(62, 62, 62);background-color: rgb(255, 255, 255);text-align: left;line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="">首先我们先初始化三个Bean。</span></section> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" mpa-preserve="t" mpa-from-tpl="t"> <pre style="margin:0;padding:0;border-radius:none;background:none;"> <code style="border-radius: 4px;font-size: 0.85em;margin: 0px 0.15em;background: rgb(40, 44, 52);color: rgb(171, 178, 191);display: block;padding: 5.95px;overflow-x: auto;white-space: nowrap;"> <span style=""> <span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 39px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">public</span> <span style="color: rgb(171, 178, 191);background: rgba(0, 0, 0, 0);display: inline;width: 106px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;"> <span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 33px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">class</span> <span style="color: rgb(230, 192, 123);background: rgba(0, 0, 0, 0);display: inline;width: 52px;text-decoration: none solid rgb(230, 192, 123);font-weight: 400;font-style: normal;">StudentA</span> {</span></span> <br mpa-from-tpl="t"> <br mpa-from-tpl="t"> <span style=""> <span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 46px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">private</span> StudentB studentB ;</span> <br mpa-from-tpl="t"> <br mpa-from-tpl="t"> <span style=""> <span style="color: rgb(171, 178, 191);background: rgba(0, 0, 0, 0);display: inline;width: 284px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;"> <span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 40px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">public</span> <span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 27px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">void</span> <span style="color: rgb(97, 174, 238);background: rgba(0, 0, 0, 0);display: inline;width: 73px;text-decoration: none solid rgb(97, 174, 238);font-weight: 400;font-style: normal;">setStudentB</span> <span style="background: rgba(0, 0, 0, 0);display: inline;width: 125px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;">(StudentB studentB)</span> </span>{</span> <br mpa-from-tpl="t"> <span style=""> <span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 26px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">this</span>.studentB = studentB;</span> <br mpa-from-tpl="t"> <span style=""> }</span> <br mpa-from-tpl="t"> <br mpa-from-tpl="t"> <span style=""> <span style="color: rgb(171, 178, 191);background: rgba(0, 0, 0, 0);display: inline;width: 119px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;"> <span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 40px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">public</span> <span style="color: rgb(97, 174, 238);background: rgba(0, 0, 0, 0);display: inline;width: 53px;text-decoration: none solid rgb(97, 174, 238);font-weight: 400;font-style: normal;">StudentA</span> <span style="background: rgba(0, 0, 0, 0);display: inline;width: 13px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;">()</span> </span>{</span> <br mpa-from-tpl="t"> <span style=""> }</span> <br mpa-from-tpl="t"> <br mpa-from-tpl="t"> <span style=""> <span style="color: rgb(171, 178, 191);background: rgba(0, 0, 0, 0);display: inline;width: 231px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;"> <span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 40px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">public</span> <span style="color: rgb(97, 174, 238);background: rgba(0, 0, 0, 0);display: inline;width: 53px;text-decoration: none solid rgb(97, 174, 238);font-weight: 400;font-style: normal;">StudentA</span> <span style="background: rgba(0, 0, 0, 0);display: inline;width: 125px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;">(StudentB studentB)</span> </span>{</span> <br mpa-from-tpl="t"> <span style=""> <span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 26px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">this</span>.studentB = studentB;</span> <br mpa-from-tpl="t"> <span style=""> }</span> <br mpa-from-tpl="t"> <span style="">}</span></code> </pre> </section> <p> <span style=""> <br></span> </p> <p> <span style=""> <br mpa-from-tpl="t"></span> </p> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" mpa-preserve="t" mpa-from-tpl="t"> <pre style="margin:0;padding:0;border-radius:none;background:none;"> <code style="border-radius: 4px;font-size: 0.85em;margin: 0px 0.15em;background: rgb(40, 44, 52);color: rgb(171, 178, 191);display: block;padding: 5.95px;overflow-x: auto;white-space: nowrap;"> <span style=""> <span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 39px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">public</span> <span style="color: rgb(171, 178, 191);background: rgba(0, 0, 0, 0);display: inline;width: 106px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;"> <span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 33px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">class</span> <span style="color: rgb(230, 192, 123);background: rgba(0, 0, 0, 0);display: inline;width: 52px;text-decoration: none solid rgb(230, 192, 123);font-weight: 400;font-style: normal;">StudentB</span> {</span></span> <br mpa-from-tpl="t"> <br mpa-from-tpl="t"> <span style=""> <span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 46px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">private</span> StudentC studentC ;</span> <br mpa-from-tpl="t"> <br mpa-from-tpl="t"> <span style=""> <span style="color: rgb(171, 178, 191);background: rgba(0, 0, 0, 0);display: inline;width: 284px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;"> <span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 40px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">public</span> <span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 27px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">void</span> <span style="color: rgb(97, 174, 238);background: rgba(0, 0, 0, 0);display: inline;width: 73px;text-decoration: none solid rgb(97, 174, 238);font-weight: 400;font-style: normal;">setStudentC</span> <span style="background: rgba(0, 0, 0, 0);display: inline;width: 125px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;">(StudentC studentC)</span> </span>{</span> <br mpa-from-tpl="t"> <span style=""> <span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 26px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">this</span>.studentC = studentC;</span> <br mpa-from-tpl="t"> <span style=""> }</span> <br mpa-from-tpl="t"> <br mpa-from-tpl="t"> <span style=""> <span style="color: rgb(171, 178, 191);background: rgba(0, 0, 0, 0);display: inline;width: 119px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;"> <span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 40px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">public</span> <span style="color: rgb(97, 174, 238);background: rgba(0, 0, 0, 0);display: inline;width: 53px;text-decoration: none solid rgb(97, 174, 238);font-weight: 400;font-style: normal;">StudentB</span> <span style="background: rgba(0, 0, 0, 0);display: inline;width: 13px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;">()</span> </span>{</span> <br mpa-from-tpl="t"> <span style=""> }</span> <br mpa-from-tpl="t"> <br mpa-from-tpl="t"> <span style=""> <span style="color: rgb(171, 178, 191);background: rgba(0, 0, 0, 0);display: inline;width: 231px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;"> <span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 40px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">public</span> <span style="color: rgb(97, 174, 238);background: rgba(0, 0, 0, 0);display: inline;width: 53px;text-decoration: none solid rgb(97, 174, 238);font-weight: 400;font-style: normal;">StudentB</span> <span style="background: rgba(0, 0, 0, 0);display: inline;width: 125px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;">(StudentC studentC)</span> </span>{</span> <br mpa-from-tpl="t"> <span style=""> <span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 26px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">this</span>.studentC = studentC;</span> <br mpa-from-tpl="t"> <span style=""> }</span> <br mpa-from-tpl="t"> <span style="">}</span></code> </pre> </section> <p> <br mpa-from-tpl="t"></p> <p> <br mpa-from-tpl="t"></p> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" mpa-preserve="t" mpa-from-tpl="t"> <pre style="margin:0;padding:0;border-radius:none;background:none;"> <code style="border-radius: 4px;font-size: 0.85em;margin: 0px 0.15em;background: rgb(40, 44, 52);color: rgb(171, 178, 191);display: block;padding: 5.95px;overflow-x: auto;white-space: nowrap;"> <span style=""> <span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 39px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">public</span> <span style="color: rgb(171, 178, 191);background: rgba(0, 0, 0, 0);display: inline;width: 106px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;"> <span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 33px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">class</span> <span style="color: rgb(230, 192, 123);background: rgba(0, 0, 0, 0);display: inline;width: 52px;text-decoration: none solid rgb(230, 192, 123);font-weight: 400;font-style: normal;">StudentC</span> {</span></span> <br mpa-from-tpl="t"> <br mpa-from-tpl="t"> <span style=""> <span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 46px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">private</span> StudentA studentA ;</span> <br mpa-from-tpl="t"> <br mpa-from-tpl="t"> <span style=""> <span style="color: rgb(171, 178, 191);background: rgba(0, 0, 0, 0);display: inline;width: 284px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;"> <span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 40px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">public</span> <span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 27px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">void</span> <span style="color: rgb(97, 174, 238);background: rgba(0, 0, 0, 0);display: inline;width: 73px;text-decoration: none solid rgb(97, 174, 238);font-weight: 400;font-style: normal;">setStudentA</span> <span style="background: rgba(0, 0, 0, 0);display: inline;width: 125px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;">(StudentA studentA)</span> </span>{</span> <br mpa-from-tpl="t"> <span style=""> <span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 26px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">this</span>.studentA = studentA;</span> <br mpa-from-tpl="t"> <span style=""> }</span> <br mpa-from-tpl="t"> <br mpa-from-tpl="t"> <span style=""> <span style="color: rgb(171, 178, 191);background: rgba(0, 0, 0, 0);display: inline;width: 119px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;"> <span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 40px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">public</span> <span style="color: rgb(97, 174, 238);background: rgba(0, 0, 0, 0);display: inline;width: 53px;text-decoration: none solid rgb(97, 174, 238);font-weight: 400;font-style: normal;">StudentC</span> <span style="background: rgba(0, 0, 0, 0);display: inline;width: 13px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;">()</span> </span>{</span> <br mpa-from-tpl="t"> <span style=""> }</span> <br mpa-from-tpl="t"> <br mpa-from-tpl="t"> <span style=""> <span style="color: rgb(171, 178, 191);background: rgba(0, 0, 0, 0);display: inline;width: 231px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;"> <span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 40px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">public</span> <span style="color: rgb(97, 174, 238);background: rgba(0, 0, 0, 0);display: inline;width: 53px;text-decoration: none solid rgb(97, 174, 238);font-weight: 400;font-style: normal;">StudentC</span> <span style="background: rgba(0, 0, 0, 0);display: inline;width: 125px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;">(StudentA studentA)</span> </span>{</span> <br mpa-from-tpl="t"> <span style=""> <span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 26px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">this</span>.studentA = studentA;</span> <br mpa-from-tpl="t"> <span style=""> }</span> <br mpa-from-tpl="t"> <span style="">}</span></code> </pre> </section> <p> <br></p> <section style="margin-top: 1.1em;margin-bottom: 1.1em;white-space: normal;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;font-size: 15px;color: rgb(62, 62, 62);background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="">OK,上面是很基本的3个类,StudentA有参构造是StudentB。StudentB的有参构造是StudentC,StudentC的有参构造是StudentA ,这样就产生了一个循环依赖的情况。</span></section> <section style="margin-top: 1.1em;margin-bottom: 1.1em;white-space: normal;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;color: rgb(62, 62, 62);background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="">我们都把这三个Bean交给</span> <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzI3ODcxMzQzMw==&mid=2247492151&idx=2&sn=0b8fbb5f150d4ee427c0ab7969d4abd1&chksm=eb506701dc27ee17cf3d49899ce7c7643c0866c83264b1d449e4611836adcd7bcd1669a38252&scene=21#wechat_redirect" textvalue="Spring" data-itemshowtype="0" tab="innerlink" data-linktype="2"> <span style="">Spring</span></a> <span style="">管理,并用有参构造实例化。</span></section> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" mpa-preserve="t" mpa-from-tpl="t"> <pre style="margin:0;padding:0;border-radius:none;background:none;"> <code style="border-radius: 4px;font-size: 0.85em;margin: 0px 0.15em;background: rgb(40, 44, 52);color: rgb(171, 178, 191);display: block;padding: 5.95px;overflow-x: auto;white-space: nowrap;"> <span style=""><bean id= <span style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 20px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">"a"</span> <span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 33px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">class</span>= <span style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 172px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">"com.zfx.student.StudentA"</span>></span> <br mpa-from-tpl="t"> <span style=""> <span style="color: rgb(171, 178, 191);background: rgba(0, 0, 0, 0);display: inline;width: 231px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;">< <span style="color: rgb(224, 108, 117);background: rgba(0, 0, 0, 0);display: inline;width: 99px;text-decoration: none solid rgb(224, 108, 117);font-weight: 400;font-style: normal;">constructor-arg</span> <span style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 33px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">index</span>= <span style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 20px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">"0"</span> <span style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 20px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">ref</span>= <span style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 19px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">"b"</span>></span> <span style="color: rgb(171, 178, 191);background: rgba(0, 0, 0, 0);display: inline;width: 119px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;"></ <span style="color: rgb(224, 108, 117);background: rgba(0, 0, 0, 0);display: inline;width: 99px;text-decoration: none solid rgb(224, 108, 117);font-weight: 400;font-style: normal;">constructor-arg</span>></span></span> <br mpa-from-tpl="t"> <span style=""></ <span style="color: rgb(224, 108, 117);background: rgba(0, 0, 0, 0);display: inline;width: 26px;text-decoration: none solid rgb(224, 108, 117);font-weight: 400;font-style: normal;">bean</span>></span> <br mpa-from-tpl="t"> <span style=""><bean id= <span style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 20px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">"b"</span> <span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 33px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">class</span>= <span style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 172px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">"com.zfx.student.StudentB"</span>></span> <br mpa-from-tpl="t"> <span style=""> <span style="color: rgb(171, 178, 191);background: rgba(0, 0, 0, 0);display: inline;width: 231px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;">< <span style="color: rgb(224, 108, 117);background: rgba(0, 0, 0, 0);display: inline;width: 99px;text-decoration: none solid rgb(224, 108, 117);font-weight: 400;font-style: normal;">constructor-arg</span> <span style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 33px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">index</span>= <span style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 20px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">"0"</span> <span style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 20px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">ref</span>= <span style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 19px;text-deco
作者:微信小助手
<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="padding-right: 10px;padding-left: 10px;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;margin-top: -10px;line-height: 1.6;letter-spacing: 0.034em;color: rgb(63, 63, 63);font-size: 16px;"> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.4525" src="/upload/97f8f1c2e0a7af6e0424e7d53e9116a2.jpg" data-type="jpeg" data-w="400" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">List 可谓是我们经常使用的集合类之一,几乎所有业务代码都离不开 List。既然天天在用,那就没准就会踩中这几个 List 常见坑。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">今天我们就来总结这些常见的坑在哪里,捞自己一手,防止后续同学再继续踩坑。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">本文设计知识点如下:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.1424" src="/upload/9862af2bffe8d65714e251e397ca0d2.jpg" data-type="jpeg" data-w="1875" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;font-family: PingFangSC-Light;"> List 踩坑大全 </figcaption> </figure> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;text-align: center;background-image: url("https://mmbiz.qpic.cn/mmbiz_png/LEFcpfxrbq7lsCNncLAFicib819rONCZGn6dE9ycJSGIZPu3vMRK4n9FMTduFGgpD3hBwolwVgXDTJXz3dM8bIEg/640?wx_fmt=png");background-position: center center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 50px;margin-top: 1em;margin-bottom: 10px;"><span style="display: none;"></span><span style="display: inline-block;height: 38px;line-height: 42px;color: rgb(72, 179, 120);background-position: left center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 63px;margin-top: 38px;font-size: 18px;margin-bottom: 10px;">ArrayList 这是李逵,还是李鬼?</span></h2> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">以前实习的时候,写过这样一段简单代码,通过 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">Arrays#asList</code> 将数组转化为 List 集合。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.4537987679671458" src="/upload/d3de9eb4188e35dd8fc8caa9597bb7d7.jpg" data-type="jpeg" data-w="487" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">这段代码表面看起来没有任何问题,编译也能通过,但是真正测试运行的时候将会在第 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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">UnsupportedOperationException</code>。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">刚开始很不解,<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">Arrays#asList</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">ArrayList</code>,为什么添加一个元素就会报错?这以后还能好好新增元素吗?</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.16697588126159554" src="/upload/e5413d4b789858e0b7b6599852db9e0c.jpg" data-type="jpeg" data-w="1078" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">最后通过 Debug 才发现这个<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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">Arrays#asList</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">ArrayList</code> 其实是个<strong style="line-height: 1.75em;">李鬼</strong>,仅仅只是 Arrays 一个内部类,并非真正的 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">java.util.ArrayList</code>。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.6174496644295302" src="/upload/e612b65a7abcaabf4ec4da20c8f8afda.gif" data-type="gif" data-w="298" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">通过 IDEA,生成这两个的类图,如下:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="1.3833333333333333" src="/upload/447cde987e71f388ee6ab3b33d3b5d30.jpg" data-type="jpeg" data-w="1080" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">从上图我们发现,<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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">add/remove</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">AbstractList</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">java.util.Arrays$ArrayList</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">UnsupportedOperationException</code>。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.19301848049281314" src="/upload/d1329d76fd31acd1c1052b386ef5d71.jpg" data-type="jpeg" data-w="974" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">这就是为什么这个李鬼 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">ArrayList</code> 不支持的增删的实际原因。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;text-align: center;background-image: url("https://mmbiz.qpic.cn/mmbiz_png/LEFcpfxrbq7lsCNncLAFicib819rONCZGn6dE9ycJSGIZPu3vMRK4n9FMTduFGgpD3hBwolwVgXDTJXz3dM8bIEg/640?wx_fmt=png");background-position: center center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 50px;margin-top: 1em;margin-bottom: 10px;"><span style="display: none;"></span><span style="display: inline-block;height: 38px;line-height: 42px;color: rgb(72, 179, 120);background-position: left center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 63px;margin-top: 38px;font-size: 18px;margin-bottom: 10px;">你用你的新 List,为什么却还互相影响</span></h2> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">李鬼 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">ArrayList</code> 除了不支持增删操作这个坑以外,还存在另外一个大坑,改动内部元素将会同步影响原数组。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.40472175379426645" src="/upload/84f90477dea6983bfa1ac95aeee89812.jpg" data-type="jpeg" data-w="593" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">输出结果:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #333;background: #f8f8f8;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">arrays:[modify_1, modify_2, 3]<br>list:[modify_1, modify_2, 3]<br></code></pre> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">从日志输出可以看到,不管我们是修改原数组,还是新 List 集合,两者都会互相影响。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">查看 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">java.util.Arrays$ArrayList</code> 实现,我们可以发现底层实际使用了原始数组。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.31353591160220995" src="/upload/b10257003a8290c0bab42095957677a5.jpg" data-type="jpeg" data-w="1448" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;font-family: PingFangSC-Light;"> <br> </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">知道了实际原因,修复的办法也很简单,套娃一层 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">ArrayList</code> 呗!</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #333;background: #f8f8f8;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">List<String> list = <span style="font-weight: bold;line-height: 26px;">new</span> ArrayList<>(Arrays.asList(arrays));<br></code></pre> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">不过这么写感觉十分繁琐,推荐使用 <strong style="line-height: 1.75em;">Guava Lists</strong> 提供的方法。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #333;background: #f8f8f8;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">List<String> list = Lists.newArrayList(arrays);<br></code></pre> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">通过上面两种方式,我们将新的 List 集合与原始数组解耦,不再互相影响,同时由于此时还是真正的 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">ArrayList</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">add/remove</code>报错了。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">除了 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">Arrays#asList</code>产生新集合与原始数组互相影响之外,JDK 另一个方法 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">List#subList</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">List</code> 互相影响。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">我们来看一个例子:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.6014362657091562" src="/upload/be6bde40f53e1de5dd64421cf876e900.jpg" data-type="jpeg" data-w="557" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">日志输出结果:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #333;background: #f8f8f8;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">integerList:[10, 20, 3]<br>subList:[10, 20]<br></code></pre> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">查看 <code style="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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">List#subList</code> 实现方式,可以发现这个 SubList 内部有一个 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">parent</code> 字段保存保存最原始 List 。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.29296424452133796" src="/upload/f42153ff43d3bf7f98aa02f3ef504609.jpg" data-type="jpeg" data-w="1734" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">所有外部读写动作看起来是在操作 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">SubList</code> ,实际上底层动作却都发生在原始 List 中,比如 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">add</code> 方法:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.22585438335809807" src="/upload/d732699034fbb3dfc5b81de6b41895ac.jpg" data-type="jpeg" data-w="1346" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">另外由于 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">SubList</code> 实际上还在引用原始 List,业务开发中,如果不注意,很可能产生 <strong style="line-height: 1.75em;">OOM</strong> 问题。</p> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;background: rgb(251, 249, 253);color: rgb(106, 115, 125);margin-bottom: 20px;margin-top: 20px;padding: 15px 20px;line-height: 27px;border-left-color: rgb(53, 179, 120);"> <p style="line-height: 26px;font-size: 15px;color: rgb(89, 89, 89);">以下例子来自于极客时间:<strong style="line-height: 1.75em;color: rgb(74, 74, 74);">Java业务开发常见错误100例</strong></p> </blockquote> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #333;background: #f8f8f8;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="font-weight: bold;line-height: 26px;">private</span> <span style="font-weight: bold;line-height: 26px;">static</span> List<List<Integer>> data = <span style="font-weight: bold;line-height: 26px;">new</span> ArrayList<>();<br><br><span style="line-height: 26px;"><span style="font-weight: bold;line-height: 26px;">private</span> <span style="font-weight: bold;line-height: 26px;">static</span> <span style="font-weight: bold;line-height: 26px;">void</span> <span style="color: #900;font-weight: bold;line-height: 26px;">oom</span><span style="line-height: 26px;">()</span> </span>{<br> <span style="font-weight: bold;line-height: 26px;">for</span> (<span style="font-weight: bold;line-height: 26px;">int</span> i = <span style="color: #008080;line-height: 26px;">0</span>; i < <span style="color: #008080;line-height: 26px;">1000</span>; i++) {<br> List<Integer> rawList = IntStream.rangeClosed(<span style="color: #008080;line-height: 26px;">1</span>, <span style="color: #008080;line-height: 26px;">100000</span>).boxed().collect(Collectors.toList());<br> data.add(rawList.subList(<span style="color: #008080;line-height: 26px;">0</span>, <span style="color: #008080;line-height: 26px;">1</span>));<br> }<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;"><code style="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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">data</code> 看起来最终保存的只是 1000 个具有 1 个元素的 List,不会占用很大空间。但是程序很快就会 <strong style="line-height: 1.75em;">OOM</strong>。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;"><strong style="line-height: 1.75em;">OOM</strong> 的原因正是因为每个 SubList 都强引用个一个 10 万个元素的原始 List,导致 GC 无法回收。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">这里修复的办法也很简单,跟上面一样,也来个套娃呗,加一层 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">ArrayList</code> 。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.7865612648221344" src="/upload/fcbfda1a64b9dc20c4b5326baa121fee.jpg" data-type="jpeg" data-w="253" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> </figure> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;text-align: center;background-image: url("https://mmbiz.qpic.cn/mmbiz_png/LEFcpfxrbq7lsCNncLAFicib819rONCZGn6dE9ycJSGIZPu3vMRK4n9FMTduFGgpD3hBwolwVgXDTJXz3dM8bIEg/640?wx_fmt=png");background-position: center center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 50px;margin-top: 1em;margin-bottom: 10px;"><span style="display: none;"></span><span style="display: inline-block;height: 38px;line-height: 42px;color: rgb(72, 179, 120);background-position: left center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 63px;margin-top: 38px;font-size: 18px;margin-bottom: 10px;">不可变集合,说好不变,你怎么就变了</span></h2> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">为了防止 List 集合被误操作,我们可以使用 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">Collections#unmodifiableList</code> 生成一个不可变(<strong style="line-height: 1.75em;">immutable</strong>)集合,进行防御性编程。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">这个不可变集合只能被读取,不能做任何修改,包括增加,删除,修改,从而保护不可变集合的安全。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.31290743155149936" src="/upload/465f1ad9afba311acb1eeeca997e921c.jpg" data-type="jpeg" data-w="767" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">上面最后三行写操作都将会抛出 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">UnsupportedOperationException</code> 异常</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">但是你以为这样就安全了吗?</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="1" src="/upload/452c9958569c5e3e0c1b46ce27f7a33c.jpg" data-type="jpeg" data-w="255" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">如果有谁不小心改动原始 List,你就会发现这个不可变集合,竟然就变了。。。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.4367666232073012" src="/upload/e5575610120bed15ebcbf52c471aba4b.jpg" data-type="jpeg" data-w="767" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">上面单元测试结果将会全部通过,这就代表 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">Collections#unmodifiableList</code> 产生不可变集合将会被原始 List 所影响。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">查看 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">Collections#unmodifiableList</code> 底层实现方法:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.42496493688639553" src="/upload/6eb2e40cebb1da58eeec4884b228da21.jpg" data-type="jpeg" data-w="1426" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">可以看到这跟上面 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">SubList</code> 其实是同一个问题,新集合底层实际使用了<strong style="line-height: 1.75em;">原始 List</strong>。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">由于不可变集合所有修改操作都会报错,所以不可变集合不会产生任何改动,所以并不影响的原始集合。但是防过来,却不行,原始 List 随时都有可能被改动,从而影响不可变集合。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">可以使用如下两种方式防止上卖弄的情况。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;"><strong style="line-height: 1.75em;">使用 JDK9 List#of 方法。</strong></p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #333;background: #f8f8f8;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">List<String> list = <span style="font-weight: bold;line-height: 26px;">new</span> ArrayList<>(Arrays.asList(<span style="color: #d14;line-height: 26px;">"one"</span>, <span style="color: #d14;line-height: 26px;">"two"</span>, <span style="color: #d14;line-height: 26px;">"three"</span>));<br>List<String> unmodifiableList = List.of(list.toArray(<span style="font-weight: bold;line-height: 26px;">new</span> String[]{}));<br></code></pre> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;"><strong style="line-height: 1.75em;">使用 Guava immutable list</strong></p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #333;background: #f8f8f8;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">List<String> list = <span style="font-weight: bold;line-height: 26px;">new</span> ArrayList<>(Arrays.asList(<span style="color: #d14;line-height: 26px;">"one"</span>, <span style="color: #d14;line-height: 26px;">"two"</span>, <span style="color: #d14;line-height: 26px;">"three"</span>));<br>List<String> unmodifiableList = ImmutableList.copyOf(list);<br></code></pre> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">相比而言 Guava 方式比较清爽,使用也比较简单,推荐使用 Guava 这种方式生成不可变集合。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;text-align: center;background-image: url("https://mmbiz.qpic.cn/mmbiz_png/LEFcpfxrbq7lsCNncLAFicib819rONCZGn6dE9ycJSGIZPu3vMRK4n9FMTduFGgpD3hBwolwVgXDTJXz3dM8bIEg/640?wx_fmt=png");background-position: center center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 50px;margin-top: 1em;margin-bottom: 10px;"><span style="display: none;"></span><span style="display: inline-block;height: 38px;line-height: 42px;color: rgb(72, 179, 120);background-position: left center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 63px;margin-top: 38px;font-size: 18px;margin-bottom: 10px;">foreach 增加/删除元素大坑</span></h2> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">先来看一段代码:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #333;background: #f8f8f8;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">String[] arrays = {<span style="color: #d14;line-height: 26px;">"1"</span>, <span style="color: #d14;line-height: 26px;">"2"</span>, <span style="color: #d14;line-height: 26px;">"3"</span>};<br>List<String> list = <span style="font-weight: bold;line-height: 26px;">new</span> ArrayList<>(Arrays.asList(arrays));<br><span style="font-weight: bold;line-height: 26px;">for</span> (String str : list) {<br> <span style="font-weight: bold;line-height: 26px;">if</span> (str.equals(<span style="color: #d14;line-height: 26px;">"1"</span>)) {<br> list.remove(str);<br> }<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">上面的代码我们使用 <code style="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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">foreach</code> 方式遍历 List 集合,如果符合条件,将会从集合中删除改元素。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">这个程序编译正常,但是运行时,程序将会发生异常,日志如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #333;background: #f8f8f8;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">java.util.ConcurrentModificationException<br> at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:939)<br> at java.base/java.util.ArrayList$Itr.next(ArrayList.java:893)<br></code></pre> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">可以看到程序最终错误是由 <code style="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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">ArrayList$Itr.next</code> 处的代码抛出,但是代码中我们并没有调用该方法,为什么会这样?</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">实际是因为 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">foreach</code> 这种方式实际上 Java 给我们提供的一种语法糖,编译之后将会变为另一种方式。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">我们将上面的代码产生 class 文件反编来看下最后代码长的啥样。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.4798061389337641" src="/upload/137a8e361d6b9439edf9d28012baf9e.jpg" data-type="jpeg" data-w="619" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">可以看到 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">foreach</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">Iterator</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">foreach</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">Iterator</code>接口的原因。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">接着我们来看下抛出异常方法:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.18181818181818182" src="/upload/de6dce69d7ee69aebc80a746e4433d82.jpg" data-type="jpeg" data-w="1298" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;"><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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">expectedModCount</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">list#iterator</code> 方法:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.6365384615384615" src="/upload/c2bcb38a7998cd61fe8e2e0dba8e7a74.jpg" data-type="jpeg" data-w="1040" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">也就是说刚开始遍历循环的时候 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">expectedModCount==modCount</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">modCount</code>。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;"><code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">modCount</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">ArrayList</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">AbstractList</code>,可以用来记录 List 集合被修改的次数。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.08414239482200647" src="/upload/32b05ad9bfbe3fa948d05fb635981f1f.jpg" data-type="jpeg" data-w="2472" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;"><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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">ArrayList#remove</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">modCount</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">expectedModCount</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">modCount</code> 将会不相等,这就导致迭代器遍历时将会抛错。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.7474048442906575" src="/upload/6da06c40cc1da5603f74ec4f18b9d649.jpg" data-type="jpeg" data-w="1445" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> </figure> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;background: rgb(251, 249, 253);color: rgb(106, 115, 125);margin-bottom: 20px;margin-top: 20px;padding: 15px 20px;line-height: 27px;border-left-color: rgb(53, 179, 120);"> <p style="line-height: 26px;font-size: 15px;color: rgb(89, 89, 89);"><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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">modCount</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">ArrayList</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">modCount</code> 加 1。但是如 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">CopyOnWriteArrayList</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">modCount</code> 计数。</p> <p style="line-height: 26px;font-size: 15px;color: rgb(89, 89, 89);">所以 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">CopyOnWriteArrayList</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">foreach</code> 删除是安全的,但是还是建议使用如下两种删除元素,统一操作。</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">修复的办法有两种:</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;"><strong style="line-height: 1.75em;">使用 Iterator#remove 删除元素</strong></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.4662480376766091" src="/upload/d1aadf68d1d29c4f7d46b19183f83ae2.jpg" data-type="jpeg" data-w="637" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;font-family: PingFangSC-Light;"> iterator </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;"><strong style="line-height: 1.75em;">JDK1.8 List#removeIf</strong></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.28728414442700156" src="/upload/c609760eecd1865f00aef9a3786edc0f.jpg" data-type="jpeg" data-w="637" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">推荐使用 JDK1.8 这种方式,简洁明了。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;"><strong style="line-height: 1.75em;">思考</strong></p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">如果我将上面 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">foreach</code> 代码判断条件简单修改一下:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.4065934065934066" src="/upload/fc89b5e8747562b44a717a44ca183a8a.jpg" data-type="jpeg" data-w="637" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">运行这段代码,可以发现这段代码又不会报错了,有没有很意外?</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;text-align: center;background-image: url("https://mmbiz.qpic.cn/mmbiz_png/LEFcpfxrbq7lsCNncLAFicib819rONCZGn6dE9ycJSGIZPu3vMRK4n9FMTduFGgpD3hBwolwVgXDTJXz3dM8bIEg/640?wx_fmt=png");background-position: center center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 50px;margin-top: 1em;margin-bottom: 10px;"><span style="display: none;"></span><span style="display: inline-block;height: 38px;line-height: 42px;color: rgb(72, 179, 120);background-position: left center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 63px;margin-top: 38px;font-size: 18px;margin-bottom: 10px;">总结</span></h2> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">第一,我们不要先入为主,想当然就认为 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">Arrays.asList</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">List.subList</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">ArrayList</code>。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">如果没办法,使用了 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">Arrays.asList</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">List.subList</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">java.util.ArrayList</code>。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">第二 JDK 的提供的不可变集合实际非常笨重,并且低效,还不安全,所以推荐使用 Guava 不可变集合代替。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">最后,切记,不要随便在 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">foreach</code>增加/删除元素。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;"><br mpa-from-tpl="t"></p>
作者:微信小助手
<section data-mpa-template="t" mpa-from-tpl="t" data-mpa-powered-by="yiban.io"> <section data-id="94941" mpa-from-tpl="t"> <section style="margin: 0px auto;padding-right: 10px;" mpa-from-tpl="t"> <section style="border-width: 1px;border-style: solid;border-color: rgb(0, 68, 88);" mpa-from-tpl="t"> <section style="display: flex;justify-content: space-between;align-items: flex-start;" mpa-from-tpl="t"> <section style="width: 6px;height: 6px;background: rgb(0, 68, 88);" mpa-from-tpl="t"> <br> </section> <section style="width: 6px;height: 6px;background: rgb(0, 68, 88);" mpa-from-tpl="t"> <br> </section> </section> <section style="border-width: 1px;border-style: dashed;border-color: rgb(243, 135, 143);margin: 0px 6px;box-sizing: border-box;" mpa-from-tpl="t"> <section data-autoskip="1" style="color: rgb(63, 62, 63);font-size: 14px;letter-spacing: 1.5px;text-align: justify;line-height: 1.75em;padding: 1em;" mpa-from-tpl="t"> <p mpa-is-content="t"><span style="font-size: 16px;">我们使用的app大多都有分享的功能,我们可以选择分享到不同的地方,比如微博、微信、QQ等等,虽然是同一个内容,但是分享到不同的平台就会有不同的处理方式,比如要跳转到不同的app或者直接复制链接等等。如果让你来实现这个功能,你会如何实现呢?</span></p> </section> </section> <section style="display: flex;justify-content: space-between;align-items: flex-start;" mpa-from-tpl="t"> <section style="width: 6px;height: 6px;background: rgb(0, 68, 88);" mpa-from-tpl="t"> <br> </section> <section style="width: 6px;height: 6px;background: rgb(0, 68, 88);" mpa-from-tpl="t"> <br> </section> </section> </section> <section style="width: 30px;float: right;margin-top: -25px;margin-right: -10px;transform: rotate(0deg);" mpa-from-tpl="t"> <img data-ratio="0.9473684210526315" src="/upload/2e5db2cf5b81d24842985c76b72fca6b.null" data-w="57" data-width="100%" style="width: 100%;display: block;"> </section> </section> </section> </section> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.7070484581497798" data-s="300,640" src="/upload/24bca5bd8d5f5bfa5faa229b9c4960a3.png" data-type="png" data-w="454" style=""></p> <p cid="n19" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 1rem;margin-bottom: 1.5em;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;"><span style="box-sizing: border-box;font-size: 17px;">如果你对设计模式不熟悉,那么第一反应就是有if...else或者switch语句来进行条件判断,根据用户的不同选择而使用不同的处理方法。我们用代码简化地处理一下:</span></p> <section style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">public</span> <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">void</span> Share{<br><span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">public</span> <span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">void</span> <span style="line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">shareOptions</span><span style="line-height: inherit;color: rgb(255, 152, 35);overflow-wrap: inherit !important;word-break: inherit !important;">(String option)</span></span>{<br> <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">if</span>(option.equals(<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"微博"</span>)){<br> <span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//function1();</span><br> <span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//...</span><br> }<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">else</span> <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">if</span>(option.equals(<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"微信"</span>)){<br> <span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//function2();</span><br> <span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//...</span><br> }<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">else</span> <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">if</span>(option.equals(<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"朋友圈"</span>)){<br> <span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//function3();</span><br> <span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//...</span><br> }<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">else</span> <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">if</span>(option.equals(<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"QQ"</span>)){<br> <span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//function4();</span><br> <span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//...</span><br> }<br> <span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//...</span><br>}<br></code></pre> </section> <p cid="n19" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 1rem;margin-bottom: 1.5em;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;"><br></p> <p cid="n9" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 1rem;margin-bottom: 1.5em;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;"><span style="box-sizing: border-box;font-size: 17px;">如果只是写一个这么简单的功能,那么这样的代码也未尝不可,因为这样的代码量不多,后续也不需要怎么拓展和修改,维护起来也不算麻烦。但是,我们工作中遇到的都是一些比较复杂的项目,要保证项目的可读性、可维护性和可拓展性,就必须在代码上下功夫了。</span></p> <p cid="n28" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 1rem;margin-bottom: 1.5em;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;"><span style="box-sizing: border-box;font-size: 17px;">这里我们就要提到一个概念,那就是设计模式了。设计模式是指针对软件开发过程中重复发生的问题的解决办法。其中以被称为Gang of Four(GoF)的4人整理出的23种设计模式最为有名。</span></p> <p cid="n30" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 1rem;margin-bottom: 1.5em;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;"><span style="box-sizing: border-box;font-size: 17px;">当然,我不可能在这里把23种设计模式全部介绍完,就算全部介绍一遍,而且你还能全部记住,也不一定奏效。首先,你没有必要全部记下来,因为这23种设计模式并非都是经常使用到的设计模式。其次,死记硬背下这些设计模式没有任何意义,重要的是在自己脑海中理解设计模式是怎样解决问题的。</span></p> <p cid="n35" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 1rem;margin-bottom: 1.5em;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;"><span style="box-sizing: border-box;font-size: 17px;">今天我们就谈谈可以优化以上问题的设计模式,策略模式(Strategy Design Pattern)。</span></p> <h2 mdtype="heading" cid="n2" style="box-sizing: border-box;break-after: avoid-page;break-inside: avoid;font-size: 1.3125em;margin-top: 2.28571em;margin-bottom: 0.75em;font-weight: bold;line-height: 1.15;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;text-align: start;"><span style="box-sizing: border-box;font-size: 17px;">策略模式(Strategy Design Pattern)</span></h2> <section data-mpa-template="t" mpa-from-tpl="t"> <section style="width: 100%;padding-left: 3px;padding-top: 5px;" data-mid="" mpa-from-tpl="t"> <section style="width: 100%;background: rgb(255, 255, 255);border-width: 1px;border-style: solid;border-color: rgb(28, 32, 178);display: flex;justify-content: flex-start;align-items: flex-start;" data-mid="" mpa-from-tpl="t"> <section style="width: 100%;padding: 17px 13px 31px;background: rgb(255, 255, 255);border-width: 1px;border-style: solid;border-color: rgb(28, 32, 178);font-size: 14px;font-weight: 500;color: rgb(54, 56, 183);line-height: 20px;margin: -4px 3px 4px -3px;z-index: 3;" data-mid="" mpa-from-tpl="t"> <p data-mid="" mpa-is-content="t"><span style="font-size: 16px;">策略指的是计策、谋略,而模式一般指人为整理而成的,在某种场景下重复发生的问题的解决办法。在编程中,我们可以把策略看做是“算法”,而策略模式,按照GoF的定义,就是我们设计一些算法,把它们封装起来,让它们可以相互替换,这样就可以轻松地切换不同的算法来解决同一个问题。</span></p> </section> </section> <section style="width: 100%;display: flex;justify-content: flex-end;align-items: flex-start;padding-right: 13px;" data-mid="" mpa-from-tpl="t"> <section data-mid="" mpa-from-tpl="t" style="width: 16px;height: 16px;background: url("https://mmbiz.qpic.cn/sz_mmbiz_png/w0loKR5CKk93rbDvkNZumkZoYicTauMVb4I3lHr6sAohGhcjLYUXzBpY8ticBcdjWtBBS1kfdxXOMcExkQG2X5lQ/640") center center / contain no-repeat;margin-top: -21px;z-index: 10;"> <br> </section> </section> </section> </section> <p><br></p> <p cid="n37" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 1rem;margin-bottom: 1.5em;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;"><span style="box-sizing: border-box;font-size: 17px;">我们看一下策略模式中有哪些角色。</span></p> <ul class="list-paddingleft-2" cid="n45" mdtype="list" data-mark="-" style="list-style: none;margin-top: 0.5em;margin-bottom: 1.5em;margin-left: 1.5em;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;white-space: normal;"> <li style="box-sizing: border-box;list-style-type: disc;list-style-position: outside;font-size: 17px;"><p cid="n39" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-bottom: 0.5rem;white-space: pre-wrap;"><span style="box-sizing: border-box;font-size: 17px;">Strategy(策略)Strategy角色负责决定实现策略所必需的接口(API)。在示例程序中,由strategy接口扮演此角色。</span></p></li> <li style="box-sizing: border-box;list-style-type: disc;list-style-position: outside;font-size: 17px;"><p cid="n46" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-bottom: 0.5rem;white-space: pre-wrap;"><span style="box-sizing: border-box;font-size: 17px;">ConcreteStrategy(具体的策略)ConcreteStrategy角色负责实现Strategy角色的接口(API),即负责实现具体的策略(战略、方向、方法和算法)。</span></p></li> <li style="box-sizing: border-box;list-style-type: disc;list-style-position: outside;font-size: 17px;"><p cid="n49" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-bottom: 0.5rem;white-space: pre-wrap;"><span style="box-sizing: border-box;font-size: 17px;">Context(上下文)负责使用Strategy角色。Context角色保存了ConcreteStrategy角色的实例,并使用ConcreteStrategy角色去实现需求(总之,还是要调用Strategy角色的接口(API))。</span></p></li> </ul> <p cid="n57" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 1rem;margin-bottom: 1.5em;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;"><span style="box-sizing: border-box;font-size: 17px;">再看看策略模式的类图:</span></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.5667090216010165" data-s="300,640" src="/upload/afb0f82ca2c0b032ffdf7b3e390ff62f.png" data-type="png" data-w="787" style=""></p> <p cid="n7" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 1rem;margin-bottom: 1.5em;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;"><span style="box-sizing: border-box;font-size: 17px;">介绍到这里,相信你对策略模式有了初步的认识,那我们就用策略模式来重构前面的代码,让你加深对策略模式的理解。</span><br></p> <section style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//定义策略接口</span><br><span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">public</span> <span style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">interface</span> <span style="line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">DealStrategy</span></span>{<br> <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">void</span> <span style="line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">dealMythod</span><span style="line-height: inherit;color: rgb(255, 152, 35);overflow-wrap: inherit !important;word-break: inherit !important;">(String option)</span></span>;<br>}<br><br><span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//定义具体的策略1</span><br><span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">public</span> <span style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">class</span> <span style="line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;"><span style="color: rgb(165, 218, 45);font-family: Consolas, Inconsolata, Courier, monospace;font-size: 14px;white-space: pre;background-color: rgb(40, 43, 46);">Deal</span>Sina</span> <span style="line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">implements</span> <span style="line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">DealStrategy</span></span>{<br> <span style="font-size: inherit;line-height: inherit;color: rgb(91, 218, 237);overflow-wrap: inherit !important;word-break: inherit !important;">@override</span><br> <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">public</span> <span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">void</span> <span style="line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">dealMythod</span><span style="line-height: inherit;color: rgb(255, 152, 35);overflow-wrap: inherit !important;word-break: inherit !important;">(String option)</span></span>{<br> <span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//...</span><br> }<br>}<br><br><span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//定义具体的策略2</span><br><span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">public</span> <span style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">class</span> <span style="line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;"><span style="color: rgb(165, 218, 45);font-family: Consolas, Inconsolata, Courier, monospace;font-size: 14px;white-space: pre;background-color: rgb(40, 43, 46);">Deal</span>WeChat</span> <span style="line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">implements</span> <span style="line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">DealStrategy</span></span>{<br> <span style="font-size: inherit;line-height: inherit;color: rgb(91, 218, 237);overflow-wrap: inherit !important;word-break: inherit !important;">@override</span><br> <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">public</span> <span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">void</span> <span style="line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">dealMythod</span><span style="line-height: inherit;color: rgb(255, 152, 35);overflow-wrap: inherit !important;word-break: inherit !important;">(String option)</span></span>{<br> <span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//...</span><br> }<br>}<br><br><span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//定义上下文,负责使用DealStrategy角色</span><br><span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">public</span> <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">static</span> <span style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">class</span> <span style="color: rgb(165, 218, 45);font-family: Consolas, Inconsolata, Courier, monospace;font-size: 14px;white-space: pre;background-color: rgb(40, 43, 46);">Deal</span><span style="line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">Context</span></span>{<br> <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">private</span> String type;<br> <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">private</span> DealStrategy deal;<br> <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">public</span> <span style="color: rgb(165, 218, 45);font-family: Consolas, Inconsolata, Courier, monospace;font-size: 14px;white-space: pre;background-color: rgb(40, 43, 46);">Deal</span><span style="line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">Context</span><span style="line-height: inherit;color: rgb(255, 152, 35);overflow-wrap: inherit !important;word-break: inherit !important;">(String type,DealStrategy deal)</span></span>{<br> <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">this</span>.type = type;<br> <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">this</span>.deal = deal;<br>}<br> <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">public</span> <span style="line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">getDeal</span><span style="line-height: inherit;color: rgb(255, 152, 35);overflow-wrap: inherit !important;word-break: inherit !important;">()</span></span>{<br> <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">return</span> deal;<br> }<br> <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">public</span> <span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">boolean</span> <span style="line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">options</span><span style="line-height: inherit;color: rgb(255, 152, 35);overflow-wrap: inherit !important;word-break: inherit !important;">(String type)</span></span>{<br> <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">return</span> <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">this</span>.type.equals(type);<br> }<br>}<br></code><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><br></code></pre> </section> <p cid="n7" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 1rem;margin-bottom: 1.5em;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;"><br></p> <section style="font-size: 16px;line-height: 1.6;letter-spacing: 0px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;"> <pre style="font-size: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span style="color: rgb(169, 183, 198);"><span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">public</span> <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">void</span> Share{<br> <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">private</span> <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">static</span> List<</span><span style="color:#a5da2d;"></span><span style="font-family: Consolas, Inconsolata, Courier, monospace;font-size: 14px;white-space: pre;color: rgb(165, 218, 45);background-color: rgb(40, 43, 46);">Deal</span><span style="font-family: Consolas, Inconsolata, Courier, monospace;font-size: 14px;white-space: pre;background-color: rgb(40, 43, 46);line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">Context</span><span style="color:#a9b7c6;">> algs = </span><span style="color: rgb(248, 35, 117);font-size: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">new</span><span style="color:#a9b7c6;"> ArrayList();</span><span style="color:#a9b7c6;"><br> </span><span style="color: rgb(128, 128, 128);font-size: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">//静态代码块,先加载所有的策略</span><span style="color:#a9b7c6;"><br> </span><span style="color: rgb(248, 35, 117);font-size: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">static</span><span style="color:#a9b7c6;"> {</span><span style="color:#a9b7c6;"><br> algs.add(</span><span style="color: rgb(248, 35, 117);font-size: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">new</span><span style="color:#a9b7c6;"> </span><span style="color: rgb(165, 218, 45);font-family: Consolas, Inconsolata, Courier, monospace;font-size: 14px;white-space: pre;background-color: rgb(40, 43, 46);"></span><span style="font-family: Consolas, Inconsolata, Courier, monospace;font-size: 14px;white-space: pre;color: rgb(165, 218, 45);background-color: rgb(40, 43, 46);">Deal</span><span style="font-family: Consolas, Inconsolata, Courier, monospace;font-size: 14px;white-space: pre;background-color: rgb(40, 43, 46);line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">Context</span><span style="color:#a9b7c6;">(</span><span style="color: rgb(238, 220, 112);font-size: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">"Sina"</span><span style="color:#a9b7c6;">,</span><span style="color: rgb(248, 35, 117);font-size: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">new</span><span style="color:#a9b7c6;"> DealSina()));</span><span style="color:#a9b7c6;"><br> algs.add(</span><span style="color: rgb(248, 35, 117);font-size: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">new</span><span style="color:#a9b7c6;"> <span style="font-family: Consolas, Inconsolata, Courier, monospace;font-size: 14px;white-space: pre;color: rgb(165, 218, 45);background-color: rgb(40, 43, 46);">Deal</span><span style="font-family: Consolas, Inconsolata, Courier, monospace;font-size: 14px;white-space: pre;background-color: rgb(40, 43, 46);line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">Context</span>(</span><span style="color: rgb(238, 220, 112);font-size: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">"WeChat"</span><span style="color:#a9b7c6;">,</span><span style="color: rgb(248, 35, 117);font-size: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">new</span><span style="color:#a9b7c6;"> DealWeChat()));</span><span style="color:#a9b7c6;"><br> }</span><span style="color:#a9b7c6;"><br></span><span style="color: rgb(248, 35, 117);font-size: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">public</span> <span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">void</span> <span style="line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">shareOptions</span><span style="line-height: inherit;color: rgb(255, 152, 35);overflow-wrap: inherit !important;word-break: inherit !important;">(String type)</span></span><span style="color:#a9b7c6;">{</span><span style="color:#a9b7c6;"><br> DealStrategy dealStrategy = </span><span style="color: rgb(248, 35, 117);font-size: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">null</span><span style="color:#a9b7c6;">;</span><span style="color:#a9b7c6;"><br> </span><span style="color: rgb(248, 35, 117);font-size: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">for</span><span style="color:#a9b7c6;"> (<span style="font-family: Consolas, Inconsolata, Courier, monospace;font-size: 14px;white-space: pre;color: rgb(165, 218, 45);background-color: rgb(40, 43, 46);">Deal</span><span style="font-family: Consolas, Inconsolata, Courier, monospace;font-size: 14px;white-space: pre;background-color: rgb(40, 43, 46);line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">Context</span> deal : algs) {</span><span style="color:#a9b7c6;"><br> </span><span style="color: rgb(248, 35, 117);font-size: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">if</span><span style="color:#a9b7c6;"> (deal.options(type)) {</span><span style="color:#a9b7c6;"><br> dealStrategy = deal.getDeal();</span><span style="color:#a9b7c6;"><br> </span><span style="color: rgb(248, 35, 117);font-size: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">break</span><span style="color:#a9b7c6;">;</span><span style="color:#a9b7c6;"><br> } </span><span style="color:#a9b7c6;"><br> }</span><span style="color:#a9b7c6;"><br> dealStrategy.dealMythod(type);</span><span style="color:#a9b7c6;"><br> }</span><span style="color:#a9b7c6;"><br>}</span><span style="color:#a9b7c6;"><br></span></code></pre> </section> <p cid="n4" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 1rem;margin-bottom: 1.5em;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;"><span style="font-size: 17px;box-sizing: border-box;">再回忆一下策略模式中的各个角色,代码中的DealStrategy接口就是策略,DealSina和DealWeChat是具体的策略,DealContext就是使用策略的上下文。<br></span></p> <p cid="n69" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 1rem;margin-bottom: 1.5em;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;"><span style="box-sizing: border-box;font-size: 17px;">所以这样的代码已经符合策略模式的代码结构了。我们通过策略模式将策略的定义、创建、使用解耦,让每一部分都不至于太复杂,也去除了if...else这样的条件判断语句,代码的可维护性和可拓展性都提高了。</span></p> <p cid="n67" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 1rem;margin-bottom: 1.5em;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;"><span style="box-sizing: border-box;font-size: 17px;">我们把可变的部分放到 了Share 类中的静态代码段中。如果有新的需求,要添加一个分享的方式时,只需要定义好具体的策略,然后修改 Share 类中的静态代码段,其他代码都不需要修改。</span></p> <p cid="n76" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 1rem;margin-bottom: 1.5em;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;"><span style="box-sizing: border-box;font-size: 17px;">策略模式还是比较常用的一种设计模式,比如java中给我定义好的Comparator 接口就是策略模式的一个实践。</span></p> <p cid="n76" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 1rem;margin-bottom: 1.5em;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;"><span style="box-sizing: border-box;font-size: 17px;">如果需要对某个类的排序,而该类没有实现Comparable接口,那么可以建立一个实现Comparator接口的比较器即可。通过实现Comparator类来新建一个比较器,然后通过该比较器来对类进行排序。</span></p> <section style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//策略接口</span><br><span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">public</span> <span style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">interface</span> <span style="line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">Comparator</span><<span style="line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">T</span>> </span>{<br> <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">int</span> <span style="line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">compare</span><span style="line-height: inherit;color: rgb(255, 152, 35);overflow-wrap: inherit !important;word-break: inherit !important;">(T o1, T o2)</span></span>;<br>}<br><br><span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//需要我们来定义具体的策略</span><br><span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">public</span> <span style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">class</span> <span style="line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">sorter</span> <span style="line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">implements</span> <span style="line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">Comparator</span></span>{<br> <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">public</span> <span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">int</span> <span style="line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">compare</span><span style="line-height: inherit;color: rgb(255, 152, 35);overflow-wrap: inherit !important;word-break: inherit !important;">(String s1, String s2)</span> </span>{<br> <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">return</span> Integer.compare(s1.length(), s2.length());<br> }<br>}<br><span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//一般我们会用更简洁的Lambda表达式来实现</span><br></code></pre> </section> <p cid="n76" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 1rem;margin-bottom: 1.5em;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;"><br></p> <p cid="n73" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 1rem;margin-bottom: 1.5em;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;"><span style="box-sizing: border-box;font-size: 17px;">如果你使用的是Java ,想更符合开闭原则,并对反射有一定了解,那还可以通过反射来避免对类的修改。</span></p> <p cid="n73" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 1rem;margin-bottom: 1.5em;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;"><span style="box-sizing: border-box;font-size: 17px;">你可以通过一个配置文件或者定义一个注解来标注定义的策略类;通过读取配置文件或者搜索被标注的策略类,通过反射动态地加载这些策略类、创建策略对象;当我们新添加一个策略的时候,只需要将这个新添加的策略类添加到配置文件或者用定义的注解标注即可。</span></p> <p cid="n88" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 1rem;margin-bottom: 1.5em;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;"><span style="box-sizing: border-box;font-size: 17px;">Strategy模式特意将算法与其他部分分离开来,只是定义了与算法相关的接口(APl),然后在程序中以委托的方式来使用算法。</span></p> <p cid="n88" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 1rem;margin-bottom: 1.5em;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;"><span style="box-sizing: border-box;font-size: 17px;">这样看起来程序好像变复杂了,其实不然。例如,当我们想要通过改善算法来提高算法的处理速度时,如果使用了Strategy模式,就不必修改Strategy角色的接口(API)了,仅仅修改ConcreteStrategy角色即可。</span></p> <p cid="n88" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 1rem;margin-bottom: 1.5em;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;"><span style="box-sizing: border-box;font-size: 17px;">而且,使用委托这种弱关联关系可以很方便地整体替换算法。例如,使用Strategy模式编写棋类程序时,可以方便地根据棋手的选择切换AI电脑的水平。</span></p> <p cid="n92" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 1rem;margin-bottom: 1.5em;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;"><span style="box-sizing: border-box;font-size: 17px;">至此,我们可以小结出策略模式的使用场景:</span></p> <ul class="list-paddingleft-2" cid="n100" mdtype="list" data-mark="-" style="list-style: none;margin-top: 0.5em;margin-bottom: 1.5em;margin-left: 1.5em;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;white-space: normal;"> <li style="box-sizing: border-box;list-style-type: disc;list-style-position: outside;font-size: 17px;"><p cid="n97" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-bottom: 0.5rem;white-space: pre-wrap;"><span style="box-sizing: border-box;font-size: 17px;">一个项目中有许多类,它们之间的区别仅在于它们的行为,希望动态地让一个对象在许多行为中选择一种行为时;</span></p></li> <li style="box-sizing: border-box;list-style-type: disc;list-style-position: outside;font-size: 17px;"><p cid="n101" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-bottom: 0.5rem;white-space: pre-wrap;"><span style="box-sizing: border-box;font-size: 17px;">一个项目需要动态地在几种算法中选择一种时;</span></p></li> <li style="box-sizing: border-box;list-style-type: disc;list-style-position: outside;font-size: 17px;"><p cid="n104" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-bottom: 0.5rem;white-space: pre-wrap;"><span style="box-sizing: border-box;font-size: 17px;">一个对象有很多的行为,不想使用多重的条件选择语句来选择使用哪个行为时。</span></p></li> </ul> <p cid="n104" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-bottom: 0.5rem;white-space: pre-wrap;"><span style="font-family: 'PingFang SC', 'Lantinghei SC', 'Microsoft Yahei', 'Hiragino Sans GB', 'Microsoft Sans Serif', 'WenQuanYi Micro Hei', Helvetica, sans-serif;text-align: start;background-color: rgb(255, 255, 255);"></span><br mpa-from-tpl="t"></p> <section data-mpa-template="t" mpa-from-tpl="t"> <section style="width: 100%;" data-mid="" mpa-from-tpl="t"> <section style="width: 100%;padding: 0px 1px;" data-mid="" mpa-from-tpl="t"> <section style="width: 100%;padding: 13px 13px 25px;border-width: 1px;border-style: dashed;border-color: rgb(113, 182, 253);font-size: 14px;font-weight: 500;color: rgb(86, 86, 86);line-height: 20px;" data-mid="" mpa-from-tpl="t"> <p data-mid="" mpa-is-content="t"><span style="font-size: 16px;">策略模式不仅仅可以优化if else代码,其主要的作用还是解耦策略的定义、创建和使用,控制代码的复杂度,让每个部分都不至于过于复杂、代码量过多。除此之外,对于复杂代码来说,策略模式还能让其满足开闭原则,添加新策略的时候,最小化、集中化代码改动,减少引入 bug 的风险。</span></p> </section> </section> <section style="width: 100%;display: flex;justify-content: flex-end;align-items: flex-start;padding-right: 4px;" data-mid="" mpa-from-tpl="t"> <section style="width: 31px;margin-top: -18px;z-index: 10;" data-mid="" mpa-from-tpl="t"> <img data-ratio="0.5161290322580645" src="/upload/cd9eaf1b861a627cf7d1be6171f9bdf8.null" data-w="124" style="width: 100%;display: block;"> </section> </section> <section style="width: 100%;display: flex;justify-content: flex-end;align-items: flex-start;" data-mid="" mpa-from-tpl="t"> <section style="width: 70.8%;height: 3px;background: rgb(113, 182, 253);border-radius: 1px;margin-top: -2px;z-index: 20;" data-mid="" mpa-from-tpl="t"> <br> </section> </section> </section> </section> <p style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 1rem;margin-bottom: 1.5em;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;"><br></p> <p cid="n104" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 1rem;margin-bottom: 1.5em;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;"><span style="box-sizing: border-box;font-size: 17px;">可能有人会问:状态模式也可以优化if else,那么策略模式和状态模式又有什么不同呢?</span></p> <p cid="n104" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 1rem;margin-bottom: 1.5em;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;"><span style="box-sizing: border-box;font-size: 17px;">让我们来简单回顾一下状态模式的类图:</span></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.6317780580075663" data-s="300,640" src="/upload/d8ad0d87ca12445c5c34bd9354b1d605.png" data-type="png" data-w="793" style=""></p> <p style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 1rem;margin-bottom: 1.5em;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;"><span style="box-sizing: border-box;font-size: 17px;">使用策略模式和状态模式都可以替换被委托对象,而且它们的类之间的关系也很相似。但是两种模式的目的不同。</span></p> <p style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 1rem;margin-bottom: 1.5em;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;"><span style="box-sizing: border-box;font-size: 17px;">在策略模式中,ConcreteStrategy角色是表示算法的类。在Strategy模式中,可以替换被委托对象的类。当然如果没有必要,也可以不替换。</span></p> <p style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 1rem;margin-bottom: 1.5em;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;"><span style="box-sizing: border-box;font-size: 17px;">而在状态模式中,ConcreteState角色是表示“状态”的类。在State模式中,每次状态变化时,被委托对象的类都必定会被替换。</span></p> <p style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 1rem;margin-bottom: 1.5em;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;"><span style="box-sizing: border-box;font-size: 17px;"><br></span></p> <p cid="n86" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 1rem;margin-bottom: 1.5em;white-space: pre-wrap;color: rgb(31, 9, 9);font-family: "PT Serif", "Times New Roman", Times, serif;font-size: 16px;text-align: start;"><span style="box-sizing: border-box;font-size: 17px;">好了,关于策略模式我们就是介绍到这里。</span><span style="font-size: 17px;">你</span><span style="font-size: 17px;">在做项目时用过策略模式吗?</span><span style="font-size: 17px;">是在什么场景中使</span><span style="font-size: 17px;">用呢?</span><span style="font-size: 17px;">欢迎留言说说。</span></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.4846715328467153" data-s="300,640" src="/upload/5fefdcf380ddc05fd14d59ab0167d19d.png" data-type="png" data-w="685" style="width: 436px;height: 212px;"></p> <p style="text-align: center;"><br></p> <p style="letter-spacing: 0.544px;font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;widows: 1;line-height: 25.6px;text-align: center;"><span style="font-size: 18px;line-height: 28.8px;">喜欢本文的朋友,欢迎关注公众号 </span><span style="font-size: 18px;line-height: 28.8px;color: rgb(255, 76, 0);"><strong>程序员小灰</strong></span><span style="font-size: 18px;line-height: 28.8px;">,收看更多精彩内容</span></p> <p style="letter-spacing: 0.544px;font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;widows: 1;line-height: 25.6px;text-align: center;"><img data-copyright="0" data-ratio="1" data-s="300,640" data-type="jpeg" data-w="344" src="/upload/37f513ecb7627cdbb355876dab88096.jpg" style="font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;box-sizing: border-box !important;visibility: visible !important;width: 333px !important;"></p> <section powered-by="xiumi.us"> <section> <section> <pre style="font-size: inherit;color: inherit;line-height: inherit;"> <section data-tools="135编辑器" data-id="94250" style="letter-spacing: 0.544px;white-space: normal;border-width: 0px;border-style: none;border-color: initial;"> <section data-tools="135编辑器" data-id="91842" style="border-width: 0px;border-style: none;border-color: initial;"> <section style="text-align: right;width: auto;"> <section style="display: inline-block;clear: both;"> <section data-brushtype="text" style="padding: 18px 15px 20px 10px;color: rgb(86, 146, 214);text-align: center;letter-spacing: 1.5px;background-image: url("https://mmbiz.qpic.cn/mmbiz_png/Pn4Sm0RsAuhpplm16ibb8iaib7RoGQ5iaHEdy66AHd7QqL7A2s5icSBE0aw4iaKOKPnXGYxQPhG7VMpbbYV6VJprSh7w/640?wx_fmt=png");background-size: 100% 100%;background-repeat: no-repeat;"> <section style="display: flex;justify-content: center;align-items: center;"> <section style="margin-left: 2px;font-size: 16px;word-spacing: 2px;width: 20px;"> <img data-ratio="0.8936170212765957" data-type="png" data-w="47" src="/upload/737696b8734b6f688ae95660c4411917.png" style="margin-bottom: -6px;box-sizing: border-box !important;visibility: visible !important;width: 20px !important;"> </section> <section data-brushtype="text" style="word-spacing: 2px;font-size: 14px;color: rgb(51, 51, 51);"> <span style="font-family: 楷体, 楷体_GB2312, SimKai;">点个[在看],是对小灰最大的支持!</span> </section> <p><br></p> </section> </section> </section> </section> </section> </section></pre> </section> </section> </section>
作者:じ☆ve不哭
> 使用insert into xxx select REPLACE(uuid(),'-',''), * from xx; 提示主键冲突,这个问题怎么解决呢? ## 复现问题: -- 执行如下SQL ``` SELECT REPLACE(uuid(),'-','') FROM tbl_name limit 100; ```  结果就是uuid重复。 -- 去掉replace ``` SELECT uuid() FROM tbl_name limit 100; ```  结果不再重复。 **结果显而易见,replace搞的鬼。** ## 解决办法 ``` SELECT MD5(uuid()) FROM tbl_com_contact limit 100; ``` **将uuid再一次md5一下就得到32位不带-的uuid了。产生原因尚未翻阅官网暂时无法解释**
作者:微信小助手
<p style="text-align: center;"><span style="font-size: 14px;letter-spacing: 0.5440000295639038px;text-align: center;max-width: 100%;color: rgb(255, 41, 65);line-height: 22.4px;">(给</span><span style="font-size: 14px;letter-spacing: 0.5440000295639038px;text-align: center;max-width: 100%;line-height: 22.4px;color: rgb(0, 128, 255);">ImportNew</span><span style="font-size: 14px;letter-spacing: 0.5440000295639038px;text-align: center;max-width: 100%;color: rgb(255, 41, 65);line-height: 22.4px;">加星标,提高Java技能)</span></p> <blockquote> <p style="letter-spacing: 0.5440000295639038px;white-space: normal;background-color: rgb(255, 255, 255);max-width: 100%;min-height: 1em;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">转自:简书 作者:wangzaiplus</span></p> <p style="letter-spacing: 0.5440000295639038px;white-space: normal;background-color: rgb(255, 255, 255);max-width: 100%;min-height: 1em;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="font-size: 14px;">https://www.jianshu.com/p/6189275403ed</span></p> </blockquote> <h3 style="line-height: 1.5em;"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;letter-spacing: normal;">一、概念</span></strong></span></h3> <p><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></p> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">幂等性, 通俗的说就是一个接口, 多次发起同一个请求, 必须保证操作只能执行一次<br>比如:</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <ul class="list-paddingleft-2"> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">订单接口, 不能多次创建订单</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">支付接口, 重复支付同一笔订单只能扣一次钱</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">支付宝回调接口, 可能会多次回调, 必须处理重复回调</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">普通表单提交接口, 因为网络超时等原因多次点击提交, 只能成功一次<br>等等</span> </section></li> </ul> <h3 style="line-height: 1.5em;"><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></h3> <h3 style="line-height: 1.5em;"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;letter-spacing: normal;">二、常见解决方案</span></strong></span></h3> <p><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></p> <ol class="list-paddingleft-2"> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">唯一索引 -- 防止新增脏数据</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">token机制 -- 防止页面重复提交</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">悲观锁 -- 获取数据的时候加锁(锁表或锁行)</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">乐观锁 -- 基于版本号version实现, 在更新数据那一刻校验数据</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">分布式锁 -- redis(jedis、redisson)或zookeeper实现</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">状态机 -- 状态变更, 更新数据时判断状态</span> </section></li> </ol> <h3 style="line-height: 1.5em;"><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></h3> <h3 style="line-height: 1.5em;"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;letter-spacing: normal;">三、本文实现</span></strong></span></h3> <p><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></p> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">本文采用第2种方式实现, 即通过redis + token机制实现接口幂等性校验</span> </section> <h3 style="line-height: 1.5em;"><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></h3> <h3 style="line-height: 1.5em;"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;letter-spacing: normal;">四、实现思路</span></strong></span></h3> <p><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></p> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">为需要保证幂等性的每一次请求创建一个唯一标识token, 先获取token, 并将此token存入redis, 请求接口时, 将此token放到header或者作为请求参数请求接口, 后端接口判断redis中是否存在此token:</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <ul class="list-paddingleft-2"> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">如果存在, 正常处理业务逻辑, 并从redis中删除此token, 那么, 如果是重复请求, 由于token已被删除, 则不能通过校验, 返回请勿重复操作提示</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">如果不存在, 说明参数不合法或者是重复请求, 返回提示即可</span> </section></li> </ul> <h3 style="line-height: 1.5em;"><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></h3> <h3 style="line-height: 1.5em;"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;letter-spacing: normal;">五、项目简介</span></strong></span></h3> <p><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></p> <ul class="list-paddingleft-2"> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">springboot</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">redis</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">@ApiIdempotent注解 + 拦截器对请求进行拦截</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">@ControllerAdvice全局异常处理</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">压测工具: jmeter</span> </section></li> </ul> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">说明:</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <ul class="list-paddingleft-2"> <li> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">本文重点介绍幂等性核心实现, 关于springboot如何集成redis、ServerResponse、ResponseCode等细枝末节不在本文讨论范围之内, 有兴趣的小伙伴可以查看我的Github项目: </span> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">https://github.com/wangzaiplus/springboot/tree/wxw</span> </section></li> </ul> <p style="line-height: 1.5em;"><br></p> <h3 style="line-height: 1.5em;"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;letter-spacing: normal;">六、代码实现</span></strong></span></h3> <p><span style="font-size: 15px;letter-spacing: normal;color: rgb(0, 0, 0);"><br></span></p> <p><strong>1.pom</strong></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> </ul> <pre class="code-snippet__js" data-lang="xml"><code><span class="code-snippet_outer"><span class="code-snippet__comment"><!-- Redis-Jedis --></span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag"><<span class="code-snippet__name">dependency</span>></span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag"><<span class="code-snippet__name">groupId</span>></span>redis.clients<span class="code-snippet__tag"></<span class="code-snippet__name">groupId</span>></span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag"><<span class="code-snippet__name">artifactId</span>></span>jedis<span class="code-snippet__tag"></<span class="code-snippet__name">artifactId</span>></span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag"><<span class="code-snippet__name">version</span>></span>2.9.0<span class="code-snippet__tag"></<span class="code-snippet__name">version</span>></span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag"></<span class="code-snippet__name">dependency</span>></span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"><!--lombok 本文用到@Slf4j注解, 也可不引用, 自定义log即可--></span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag"><<span class="code-snippet__name">dependency</span>></span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag"><<span class="code-snippet__name">groupId</span>></span>org.projectlombok<span class="code-snippet__tag"></<span class="code-snippet__name">groupId</span>></span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag"><<span class="code-snippet__name">artifactId</span>></span>lombok<span class="code-snippet__tag"></<span class="code-snippet__name">artifactId</span>></span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag"><<span class="code-snippet__name">version</span>></span>1.16.10<span class="code-snippet__tag"></<span class="code-snippet__name">version</span>></span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag"></<span class="code-snippet__name">dependency</span>></span></span></code></pre> </section> <section style="line-height: 1.5em;"> <br> </section> <p style="line-height: 1.5em;"><strong><span style="font-size: 15px;letter-spacing: normal;color: rgb(0, 0, 0);">2.JedisUtil</span></strong></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> </ul> <pre class="code-snippet__js" data-lang="kotlin"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">package</span> com.wangzaiplus.test.util;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">import</span> lombok.extern.slf4j.Slf4j;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">import</span> org.springframework.beans.factory.<span class="code-snippet__keyword">annotation</span>.Autowired;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">import</span> org.springframework.stereotype.Component;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">import</span> redis.clients.jedis.Jedis;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">import</span> redis.clients.jedis.JedisPool;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__meta">@Component</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__meta">@Slf4j</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">public</span> <span class="code-snippet__class"><span class="code-snippet__keyword">class</span> <span class="code-snippet__title">JedisUtil</span> </span>{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__meta">@Autowired</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">private</span> JedisPool jedisPool;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">private</span> Jedis getJedis() {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> jedisPool.getResource();</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">/**</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * 设值</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> *</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * <span class="code-snippet__doctag">@param</span> key</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * <span class="code-snippet__doctag">@param</span> value</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * <span class="code-snippet__doctag">@return</span></span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> */</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">public</span> String <span class="code-snippet__keyword">set</span>(String key, String value) {</span></code><code><span class="code-snippet_outer"> Jedis jedis = <span class="code-snippet__literal">null</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">try</span> {</span></code><code><span class="code-snippet_outer"> jedis = getJedis();</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> jedis.<span class="code-snippet__keyword">set</span>(key, value);</span></code><code><span class="code-snippet_outer"> } <span class
作者:微信小助手
<p style="line-height: normal;"><br></p> <section data-tools="135编辑器" data-id="93073"> <section> <section data-width="90%"> <section data-tools="135编辑器" data-id="90422"> <section> <section data-width="100%"> <section> <section style="box-sizing: border-box;font-size: 16px;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: 100%;vertical-align: top;box-sizing: border-box;"> <section style="text-align: center;margin-top: 10px;margin-right: 0%;margin-left: 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;vertical-align: bottom;width: 33.33%;box-sizing: border-box;line-height: 0;"> <section style="line-height: 0;width: 0px;"> <svg viewbox="0 0 1 1" style="vertical-align:top;"></svg> </section> </section> <section style="display: inline-block;vertical-align: bottom;width: 17%;box-sizing: border-box;"> <section style="font-size: 22px;margin-top: 3px;margin-bottom: 3px;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: 1.8em;height: 1.8em;line-height: 1.8em;border-radius: 100%;margin-left: auto;margin-right: auto;font-size: 20px;color: rgb(255, 255, 255);border-width: 1px;border-style: solid;border-color: rgb(89, 89, 89);background-color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">1</p> </section> </section> </section> <section style="display: inline-block;vertical-align: bottom;width: 33.33%;box-sizing: border-box;line-height: 0;"> <section style="line-height: 0;width: 0px;"> <svg viewbox="0 0 1 1" style="vertical-align:top;"></svg> </section> </section> </section> <section style="margin-right: 0%;margin-bottom: 10px;margin-left: 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="text-align: center;white-space: normal;box-sizing: border-box;"><strong>大家听过 MySQL MGR 技术吗?</strong></p> </section> </section> </section> </section> </section> <section style="line-height: normal;"> <br> </section> </section> </section> </section> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">MySQL 是目前最流行的开源关系型数据库,国内金融行业也开始全面使用,其中 MySQL 5.7.17 提出的 MGR(MySQL Group Replication)既可以很好的保证数据一致性又可以自动切换,具备故障检测功能、支持多节点写入,MGR 是一项被普遍看好的技术。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">本文给大家介绍一下 MySQL MGR 技术演变过程、事务生命周期及事务冲突检测机制。</span></p> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: 100%;vertical-align: top;box-sizing: border-box;"> <section style="text-align: center;margin-top: 10px;margin-right: 0%;margin-left: 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;vertical-align: bottom;width: 33.33%;box-sizing: border-box;line-height: 0;"> <section style="line-height: 0;width: 0px;"> <svg viewbox="0 0 1 1" style="vertical-align:top;"></svg> </section> </section> <section style="display: inline-block;vertical-align: bottom;width: 17%;box-sizing: border-box;"> <section style="font-size: 22px;margin-top: 3px;margin-bottom: 3px;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: 1.8em;height: 1.8em;line-height: 1.8em;border-radius: 100%;margin-left: auto;margin-right: auto;font-size: 20px;color: rgb(255, 255, 255);border-width: 1px;border-style: solid;border-color: rgb(89, 89, 89);background-color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">2</p> </section> </section> </section> <section style="display: inline-block;vertical-align: bottom;width: 33.33%;box-sizing: border-box;line-height: 0;"> <section style="line-height: 0;width: 0px;"> <svg viewbox="0 0 1 1" style="vertical-align:top;"></svg> </section> </section> </section> <section style="margin-right: 0%;margin-bottom: 10px;margin-left: 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="text-align: center;white-space: normal;box-sizing: border-box;"><strong>MGR 技术演进</strong></p> </section> </section> </section> </section> </section> <section data-tools="135编辑器" data-id="90422"> <section> <section data-width="100%"> <section data-brushtype="text"> <section style="line-height: normal;"> <br> </section> </section> </section> </section> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">传统的 MySQL 主从复制架构是 MySQL 保持数据一致性的最基本架构,如下图 1 所示,一主一从架构,从库给主库发起读数据请求后,主库会通过 dump线程把 binlog 日志文件推送给从库,从库的 I/O 线程把接收到数据更新到 relay log,之后从库的 SQL 线程把 relay log 应用为 binlog 日志,直到主库与从库的 binlog 日志文件完全数据一致,达到主从同步。</span> </section> <section style="text-align: center;margin-bottom: 5px;"> <img class="rich_pages" data-ratio="0.8966244725738397" data-s="300,640" src="/upload/d3d87839741f978817bf1266ed79bb10.png" data-type="png" data-w="474" style=""> </section> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 14px;"><em><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">图 1:主从复制示意图</span></em></span></p> <section style="line-height: normal;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">接下来我们看一下 MySQL 异步复制,如下图 2 所示,一主两从架构,应用发来的事务请求,经过执行之后写入 binlog,主库 master 把 binlog 日志推送给从库 salve1 和 slave2 ,主库不需要等到从库是否成功更新数据到 relay log,主库直接提交事务即可。这种模式牺牲了数据一致性,不能很好保证主从数据一致性。</span> </section> <section style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"> <img class="rich_pages" data-ratio="0.35775335775335776" data-s="300,640" src="/upload/523aff80d3b318aa3fdbe996d3e8f4fb.png" data-type="png" data-w="819" style=""> </section> <section data-tools="135编辑器" data-id="94342"> <section data-width="96%"> <section> <section> <section> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 14px;"><em><img data-ratio="1" src="/upload/bf5651c2a95fc53ac68a1807c94852b7.gif" data-type="gif" data-w="1" style="width: auto;background-color: rgb(255, 255, 255);caret-color: red;"><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">图 2:异步复制示意图</span></em></span></p> <p style="line-height: normal;"><br></p> </section> </section> </section> </section> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">模拟异步复制场景举例,如下图 3 所示,三个人对话,一个人在不停歇的演讲,不需要知道两个听众是否听懂,听众也不需要做出回应,等演讲完毕,有可能听众没听懂,最终大家认知到信息可能不一致,为了解决上述问题 MySQL 5.5.8 就有了半同步复制。</span> </section> <p style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="rich_pages" data-ratio="1.1090425531914894" data-s="300,640" src="/upload/e8e36198586230d13807d6b198119290.png" data-type="png" data-w="752" style=""></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 14px;"><em><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">图 3:异步复制场景模拟图</span></em></span></p> <section style="line-height: normal;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">接下来看一下 MySQL 的半同步复制,如下图 4 所示,一主两从架构,应用发来的事务请求,在主库执行后写入 binlog,主库 master 把 binlog 日志推送给从库 salve1 和 slave2 ,半同步主库需要等待其中任意一个从库更新数据到 relay log 成功并且告知主库,主库才提交事务,这样保证至少有一个从库同步上数据了,也缩短了延迟时间,保证了数据安全。</span> <img data-ratio="1" src="/upload/bf5651c2a95fc53ac68a1807c94852b7.gif" data-type="gif" data-w="1" style="width: auto;caret-color: red;"> </section> <p style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="rich_pages" data-ratio="0.3301088270858525" data-s="300,640" src="/upload/ad7495add8c9515b8724b4fb6b870a5a.png" data-type="png" data-w="827" style=""></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 14px;"><em><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">图 4:半同步示意图</span></em></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">模拟半同步复制场景举例,如下图 5 所示,三个人对话,一个人在不停歇的演讲,任意一个听众回应听懂了,演讲者就继续往下说,否则停止演讲,最后等演讲结束,至少一听众听懂演讲者的意思,保证信息传递一致性。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">这种复制模式也存在两个问题:</span></p> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">MySQL 无法自动切换,需要借助外力切库,运维复杂。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">从库 Slave 的读压力太大会导致复制延迟不断增加。</span></p></li> </ul> <section style="line-height: normal;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">MySQL5.7 版本的 MGR 技术可以解决上述问题。</span> </section> <p style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="rich_pages" data-ratio="1.1820809248554913" data-s="300,640" src="/upload/199a69e5e46c520e81c093b39a962321.png" data-type="png" data-w="692" style=""></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 14px;"><em><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">图 5:半同步复制场景模拟</span></em></span></p> <section style="line-height: normal;"> <br> </section> <section style="box-sizing: border-box;font-size: 16px;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: 100%;vertical-align: top;box-sizing: border-box;"> <section style="text-align: center;margin-top: 10px;margin-right: 0%;margin-left: 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;vertical-align: bottom;width: 33.33%;box-sizing: border-box;line-height: 0;"> <section style="line-height: 0;width: 0px;"> <svg viewbox="0 0 1 1" style="vertical-align:top;"></svg> </section> </section> <section style="display: inline-block;vertical-align: bottom;width: 17%;box-sizing: border-box;"> <section style="font-size: 22px;margin-top: 3px;margin-bottom: 3px;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: 1.8em;height: 1.8em;line-height: 1.8em;border-radius: 100%;margin-left: auto;margin-right: auto;font-size: 20px;color: rgb(255, 255, 255);border-width: 1px;border-style: solid;border-color: rgb(89, 89, 89);background-color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">3</p> </section> </section> </section> <section style="display: inline-block;vertical-align: bottom;width: 33.33%;box-sizing: border-box;line-height: 0;"> <section style="line-height: 0;width: 0px;"> <svg viewbox="0 0 1 1" style="vertical-align:top;"></svg> </section> </section> </section> <section style="margin-right: 0%;margin-bottom: 10px;margin-left: 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="text-align: center;white-space: normal;box-sizing: border-box;"><strong>至此 MGR 技术诞生!</strong></p> </section> </section> </section> </section> </section> <section data-tools="135编辑器" data-id="90422"> <section> <section data-width="100%"> <section data-brushtype="text"> <section style="line-height: normal;"> <br> </section> </section> </section> </section> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">MGR(MySQL Group Replication)是 MySQL 自带的一个插件,可以灵活部署。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">MySQL MGR 集群是多个 MySQL Server 节点共同组成的分布式集群,每个 Server 都有完整的副本,它是基于 ROW 格式的二进制日志文件和 GTID 特性。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">如下图 6 所示为 MGR 架构图,主要是 APIs 层、组件层、复制协议模块层和 GCS API+Paxos 引擎层构成。</span></p> <section style="line-height: normal;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">如图 6 所示,应用发来的事务从 MySQL Server 经过 MGR 的 APIs 接口层分发到组件层,组件层去 capture 事务相关信息,然后经过复制协议层进行事务传输,最后经过 GCS API+Paxos 引擎层保证事务在各个节点数据最终一致性。这是事务进入 MGR 层内部处理过程。</span> </section> <section data-tools="135编辑器" data-id="94342"> <section data-width="96%"> <section> <section> <p style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="rich_pages" data-ratio="0.8490196078431372" data-s="300,640" src="/upload/52ba3d95fc1cfa17f411be99c277d17f.png" data-type="png" data-w="510" style=""></p> </section> </section> </section> </section> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 14px;"><em><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">图 6:MGR 架构示意图</span></em></span></p> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: 100%;vertical-align: top;box-sizing: border-box;"> <section style="text-align: center;margin-top: 10px;margin-right: 0%;margin-left: 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;vertical-align: bottom;width: 33.33%;box-sizing: border-box;line-height: 0;"> <section style="line-height: 0;width: 0px;"> <svg viewbox="0 0 1 1" style="vertical-align:top;"></svg> </section> </section> <section style="display: inline-block;vertical-align: bottom;width: 17%;box-sizing: border-box;"> <section style="font-size: 22px;margin-top: 3px;margin-bottom: 3px;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: 1.8em;height: 1.8em;line-height: 1.8em;border-radius: 100%;margin-left: auto;margin-right: auto;font-size: 20px;color: rgb(255, 255, 255);border-width: 1px;border-style: solid;border-color: rgb(89, 89, 89);background-color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">4</p> </section> </section> </section> <section style="display: inline-block;vertical-align: bottom;width: 33.33%;box-sizing: border-box;line-height: 0;"> <section style="line-height: 0;width: 0px;"> <svg viewbox="0 0 1 1" style="vertical-align:top;"></svg> </section> </section> </section> <section style="margin-right: 0%;margin-bottom: 10px;margin-left: 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="text-align: center;white-space: normal;box-sizing: border-box;"><strong>MGR 集群中事务整个生命周期啥样?</strong></p> </section> </section> </section> </section> </section> <section data-tools="135编辑器" data-id="90422"> <section> <section data-width="100%"> <section data-brushtype="text"> <section style="line-height: normal;"> <br> </section> </section> </section> </section> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">接下来从全局角度看事务整个生命周期,如下图 7 所示,DB1 、DB2 、DB3 构成的 MGR 集群, 集群中每个 DB 都有 MGR 层,MGR 层功能也可简单理解为由 Paxos 模块和冲突检测 Certify 模块实现。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Paxos 模块是基于 Paxos 算法确保所有节点收到相同广播消息,transaction message 就是广播消息的内容结构;冲突检测 Certify 模块进行冲突检测确保数据最终一致性,其中 certification info 是冲突检测中内存结构。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">本文详细介绍冲突检测模块实现原理,Paxos 算法实现部分后续对比 Raft 算法详细介绍。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">当 DB1 上有事务 T1 要执行时,T1 对 DB1 是来说本地事务,对于 DB2、DB3 来说是远端事务;DB1 上在事务 T1 在被执行后,会把执行事务 T1 信息广播给集群各个节点,包括 DB1 本身,通过 Paxos 模块广播给 MGR 集群各个节点,半数以上的节点同意并且达成共识,之后共识信息进入各个节点的冲突检测 certify 模块,各个节点各自进行冲突检测验证,最终保证事务在集群中最终一致性。</span></p> <section style="line-height: normal;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">在冲突检测通过之后,本地事务 T1 在 DB1 直接提交即可,否则直接回滚。远端事务 T1 在 DB2 和 DB3 分别先更新到 relay log,然后应用到 binlog,完成数据的同步,否则直接放弃该事务。</span> </section> <p style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="rich_pages" data-ratio="0.4925925925925926" data-s="300,640" src="/upload/f118c577b12ed1c1576f975610a50a15.png" data-type="png" data-w="1080" style=""></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 14px;"><em><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">图 7:MGR 组复制技术示意图</span></em></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">前面我们从全局视角介绍了一个事务在 MGR 集群中从开始到结束整个处理过程,接下从局部角度详细介绍冲突检测机制实现机制。</span></p> <section style="line-height: normal;"> <br> </section> <section style="box-sizing: border-box;font-size: 16px;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: 100%;vertical-align: top;box-sizing: border-box;"> <section style="text-align: center;margin-top: 10px;margin-right: 0%;margin-left: 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;vertical-align: bottom;width: 33.33%;box-sizing: border-box;line-height: 0;"> <section style="line-height: 0;width: 0px;"> <svg viewbox="0 0 1 1" style="vertical-align:top;"></svg> </section> </section> <section style="display: inline-block;vertical-align: bottom;width: 17%;box-sizing: border-box;"> <section style="font-size: 22px;margin-top: 3px;margin-bottom: 3px;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: 1.8em;height: 1.8em;line-height: 1.8em;border-radius: 100%;margin-left: auto;margin-right: auto;font-size: 20px;color: rgb(255, 255, 255);border-width: 1px;border-style: solid;border-color: rgb(89, 89, 89);background-color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">5</p> </section> </section> </section> <section style="display: inline-block;vertical-align: bottom;width: 33.33%;box-sizing: border-box;line-height: 0;"> <section style="line-height: 0;width: 0px;"> <svg viewbox="0 0 1 1" style="vertical-align:top;"></svg> </section> </section> </section> <section style="margin-right: 0%;margin-bottom: 10px;margin-left: 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="text-align: center;white-space: normal;box-sizing: border-box;"><strong>transaction message 和 certification info</strong></p> <p style="text-align: center;white-space: normal;box-sizing: border-box;"><strong>分别是什么?</strong></p> </section> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">介绍冲突检测实现原理之前,先介绍一下广播信息 transaction message、冲突检测内存 certification info 的结构组成。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">①transaction message</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">如图 8 所示,transaction message 保存是事务 T1 要更新行的的相关信息,有 transaction_context_log_event 和 gtid_log_event 及 log_event_group 三部分组成。</span></p> <section style="line-height: normal;"> <br> </section> <section data-tools="135编辑器" data-id="97713"> <section> <section> <section> <section data-autoskip="1"> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">具体组成:</span></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="text-align: center;margin-top: 0.5em;margin-bottom: 0.5em;box-sizing: border-box;" powered-by="xiumi.us"> <section style="border-color: rgb(204, 204, 204);box-shadow: rgb(102, 102, 102) 0.2em 0.2em 0.5em;padding: 10px;border-width: 3px;border-style: solid;box-sizing: border-box;"> <section style="text-align: left;font-size: 15px;color: rgb(89, 89, 89);box-sizing: border-box;" powered-by="xiumi.us"> <p style="box-sizing: border-box;"><span style="font-size: 14px;"><em>①write set 叫写入集合,是事务更新行相关信息的 Hash 值。write set=Hash(库名+表名+主键(唯一键)字段信息)</em></span></p> <p style="box-sizing: border-box;"><br></p> <p style="box-sizing: border-box;"><span style="font-size: 14px;"><em>②gtid_executed 为已经执行过的事务 gtid 集合,也即事务快照版本。</em></span></p> <p style="box-sizing: border-box;"><br></p> <p style="box-sizing: border-box;"><span style="font-size: 14px;"><em>③把 write set 和 gtid_executed 打包成为事务上下文信息,transaction_context_log_event。</em></span></p> <p style="box-sizing: border-box;"><br></p> <p style="box-sizing: border-box;"><span style="font-size: 14px;"><em>④gtid_log_event为已经执行过的事务 gtid 集合。</em></span></p> <p style="box-sizing: border-box;"><br></p> <p style="box-sizing: border-box;"><span style="font-size: 14px;"><em>⑤log_event_group 为事务日志信息,后续要更新到 relay log 中。</em></span></p> <p style="box-sizing: border-box;"><br></p> <p style="box-sizing: border-box;"><span style="font-size: 14px;"><em>⑥把 3 和 4 和 5 一起打包成为 transaction message 广播给其它节点。</em></span></p> </section> </section> </section> </section> </section> <section style="text-align: center;margin-bottom: 5px;"> <img class="rich_pages" data-ratio="0.6819923371647509" data-s="300,640" src="/upload/1369c6404c12796f382a28ab95acca97.png" data-type="png" data-w="261" style=""> </section> </section> </section> </section> </section> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 14px;"><em><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">图 8:广播信息的内容结构</span></em></span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">②certification info</span></strong></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">广播的信息到达冲突检测模块 certification 之后是如何工作?</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">每个节点都有一个 certification info 的内存结构,certification info 保存了通过冲突检测的事务的 write set 和 gtid_executed。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">certification info 相当于一个 map,key 是 string 结构,保存 write set 中提取的主键值;value 是 set 集合,保存 gtid_executed 事务快照版本。</span></p> <section style="line-height: normal;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">例如 T1 事务,T1 更新数据库 d1 中的表 t1 中两行数据 id=1 和 id=2,它对应快照版本 UUID_MGR 是 :1-100,刚开始 certification info 为空,所以直接提交,之后 certification info 中快照版本直接更新为 1-101。</span> </section> <p style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="rich_pages" data-ratio="0.4101851851851852" data-s="300,640" src="/upload/9dbfb7c2f7d0bd3f751fb73ef991cae.png" data-type="png" data-w="1080" style=""></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 14px;"><em><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">图 9:certification info 结构图</span></em></span></p> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: 100%;vertical-align: top;box-sizing: border-box;"> <section style="text-align: center;margin-top: 10px;margin-right: 0%;margin-left: 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;vertical-align: bottom;width: 33.33%;box-sizing: border-box;line-height: 0;"> <section style="line-height: 0;width: 0px;"> <svg viewbox="0 0 1 1" style="vertical-align:top;"></svg> </section> </section> <section style="display: inline-block;vertical-align: bottom;width: 17%;box-sizing: border-box;"> <section style="font-size: 22px;margin-top: 3px;margin-bottom: 3px;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: 1.8em;height: 1.8em;line-height: 1.8em;border-radius: 100%;margin-left: auto;margin-right: auto;font-size: 20px;color: rgb(255, 255, 255);border-width: 1px;border-style: solid;border-color: rgb(89, 89, 89);background-color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">6</p> </section> </section> </section> <section style="display: inline-block;vertical-align: bottom;width: 33.33%;box-sizing: border-box;line-height: 0;"> <section style="line-height: 0;width: 0px;"> <svg viewbox="0 0 1 1" style="vertical-align:top;"></svg> </section> </section> </section> <section style="margin-right: 0%;margin-bottom: 10px;margin-left: 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="text-align: center;white-space: normal;box-sizing: border-box;"><strong>冲突检测核心机制!敲黑板!</strong></p> </section> </section> </section> </section> </section> <section data-tools="135编辑器" data-id="90422"> <section> <section data-width="100%"> <section data-brushtype="text"> <section style="line-height: normal;"> <br> </section> </section> </section> </section> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">通过上面的例子可知通过冲突检测标准:若 transaction UUID_MGR ">="certification info UUID_MGR,则冲突检测通过。</span> </section> <p style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="rich_pages" data-ratio="0.39351851851851855" data-s="300,640" src="/upload/d149ee86db810b1a1a244776e4989f41.png" data-type="png" data-w="1080" style=""></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 14px;"><em><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">图 10:冲突检测事务执行举例</span></em></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">根据上述标准举例,事务 T2,更新 id=2 的行,事务 T2 的 UUID_MGR 为 1-102,节点中冲突检测模块中的 certification info 中的 UUID_MGR 为 1-101,这里 T2:UUID_MGR:1-102>UUID_MGR:1-100,则 T2 冲突检测通过。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">反之,事务 T3,更新 id=1 的行,事务 T3 的 UUID_MGR 为 1-100, 节点中冲突检测模块中的 certification info 中的 UUID_MGR 为 1-101,很明显 T3:UUID_MGR:1-100<UUID_MGR:1-101,则 T3 冲突检测失败,事务回滚或者丢弃。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">上面是针对于单独一个写来进行判断,现在我们来展示一下多节点模式中,多个事务同时写入时冲突检测机制。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">如下图所示,三个事务 T4、T5、T6 并行写入某个 MySQL 节点,通过了 Paxos 协议模块达成一致性共识,</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">进行冲突检测时遵循下面三个原则:</span></p> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">多个事务修改同一个 id 对应的数值,需要按照先后顺序进行冲突检测。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">多个事务同时对不同的 id 进行修改,各自进行修改即可。</span></p></li> <li> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">不同的事务对同一个 id 修改,需要按照先后顺序进行冲突检测即。</span> </section></li> </ul> <p style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="rich_pages" data-ratio="0.4888888888888889" data-s="300,640" src="/upload/1e78e34f6bf3b5d19bd0503ea570d765.png" data-type="png" data-w="1080" style=""></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 14px;"><em><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">图 11:多事务同时写入示意图</span></em></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">如图 11 所示,事务 T4 和事务 T5 同时更新 id=1 的行,按照先来后到顺序进行冲突检测,T4 先到先进行冲突检测。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">事务 T4,更新 id=1 的行,事务 T4 的 UUID_MGR 为 1-102,节点中冲突检测模块中的 certification info 中 id=1 的 UUID_MGR 为 1-101,很明显 T2:UUID_MGR:1-102>UUID_MGR:1-101,则 T4 冲突检测通过,更新为 certification info 中 UUID_MGR 为 1-103。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">事务 T5,更新 id=1 的行,事务 T5 的 UUID_MGR 为 1-100, 节点中冲突检测模块中的 certification info 中 id=1 的 UUID_MGR 为 1-102,其中 T5:UUID_MGR:1-100>UUID_MGR:1-102,则 T5 冲突检测不通过。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">事务 T6,更新 id=3 的行,事务 T6 的 UUID_MGR 为 1-100, 节点中冲突检测模块中的 certification info 中 id=3 的 UUID_MGR 为空,其中 T6:UUID_MGR:1-100>UUID_MGR,则 T6 冲突检测通过,更新为 certification info 中 UUID_MGR 为 1-101。</span></p> <section style="line-height: normal;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">如下图 12 所示,事务 T4 和事务 T5 并行修改 id=1,T4 写入成功,T5 丢弃,T6 写入 id=3 事务,写入成功。</span> </section> <p style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="rich_pages" data-ratio="0.4898148148148148" data-s="300,640" src="/upload/5a5a54b6d4fba2d09b6e82d565271c6b.png" data-type="png" data-w="1080" style=""></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 14px;"><em><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">图 12:多事务同时写入结果图</span></em></span><br></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">随着 write set 不断写入 certification info 中,内存消耗会相应增大,MGR 有配套的 write set 清理线程,每隔一段时间去清理已经在节点应用或者回放的事务的 write set 信息。</span></p> <section data-tools="135编辑器" data-id="90422"> <section> <section data-width="100%"> <section data-brushtype="text"> <section style="line-height: normal;"> <br> </section> <section style="box-sizing: border-box;font-size: 16px;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: 100%;vertical-align: top;box-sizing: border-box;"> <section style="text-align: center;margin-top: 10px;margin-right: 0%;margin-left: 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;vertical-align: bottom;width: 33.33%;box-sizing: border-box;line-height: 0;"> <section style="line-height: 0;width: 0px;"> <svg viewbox="0 0 1 1" style="vertical-align:top;"></svg> </section> </section> <section style="display: inline-block;vertical-align: bottom;width: 17%;box-sizing: border-box;"> <section style="font-size: 22px;margin-top: 3px;margin-bottom: 3px;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: 1.8em;height: 1.8em;line-height: 1.8em;border-radius: 100%;margin-left: auto;margin-right: auto;font-size: 20px;color: rgb(255, 255, 255);border-width: 1px;border-style: solid;border-color: rgb(89, 89, 89);background-color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">7</p> </section> </section> </section> <section style="display: inline-block;vertical-align: bottom;width: 33.33%;box-sizing: border-box;line-height: 0;"> <section style="line-height: 0;width: 0px;"> <svg viewbox="0 0 1 1" style="vertical-align:top;"></svg> </section> </section> </section> <section style="margin-right: 0%;margin-bottom: 10px;margin-left: 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="text-align: center;white-space: normal;box-sizing: border-box;"><strong>MGR 技术特点有哪些?</strong></p> </section> </section> </section> </section> </section> <section style="line-height: normal;"> <br> </section> </section> </section> </section> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">如下图 13 所示,MGR 具备以下技术特点:</span></p> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">MGR 是基于 Paxos 协议和原生复制的分布式集群,大多数节点同意即可以通过议题的模式,数据一致性高。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">具备高可用、自动故障检测功能,可自动切换。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">可弹性扩展,集群自动的新增和移除节点,集群最多接入 9 个节点。</span></p></li> <li> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">有单主和多主模式。支持多节点写入,具备冲突检测机制,可以适应多种应用场景需求。</span> </section></li> </ul> <p style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="rich_pages" data-ratio="0.4324074074074074" data-s="300,640" src="/upload/f597b085916addeb87fbf38c61ded527.png" data-type="png" data-w="1080" style=""></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 14px;"><em><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">图 13:MGR 技术闪亮点</span></em></span><br></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">MGR 目前还存在一些功能限制和不足,但是是未来数据库发展的一个趋势,随着产品不断完善,MGR 必将引领数据库系统发展的潮流。</span></p> <section data-tools="135编辑器" data-id="90422"> <section> <section data-width="100%"> <section data-brushtype="text"> <section style="line-height: normal;"> <br> </section> <section style="box-sizing: border-box;font-size: 16px;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: 100%;vertical-align: top;box-sizing: border-box;"> <section style="text-align: center;margin-top: 10px;margin-right: 0%;margin-left: 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;vertical-align: bottom;width: 33.33%;box-sizing: border-box;line-height: 0;"> <section style="line-height: 0;width: 0px;"> <svg viewbox="0 0 1 1" style="vertical-align:top;"></svg> </section> </section> <section style="display: inline-block;vertical-align: bottom;width: 17%;box-sizing: border-box;"> <section style="font-size: 22px;margin-top: 3px;margin-bottom: 3px;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: 1.8em;height: 1.8em;line-height: 1.8em;border-radius: 100%;margin-left: auto;margin-right: auto;font-size: 20px;color: rgb(255, 255, 255);border-width: 1px;border-style: solid;border-color: rgb(89, 89, 89);background-color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">8</p> </section> </section> </section> <section style="display: inline-block;vertical-align: bottom;width: 33.33%;box-sizing: border-box;line-height: 0;"> <section style="line-height: 0;width: 0px;"> <svg viewbox="0 0 1 1" style="vertical-align:top;"></svg> </section> </section> </section> <section style="margin-right: 0%;margin-bottom: 10px;margin-left: 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="text-align: center;white-space: normal;box-sizing: border-box;"><strong>总结展望</strong></p> </section> </section> </section> </section> </section> <section style="line-height: normal;"> <br> </section> </section> </section> </section> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">MySQL 是应用最广泛的一个开源数据库 ,其中 MGR 技术在保证数据一致性基础上,可自动进行故障检测、自动切换,具备防脑裂机制,兼具多节点写入等优点,是一个很好的技术发展方向。</span></p> <section style="line-height: normal;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">目前部分银行应用 MySQL 比例较高,并且也已开始推广上线 MGR 架构;G 行数据库数据库规划秉持传统数据库和开源数据库并行使用模式,MySQL 线上应用也有上百套,其中的 A 类系统中的分布式企业总线开始应用实践 MGR 技术。后续还将持续推广该项技术,不断提升开源数据库技术管理水平。</span> </section> <p style="line-height: normal;text-align: center;margin-bottom: 5px;"><img data-ratio="1" src="/upload/37c342fa494415544eb9133b737cb88a.gif" data-type="gif" data-w="1" style="white-space: normal;width: auto;"></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">最后跟大家梳理一下文章内容,先介绍 MySQL MGR 技术演变过程,然后全局阐述了事务生命周期,最后详细解释了事务冲突检测机制,文章略长但干货够足,大家看懂了没?</span> </section> <section style="box-sizing: border-box;font-size: 16px;"> <section style="margin: 10px 0% -20px;transform: translate3d(1px, 0px, 0px);box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: auto;vertical-align: top;min-width: 10%;max-width: 100%;height: auto;padding-right: 10px;padding-left: 10px;box-shadow: rgb(0, 0, 0) 0px 0px 0px;box-sizing: border-box;"> <section style="text-align: left;justify-content: flex-start;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: auto;vertical-align: top;min-width: 10%;max-width: 100%;height: auto;background-color: rgb(89, 89, 89);border-radius: 50px 20px 20px 50px;border-width: 0px;border-style: none;border-color: rgb(62, 62, 62);overflow: hidden;padding: 8px 10px;box-shadow: rgb(0, 0, 0) 0px 0px 0px;box-sizing: border-box;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: flex;flex-flow: row nowrap;box-sizing: border-box;"> <section style="display: inline-block;vertical-align: middle;width: auto;flex: 1 1 0%;align-self: center;height: auto;box-sizing: border-box;"> <section style="text-align: center;margin-right: 0%;margin-left: 0%;justify-content: center;font-size: 0px;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;vertical-align: top;overflow: hidden;height: 10px;width: 10px;border-width: 1px;border-radius: 100%;border-style: solid;border-color: rgb(255, 255, 255);background-color: rgb(255, 255, 255);box-shadow: rgb(89, 89, 89) 0px 1px 3px inset;box-sizing: border-box;"> <br> </section> </section> </section> <section style="display: inline-block;vertical-align: middle;width: auto;flex: 100 100 0%;align-self: center;height: auto;padding-left: 15px;box-sizing: border-box;"> <section style="margin-right: 0%;margin-left: 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="color: rgb(89, 89, 89);text-align: center;letter-spacing: 4px;line-height: 1.4;text-shadow: rgb(255, 255, 255) 1px -1px, rgb(255, 255, 255) 1px 1px, rgb(255, 255, 255) -1px 1px, rgb(255, 255, 255) -1px -1px, rgb(255, 255, 255) 1px 0px, rgb(255, 255, 255) 0px 1px, rgb(255, 255, 255) -1px 0px, rgb(255, 255, 255) 0px -1px;box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong style="box-sizing: border-box;">今晚八点,大咖来了</strong></p> </section> </section> </section> </section> </section> </section> </section> </section> </section> <section style="margin-right: 0%;margin-bottom: 10px;margin-left: 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: 100%;vertical-align: top;border-width: 1px;border-radius: 15px;border-style: solid;border-color: rgb(89, 89, 89);overflow: hidden;padding: 30px 10px 10px;box-sizing: border-box;"> <section style="transform: translate3d(1px, 0px, 0px);text-align: center;box-sizing: border-box;" powered-by="xiumi.us"> <section style="text-align: justify;color: rgb(89, 89, 89);font-size: 14px;line-height: 2;letter-spacing: 2px;box-sizing: border-box;"> <p style="white-space: normal;box-sizing: border-box;"><img class="rich_pages js_insertlocalimg" data-ratio="1.7786666666666666" data-s="300,640" src="/upload/ee5381de1a80d404189497641f137c6b.png" data-type="png" data-w="750" style="text-align: center;white-space: normal;"></p> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section>
作者:微信小助手
<p style="text-align: center;"><span style="font-size: 14px;letter-spacing: 0.5440000295639038px;text-align: center;max-width: 100%;color: rgb(255, 41, 65);line-height: 22.4px;">(给</span><span style="font-size: 14px;letter-spacing: 0.5440000295639038px;text-align: center;max-width: 100%;line-height: 22.4px;color: rgb(0, 128, 255);">ImportNew</span><span style="font-size: 14px;letter-spacing: 0.5440000295639038px;text-align: center;max-width: 100%;color: rgb(255, 41, 65);line-height: 22.4px;">加星标,提高Java技能)</span></p> <blockquote> <p style="letter-spacing: 0.5440000295639038px;white-space: normal;background-color: rgb(255, 255, 255);max-width: 100%;min-height: 1em;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">来自作者投稿 作者:cxuan</span></p> </blockquote> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">MySQL 一直是本人很薄弱的部分,后面会多输出 MySQL 的文章贡献给大家,毕竟 MySQL 涉及到数据存储、锁、磁盘寻道、分页等操作系统概念,而且互联网对 MySQL 的注重程度是不言而喻的,后面要加紧对 MySQL 的研究。写的如果不好,还请大家见谅。<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <img class="rich_pages" data-ratio="0.2547051442910916" data-s="300,640" data-type="png" data-w="1594" src="/upload/e109bd45506856abebb0af7b903d7f0f.png" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 100%;visibility: visible !important;height: auto;" data-backw="578" data-backh="147"> </section> <h2 data-tool="mdnice编辑器" style="line-height: 1.5em;"><span style="color: rgb(171, 25, 66);"><strong><span style="font-size: 15px;letter-spacing: normal;"><br></span></strong></span></h2> <h2 data-tool="mdnice编辑器" style="line-height: 1.5em;"><span style="color: rgb(171, 25, 66);"><strong><span style="font-size: 15px;letter-spacing: normal;">非关系型数据库和关系型数据库区别,优势比较</span></strong></span></h2> <p><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></p> <section style="line-height: 1.5em;"> <img class="rich_pages" data-ratio="0.4073529411764706" data-s="300,640" data-type="png" data-w="1360" src="/upload/cbde4c92f66a19c97d24124578b349f1.png" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 100%;visibility: visible !important;height: auto;" data-backw="578" data-backh="235"> </section> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">非关系型数据库(感觉翻译不是很准确)称为 NoSQL,也就是 Not Only SQL,不仅仅是 SQL。非关系型数据库不需要写一些复杂的 SQL 语句,其内部存储方式是以 key-value 的形式存在可以把它想象成电话本的形式,每个人名(key)对应电话(value)。常见的非关系型数据库主要有 Hbase、Redis、MongoDB 等。非关系型数据库不需要经过 SQL 的重重解析,所以性能很高;非关系型数据库的可扩展性比较强,数据之间没有耦合性,遇见需要新加字段的需求,就直接增加一个 key-value 键值对即可。</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <img class="rich_pages" data-ratio="0.41544117647058826" data-s="300,640" data-type="png" data-w="1088" src="/upload/12fad7113207b66096bf5447651137bf.png" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 100%;visibility: visible !important;height: auto;" data-backw="578" data-backh="240"> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">关系型数据库以表格的形式存在,以行和列的形式存取数据,关系型数据库这一系列的行和列被称为表,无数张表组成了数据库,常见的关系型数据库有 Oracle、DB2、Microsoft SQL Server、MySQL等。关系型数据库能够支持复杂的 SQL 查询,能够体现出数据之间、表之间的关联关系;关系型数据库也支持事务,便于提交或者回滚。<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">它们之间的劣势都是基于对方的优势来满足的。</span> </section> <section style="line-height: 1.5em;"> <span style="color: rgb(171, 25, 66);"><strong><span style="font-size: 15px;letter-spacing: normal;"><br></span></strong></span> </section> <h2 data-tool="mdnice编辑器" style="line-height: 1.5em;"><span style="color: rgb(171, 25, 66);"><strong><span style="font-size: 15px;letter-spacing: normal;">MySQL 事务四大特性</span></strong></span></h2> <p><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></p> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">一说到 MySQL 事务,你肯定能想起来四大特性:原子性、一致性、隔离性、持久性,下面再对这事务的四大特性做一个描述</span> </section> <p><br></p> <ul data-tool="mdnice编辑器" class="list-paddingleft-2"> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">原子性(Atomicity): 原子性指的就是 MySQL 中的包含事务的操作要么全部成功、要么全部失败回滚,因此事务的操作如果成功就必须要全部应用到数据库,如果操作失败则不能对数据库有任何影响。</span> </section></li> </ul> <section style="line-height: 1.5em;"> <br> </section> <section style="line-height: 1.5em;"> <span style="color: rgb(171, 25, 66);"><span style="font-size: 15px;letter-spacing: normal;">这里涉及到一个概念,什么是 MySQL 中的事务?</span></span> </section> <section style="line-height: 1.5em;"> <span style="color: rgb(171, 25, 66);"><span style="font-size: 15px;letter-spacing: normal;"><br></span></span> </section> <section style="line-height: 1.5em;"> <span style="color: rgb(171, 25, 66);"><span style="font-size: 15px;letter-spacing: normal;">事务是一组操作,组成这组操作的各个单元,要不全都成功要不全都失败,这个特性就是事务。</span></span> </section> <section style="line-height: 1.5em;"> <span style="color: rgb(171, 25, 66);"><span style="font-size: 15px;letter-spacing: normal;"><br></span></span> </section> <section style="line-height: 1.5em;"> <span style="color: rgb(171, 25, 66);"><span style="font-size: 15px;letter-spacing: normal;">在 MySQL 中,事务是在引擎层实现的,只有使用 innodb 引擎的数据库或表才支持事务。</span></span> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"></span> </section> <p><br></p> <ul data-tool="mdnice编辑器" class="list-paddingleft-2"> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">一致性(Consistency):一致性指的是一个事务在执行前后其状态一致。比如 A 和 B 加起来的钱一共是 1000 元,那么不管 A 和 B 之间如何转账,转多少次,事务结束后两个用户的钱加起来还得是 1000,这就是事务的一致性。</span> </section> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">持久性(Durability): 持久性指的是一旦事务提交,那么发生的改变就是永久性的,即使数据库遇到特殊情况比如故障的时候也不会产生干扰。</span> </section> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">隔离性(Isolation):隔离性需要重点说一下,当多个事务同时进行时,就有可能出现脏读(dirty read)、不可重复读(non-repeatable read)、幻读(phantom read) 的情况,为了解决这些并发问题,提出了隔离性的概念。</span> </section> </section> <section> <section style="line-height: 1.5em;"> <br> </section> </section></li> </ul> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">脏读:事务 A 读取了事务 B 更新后的数据,但是事务 B 没有提交,然后事务 B 执行回滚操作,那么事务 A 读到的数据就是脏数据</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">不可重复读:事务 A 进行多次读取操作,事务 B 在事务 A 多次读取的过程中执行更新操作并提交,提交后事务 A 读到的数据不一致。</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">幻读:事务 A 将数据库中所有学生的成绩由 A -> B,此时事务 B 手动插入了一条成绩为 A 的记录,在事务 A 更改完毕后,发现还有一条记录没有修改,那么这种情况就叫做出现了幻读。</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">SQL的隔离级别有四种,它们分别是读未提交(read uncommitted)、读已提交(read committed)、可重复读(repetable read) 和 串行化(serializable)。下面分别来解释一下。</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">读未提交:读未提交指的是一个事务在提交之前,它所做的修改就能够被其他事务所看到。</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">读已提交:读已提交指的是一个事务在提交之后,它所做的变更才能够让其他事务看到。</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">可重复读:可重复读指的是一个事务在执行的过程中,看到的数据是和启动时看到的数据是一致的。未提交的变更对其他事务不可见。</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">串行化:顾名思义是对于同一行记录,写会加写锁,读会加读锁。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">这四个隔离级别可以解决脏读、不可重复读、幻象读这三类问题。总结如下</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <img class="rich_pages" data-ratio="0.24238733252131547" data-s="300,640" data-type="png" data-w="1642" src="/upload/6845e043eaf3ec56b82f16a1af6bc7a1.png" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 100%;visibility: visible !important;height: auto;" data-backw="578" data-backh="140"> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">其中隔离级别由低到高是:读未提交 < 读已提交 < 可重复读 < 串行化</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">隔离级别越高,越能够保证数据的完整性和一致性,但是对并发的性能影响越大。大多数数据库的默认级别是读已提交(Read committed),比如 Sql Server、Oracle ,但是 MySQL 的默认隔离级别是 可重复读(repeatable-read)。</span> </section> <p style="line-height: 1.5em;"><br></p> <h2 data-tool="mdnice编辑器" style="line-height: 1.5em;"><span style="color: rgb(171, 25, 66);"><strong><span style="font-size: 15px;letter-spacing: normal;">MySQL 常见存储引擎的区别</span></strong></span></h2> <p><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></p> <p style="line-height: 1.5em;"><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">MySQL 常见的存储引擎,可以使用</span></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> <li></li> </ul> <pre class="code-snippet__js" data-lang="sql"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">SHOW</span> <span class="code-snippet__keyword">ENGINES</span></span></code></pre> </section> <p style="line-height: 1.5em;"><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></p> <p style="line-height: 1.5em;"><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">命令,来列出所有的存储引擎</span></p> <p style="line-height: 1.5em;"><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></p> <section style="line-height: 1.5em;"> <img class="rich_pages" data-ratio="0.23832923832923833" data-s="300,640" data-type="png" data-w="1628" src="/upload/6a041039aa07e5e70a6371c83f3320b0.png" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 100%;visibility: visible !important;height: auto;" data-backw="578" data-backh="137"> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">可以看到,InnoDB 是 MySQL 默认支持的存储引擎,支持事务、行级锁定和外键。</span> </section> <h3 data-tool="mdnice编辑器" style="line-height: 1.5em;"><br></h3> <h3 data-tool="mdnice编辑器" style="line-height: 1.5em;"><span style="color: rgb(171, 25, 66);"><strong><span style="font-size: 15px;letter-spacing: normal;">MyISAM 存储引擎的特点</span></strong></span></h3> <p><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></p> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">在 5.1 版本之前,MyISAM 是 MySQL 的默认存储引擎,MyISAM 并发性比较差,使用的场景比较少,主要特点是</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <ul data-tool="mdnice编辑器" class="list-paddingleft-2"> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">不支持事务操作,ACID 的特性也就不存在了,这一设计是为了性能和效率考虑的。</span> </section> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">不支持外键操作,如果强行增加外键,MySQL 不会报错,只不过外键不起作用。</span> </section> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">MyISAM 默认的锁粒度是表级锁,所以并发性能比较差,加锁比较快,锁冲突比较少,不太容易发生死锁的情况。</span> </section> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">MyISAM 会在磁盘上存储三个文件,文件名和表名相同,扩展名分别是 .frm(存储表定义)、.MYD(MYData,存储数据)、MYI(MyIndex,存储索引)。这里需要特别注意的是 MyISAM 只缓存索引文件,并不缓存数据文件。</span> </section> </section><p><br></p></li> <li> <section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">MyISAM 支持的索引类型有 全局索引(Full-Text)、B-Tree 索引、R-Tree 索引</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">Full-Text 索引:它的出现是为了解决针对文本的模糊查询效率较低的问题。</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">B-Tree 索引:所有的索引节点都按照平衡树的数据结构来存储,所有的索引数据节点都在叶节点</span> </section> <section style="line-height: 1.5em;"> <br> </section> </section> <section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">R-Tree索引:它的存储方式和 B-Tree 索引有一些区别,主要设计用于存储空间和多维数据的字段做索引,目前的 MySQL 版本仅支持 geometry 类型的字段作索引,相对于 BTREE,RTREE 的优势在于范围查找。</span> </section> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">数据库所在主机如果宕机,MyISAM 的数据文件容易损坏,而且难以恢复。</span> </section> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">增删改查性能方面:SELECT 性能较高,适用于查询较多的情况</span> </section> </section></li> </ul> <h3 data-tool="mdnice编辑器" style="line-height: 1.5em;"><br></h3> <h3 data-tool="mdnice编辑器" style="line-height: 1.5em;"><span style="color: rgb(171, 25, 66);"><strong><span style="font-size: 15px;letter-spacing: normal;">InnoDB 存储引擎的特点</span></strong></span></h3> <p><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></p> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">自从 MySQL 5.1 之后,默认的存储引擎变成了 InnoDB 存储引擎,相对于 MyISAM,InnoDB 存储引擎有了较大的改变,它的主要特点是</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <ul data-tool="mdnice编辑器" class="list-paddingleft-2"> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">支持事务操作,具有事务 ACID 隔离特性,默认的隔离级别是可重复读(repetable-read)、通过MVCC(并发版本控制)来实现的。能够解决脏读和不可重复读的问题。</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">InnoDB 支持外键操作。</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">InnoDB 默认的锁粒度行级锁,并发性能比较好,会发生死锁的情况。</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">和 MyISAM 一样的是,InnoDB 存储引擎也有 .frm文件存储表结构 定义,但是不同的是,InnoDB 的表数据与索引数据是存储在一起的,都位于 B+ 数的叶子节点上,而 MyISAM 的表数据和索引数据是分开的。</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">InnoDB 有安全的日志文件,这个日志文件用于恢复因数据库崩溃或其他情况导致的数据丢失问题,保证数据的一致性。</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">InnoDB 和 MyISAM 支持的索引类型相同,但具体实现因为文件结构的不同有很大差异。</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">增删改查性能方面,如果执行大量的增删改操作,推荐使用 InnoDB 存储引擎,它在删除操作时是对行删除,不会重建表。</span> </section></li> </ul> <h3 data-tool="mdnice编辑器" style="line-height: 1.5em;"><span style="color: rgb(171, 25, 66);"><strong><span style="font-size: 15px;letter-spacing: normal;"><br></span></strong></span></h3> <h3 data-tool="mdnice编辑器" style="line-height: 1.5em;"><span style="color: rgb(171, 25, 66);"><strong><span style="font-size: 15px;letter-spacing: normal;">MyISAM 和 InnoDB 存储引擎的对比</span></strong></span></h3> <p><br></p> <ul data-tool="mdnice编辑器" class="list-paddingleft-2"> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">锁粒度方面:由于锁粒度不同,InnoDB 比 MyISAM 支持更高的并发;InnoDB 的锁粒度为行锁、MyISAM 的锁粒度为表锁、行锁需要对每一行进行加锁,所以锁的开销更大,但是能解决脏读和不可重复读的问题,相对来说也更容易发生死锁</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">可恢复性上:由于 InnoDB 是有事务日志的,所以在产生由于数据库崩溃等条件后,可以根据日志文件进行恢复。而 MyISAM 则没有事务日志。</span> </section><p><br></p></li> <li style="font
作者:微信小助手
<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" data-mpa-powered-by="yiban.io"> <p data-tool="mdnice编辑器"><img data-ratio="0.6666666666666666" src="/upload/cb1416bb0dab7a5772881ad0d8d147bd.png" data-type="png" data-w="960" height="436" width="723"></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;text-align: center;"><span style="font-size: 13px;">来自:Java中文社群</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><br></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">随着 JDK 1.8 Streams API 的发布,使得 HashMap 拥有了更多的遍历的方式,但应该选择那种遍历方式?反而成了一个问题。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">本文<strong>先从 HashMap 的遍历方法讲起,然后再从性能、原理以及安全性等方面,来分析 HashMap 各种遍历方式的优势与不足</strong>,本文主要内容如下图所示:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding: 0px 0.5em;"> <img data-ratio="0.5911330049261084" src="/upload/d0588d2c2ee97c79fe14f967ad0921fe.png" data-type="png" data-w="1624" style="display: block;margin-right: auto;margin-left: auto;border-radius: 6px;box-shadow: rgb(180, 180, 180) 0em 0em 0.5em 0px;font-size: 17px;"> <figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"> <br> </figcaption> </figure> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: inline-block;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;">HashMap 遍历</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">HashMap <strong>遍历从大的方向来说,可分为以下 4 类</strong>:</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 迭代器(Iterator)方式遍历; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> For Each 方式遍历; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> Lambda 表达式遍历(JDK 1.8+); </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> Streams API 遍历(JDK 1.8+)。 </section></li> </ol> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">但每种类型下又有不同的实现方式,因此具体的遍历方式又可以分为以下 7 种:</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 使用迭代器(Iterator)EntrySet 的方式进行遍历; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 使用迭代器(Iterator)KeySet 的方式进行遍历; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 使用 For Each EntrySet 的方式进行遍历; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 使用 For Each KeySet 的方式进行遍历; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 使用 Lambda 表达式的方式进行遍历; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 使用 Streams API 单线程的方式进行遍历; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 使用 Streams API 多线程的方式进行遍历。 </section></li> </ol> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">接下来我们来看每种遍历方式的具体实现代码。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;">1.迭代器 EntrySet</h3> <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;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span> <span style="color: #e6c07b;line-height: 26px;">HashMapTest</span> </span>{<br> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">static</span> <span style="color: #c678dd;line-height: 26px;">void</span> <span style="color: #61aeee;line-height: 26px;">main</span><span style="line-height: 26px;">(String[] args)</span> </span>{<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// 创建并赋值 HashMap</span><br> Map<Integer, String> map = <span style="color: #c678dd;line-height: 26px;">new</span> HashMap();<br> map.put(<span style="color: #d19a66;line-height: 26px;">1</span>, <span style="color: #98c379;line-height: 26px;">"Java"</span>);<br> map.put(<span style="color: #d19a66;line-height: 26px;">2</span>, <span style="color: #98c379;line-height: 26px;">"JDK"</span>);<br> map.put(<span style="color: #d19a66;line-height: 26px;">3</span>, <span style="color: #98c379;line-height: 26px;">"Spring Framework"</span>);<br> map.put(<span style="color: #d19a66;line-height: 26px;">4</span>, <span style="color: #98c379;line-height: 26px;">"MyBatis framework"</span>);<br> map.put(<span style="color: #d19a66;line-height: 26px;">5</span>, <span style="color: #98c379;line-height: 26px;">"Java中文社群"</span>);<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// 遍历</span><br> Iterator<Map.Entry<Integer, String>> iterator = map.entrySet().iterator();<br> <span style="color: #c678dd;line-height: 26px;">while</span> (iterator.hasNext()) {<br> Map.Entry<Integer, String> entry = iterator.next();<br> System.out.print(entry.getKey());<br> System.out.print(entry.getValue());<br> }<br> }<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">以上程序的执行结果为:</p> <blockquote data-tool="mdnice编辑器" style="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(239, 112, 96);background: rgb(255, 249, 249);"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">1 Java 2 JDK 3 Spring Framework 4 MyBatis framework 5 Java中文社群</p> </blockquote> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;">2.迭代器 KeySet</h3> <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;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span> <span style="color: #e6c07b;line-height: 26px;">HashMapTest</span> </span>{<br> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">static</span> <span style="color: #c678dd;line-height: 26px;">void</span> <span style="color: #61aeee;line-height: 26px;">main</span><span style="line-height: 26px;">(String[] args)</span> </span>{<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// 创建并赋值 HashMap</span><br> Map<Integer, String> map = <span style="color: #c678dd;line-height: 26px;">new</span> HashMap();<br> map.put(<span style="color: #d19a66;line-height: 26px;">1</span>, <span style="color: #98c379;line-height: 26px;">"Java"</span>);<br> map.put(<span style="color: #d19a66;line-height: 26px;">2</span>, <span style="color: #98c379;line-height: 26px;">"JDK"</span>);<br> map.put(<span style="color: #d19a66;line-height: 26px;">3</span>, <span style="color: #98c379;line-height: 26px;">"Spring Framework"</span>);<br> map.put(<span style="color: #d19a66;line-height: 26px;">4</span>, <span style="color: #98c379;line-height: 26px;">"MyBatis framework"</span>);<br> map.put(<span style="color: #d19a66;line-height: 26px;">5</span>, <span style="color: #98c379;line-height: 26px;">"Java中文社群"</span>);<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// 遍历</span><br> Iterator<Integer> iterator = map.keySet().iterator();<br> <span style="color: #c678dd;line-height: 26px;">while</span> (iterator.hasNext()) {<br> Integer key = iterator.next();<br> System.out.print(key);<br> System.out.print(map.get(key));<br> }<br> }<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">以上程序的执行结果为:</p> <blockquote data-tool="mdnice编辑器" style="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(239, 112, 96);background: rgb(255, 249, 249);"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">1 Java 2 JDK 3 Spring Framework 4 MyBatis framework 5 Java中文社群</p> </blockquote> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;">3.ForEach EntrySet</h3> <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;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span> <span style="color: #e6c07b;line-height: 26px;">HashMapTest</span> </span>{<br> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">static</span> <span style="color: #c678dd;line-height: 26px;">void</span> <span style="color: #61aeee;line-height: 26px;">main</span><span style="line-height: 26px;">(String[] args)</span> </span>{<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// 创建并赋值 HashMap</span><br> Map<Integer, String> map = <span style="color: #c678dd;line-height: 26px;">new</span> HashMap();<br> map.put(<span style="color: #d19a66;line-height: 26px;">1</span>, <span style="color: #98c379;line-height: 26px;">"Java"</span>);<br> map.put(<span style="color: #d19a66;line-height: 26px;">2</span>, <span style="color: #98c379;line-height: 26px;">"JDK"</span>);<br> map.put(<span style="color: #d19a66;line-height: 26px;">3</span>, <span style="color: #98c379;line-height: 26px;">"Spring Framework"</span>);<br> map.put(<span style="color: #d19a66;line-height: 26px;">4</span>, <span style="color: #98c379;line-height: 26px;">"MyBatis framework"</span>);<br> map.put(<span style="color: #d19a66;line-height: 26px;">5</span>, <span style="color: #98c379;line-height: 26px;">"Java中文社群"</span>);<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// 遍历</span><br> <span style="color: #c678dd;line-height: 26px;">for</span> (Map.Entry<Integer, String> entry : map.entrySet()) {<br> System.out.print(entry.getKey());<br> System.out.print(entry.getValue());<br> }<br> }<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">以上程序的执行结果为:</p> <blockquote data-tool="mdnice编辑器" style="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(239, 112, 96);background: rgb(255, 249, 249);"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">1 Java 2 JDK 3 Spring Framework 4 MyBatis framework 5 Java中文社群</p> </blockquote> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;">4.ForEach KeySet</h3> <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;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span> <span style="color: #e6c07b;line-height: 26px;">HashMapTest</span> </span>{<br> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">static</span> <span style="color: #c678dd;line-height: 26px;">void</span> <span style="color: #61aeee;line-height: 26px;">main</span><span style="line-height: 26px;">(String[] args)</span> </span>{<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// 创建并赋值 HashMap</span><br> Map<Integer, String> map = <span style="color: #c678dd;line-height: 26px;">new</span> HashMap();<br> map.put(<span style="color: #d19a66;line-height: 26px;">1</span>, <span style="color: #98c379;line-height: 26px;">"Java"</span>);<br> map.put(<span style="color: #d19a66;line-height: 26px;">2</span>, <span style="color: #98c379;line-height: 26px;">"JDK"</span>);<br> map.put(<span style="color: #d19a66;line-height: 26px;">3</span>, <span style="color: #98c379;line-height: 26px;">"Spring Framework"</span>);<br> map.put(<span style="color: #d19a66;line-height: 26px;">4</span>, <span style="color: #98c379;line-height: 26px;">"MyBatis framework"</span>);<br> map.put(<span style="color: #d19a66;line-height: 26px;">5</span>, <span style="color: #98c379;line-height: 26px;">"Java中文社群"</span>);<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// 遍历</span><br> <span style="color: #c678dd;line-height: 26px;">for</span> (Integer key : map.keySet()) {<br> System.out.print(key);<br> System.out.print(map.get(key));<br> }<br> }<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">以上程序的执行结果为:</p> <blockquote data-tool="mdnice编辑器" style="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(239, 112, 96);background: rgb(255, 249, 249);"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">1 Java 2 JDK 3 Spring Framework 4 MyBatis framework 5 Java中文社群</p> </blockquote> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;">5.Lambda</h3> <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;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span> <span style="color: #e6c07b;line-height: 26px;">HashMapTest</span> </span>{<br> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">static</span> <span style="color: #c678dd;line-height: 26px;">void</span> <span style="color: #61aeee;line-height: 26px;">main</span><span style="line-height: 26px;">(String[] args)</span> </span>{<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// 创建并赋值 HashMap</span><br> Map<Integer, String> map = <span style="color: #c678dd;line-height: 26px;">new</span> HashMap();<br> map.put(<span style="color: #d19a66;line-height: 26px;">1</span>, <span style="color: #98c379;line-height: 26px;">"Java"</span>);<br> map.put(<span style="color: #d19a66;line-height: 26px;">2</span>, <span style="color: #98c379;line-height: 26px;">"JDK"</span>);<br> map.put(<span style="color: #d19a66;line-height: 26px;">3</span>, <span style="color: #98c379;line-height: 26px;">"Spring Framework"</span>);<br> map.put(<span style="color: #d19a66;line-height: 26px;">4</span>, <span style="color: #98c379;line-height: 26px;">"MyBatis framework"</span>);<br> map.put(<span style="color: #d19a66;line-height: 26px;">5</span>, <span style="color: #98c379;line-height: 26px;">"Java中文社群"</span>);<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// 遍历</span><br> map.forEach((key, value) -> {<br> System.out.print(key);<br> System.out.print(value);<br> });<br> }<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">以上程序的执行结果为:</p> <blockquote data-tool="mdnice编辑器" style="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(239, 112, 96);background: rgb(255, 249, 249);"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">1 Java 2 JDK 3 Spring Framework 4 MyBatis framework 5 Java中文社群</p> </blockquote> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;">6.Streams API 单线程</h3> <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;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span> <span style="color: #e6c07b;line-height: 26px;">HashMapTest</span> </span>{<br> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">static</span> <span style="color: #c678dd;line-height: 26px;">void</span> <span style="color: #61aeee;line-height: 26px;">main</span><span style="line-height: 26px;">(String[] args)</span> </span>{<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// 创建并赋值 HashMap</span><br> Map<Integer, String> map = <span style="color: #c678dd;line-height: 26px;">new</span> HashMap();<br> map.put(<span style="color: #d19a66;line-height: 26px;">1</span>, <span style="color: #98c379;line-height: 26px;">"Java"</span>);<br> map.put(<span style="color: #d19a66;line-height: 26px;">2</span>, <span style="color: #98c379;line-height: 26px;">"JDK"</span>);<br> map.put(<span style="color: #d19a66;line-height: 26px;">3</span>, <span style="color: #98c379;line-height: 26px;">"Spring Framework"</span>);<br> map.put(<span style="color: #d19a66;line-height: 26px;">4</span>, <span style="color: #98c379;line-height: 26px;">"MyBatis framework"</span>);<br> map.put(<span style="color: #d19a66;line-height: 26px;">5</span>, <span style="color: #98c379;line-height: 26px;">"Java中文社群"</span>);<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// 遍历</span><br> map.entrySet().stream().forEach((entry) -> {<br> System.out.print(entry.getKey());<br> System.out.print(entry.getValue());<br> });<br> }<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">以上程序的执行结果为:</p> <blockquote data-tool="mdnice编辑器" style="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(239, 112, 96);background: rgb(255, 249, 249);"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">1 Java 2 JDK 3 Spring Framework 4 MyBatis framework 5 Java中文社群</p> </blockquote> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;">7.Streams API 多线程</h3> <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;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span> <span style="color: #e6c07b;line-height: 26px;">HashMapTest</span> </span>{<br> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">static</span> <span style="color: #c678dd;line-height: 26px;">void</span> <span style="color: #61aeee;line-height: 26px;">main</span><span style="line-height: 26px;">(String[] args)</span> </span>{<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// 创建并赋值 HashMap</span><br> &nb
作者:微信小助手
<p style="margin-bottom: 10px;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;color: rgb(62, 62, 62);background-color: rgb(255, 255, 255);text-size-adjust: auto;font-size: 15px;word-spacing: 2px;text-align: center;" data-mpa-powered-by="yiban.io"><span style="font-size: 14px;color: rgb(136, 136, 136);">加个“</span><span style="color: rgb(0, 128, 255);font-size: 14px;">星标</span><span style="font-size: 14px;color: rgb(136, 136, 136);">”,每天上午 09:25,干货推送!</span></p> <p style="font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;color: rgb(62, 62, 62);font-size: 14px;background-color: rgb(255, 255, 255);text-align: center;"><img data-backh="36" data-backw="578" data-ratio="0.0625" data-s="300,640" data-type="jpeg" data-w="640" width="100%" src="/upload/8c292e55ba5a23cb6ebc11f2a2c4fece.null" style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;widows: 1;word-spacing: 2px;color: rgb(136, 136, 136);box-sizing: border-box !important;visibility: visible !important;width: 677px !important;"></p> <section style="font-size: 15px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;"> <br> </section> <section style="font-size: 15px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;"> <p style="font-size: inherit;color: inherit;line-height: inherit;"><span style="font-size: 12px;color: rgb(136, 136, 136);">来源:https://www.cnblogs.com/bainianminguo/p/12247158.html<br>标题:kafka概念扫盲<br>作者:bainianminguo</span></p> <h3 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.3em;border-bottom: 2px solid rgb(0, 172, 193);"><span style="font-size: inherit;line-height: inherit;display: inline-block;font-weight: normal;background: rgb(0, 172, 193);color: rgb(255, 255, 255);padding-top: 3px;padding-right: 10px;padding-left: 10px;border-top-right-radius: 3px;border-top-left-radius: 4px;margin-right: 2px;">一、kafka概述</span></h3> <h4 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.2em;color: rgb(0, 172, 193);"><span style="font-size: inherit;color: inherit;line-height: inherit;">1.1、定义</span></h4> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">Kakfa是一个分布式的基于发布/订阅模式的消息队列(message queue),主要应用于大数据的实时处理领域</p> <h4 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.2em;color: rgb(0, 172, 193);"><span style="font-size: inherit;color: inherit;line-height: inherit;">1.2、消息队列</span></h4> <h5 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1em;color: rgb(0, 172, 193);"><span style="font-size: inherit;color: inherit;line-height: inherit;">1.2.1、传统的消息队列&新式的消息队列的模式</span></h5> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img data-ratio="0.5698924731182796" src="/upload/e47cd67730e7d01cf5199bf64142493c.png" data-type="png" data-w="558" 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.5em;margin-bottom: 1.5em;">上面是传统的消息队列,比如一个用户要注册信息,当用户信息写入数据库后,后面还有一些其他流程,比如发送短信,则需要等这些流程处理完成后,在返回给用户</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">而新式的队列是,比如一个用户注册信息,数据直接丢进数据库,就直接返回给用户成功</p> <h5 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1em;color: rgb(0, 172, 193);"><span style="font-size: inherit;color: inherit;line-height: inherit;">1.2.2、使用消息队列的好处</span></h5> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">A、 解耦</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">B、 可恢复性</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">C、 缓冲</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">D、 灵活性&峰值处理能力</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">E、 异步通信</