diff --git "a/Java\345\237\272\347\241\200\345\255\246\344\271\240/README.MD" "b/Java\345\237\272\347\241\200\345\255\246\344\271\240/README.MD" new file mode 100644 index 0000000..a038f88 --- /dev/null +++ "b/Java\345\237\272\347\241\200\345\255\246\344\271\240/README.MD" @@ -0,0 +1,22 @@ +## Java基础篇(持续更新中) +​ +公众号:捡田螺的小男孩 +​ +- [一文读懂线程池的工作原理(故事白话文)](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488078&idx=1&sn=0a7cef472002f6582fd2354fba83706a&chksm=cf21cd67f85644716263c3a80cead9b7bb36d9677f6f8b06d0602077ece70fcafa9d20c1cffb&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Synchronized解析——如果你愿意一层一层剥开我的心](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487942&idx=1&sn=bbc68d1b9da23bf6474378e310b1ef1b&chksm=cf21ceeff85647f9ad7a08226849fcba3f9481387d13b17a5787fb94027647de81c349f9e390&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [异步编程利器:CompletableFuture详解](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490456&idx=1&sn=95836324db57673a4d7aea4fb233c0d2&chksm=cf21c4b1f8564da72dc7b39279362bcf965b1374540f3b339413d138599f7de59a5f977e3b0e&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java日常开发的21个坑,你踩过几个?](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488115&idx=1&sn=bdd4a4ca36bc7ea902106d058e8537fb&chksm=cf21cd5af856444cb36af600705615454b0aaa2b289b97ddb52d594556ac07a1915b73ecce19&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [一份Java程序员的珍藏书单,请您注意查收](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488066&idx=1&sn=44b5a90be1b69d7938dbcf516d85f041&chksm=cf21cd6bf856447d869278386250f59a926881375df848e54f86a21682bdab50f9e09ca56fbd&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java程序员必备基础:JDK 5-15都有哪些经典新特性](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488058&idx=1&sn=aab4d0dc9020cb62710086474ca90baf&chksm=cf21cd13f8564405040593daa45c62aec218e13f5ff42d679c59f768dd4fcc53ddcf34e0a454&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [程序员必备基础:Git 命令全方位学习](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488013&idx=1&sn=7011a51a347e3da2cf8f8540b4d9a5d6&chksm=cf21cd24f8564432d74bc13551ebdeae71a71ea31e339c7a8f1f42f181078b5192475d598626&token=162724582&ang=zh_CN&scene=21#wechat_redirect) +- [给你的Java程序拍个片子吧:jstack命令解析](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487990&idx=1&sn=b5b3c565392f39e5ac517696603b2ed9&chksm=cf21cedff85647c960407dce77fe04d08e51f8c7332310ccacd925be5567c187aa761dd1d1c8&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java程序员必备基础结构图](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487985&idx=1&sn=ead28c6c8d81b98e59603b848d250b30&chksm=cf21ced8f85647ce336f19016c7ff1936b21c81066815c8f28b830098716111548edb9767b21&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java程序员必备:序列化全方位解析](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487980&idx=1&sn=2a9ce519f87a1ffe1511022e6724208e&chksm=cf21cec5f85647d357c79860171fc1799ef3c44a2bdd0716e8437e31708a17d9000b4224bd36&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [优化if-else代码的八种方案](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487970&idx=1&sn=c296bb03419adf93955c6d0f27e56b29&chksm=cf21cecbf85647dd0ef5160559bc0d524a4be004a28bc5d2770a43409e3b090123c0930cf047&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java程序员必备基础:泛型解析](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487964&idx=1&sn=24d7228cc10afc98c52dbf35da61a7b9&chksm=cf21cef5f85647e3d2b3f1e126cdc46d9e889d2e30c09716e0aea016beee3ca6d4c321cf60ae&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java程序员必备基础:内部类解析](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487963&idx=1&sn=a0b49cd49a3dd51b6736c9ffa0a5997a&chksm=cf21cef2f85647e49a4bdb43f27583f03fb9ec4719767512dc084edd05675599c3bec44251fb&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [老是遇到乱码问题:它是如何产生的,又如何解决呢?](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487962&idx=1&sn=7424e843c80b228283fc08d4d24cc4bb&chksm=cf21cef3f85647e5a9c92d280624ad2564e885561a8b64cbf6722459f7c13da7421765321aa9&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [谈谈Java反射:从入门到实践,再到原理](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487959&idx=1&sn=778114d611f18b0f307a3f3ab6cd9117&chksm=cf21cefef85647e84b77c0e46620e91cf5ff079785b58a7dc66e5ed7419e21e0da9180699617&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java程序员必备的一些流程图](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487946&idx=1&sn=57a86e1d2fe1a9ecf00594a0bb6baf5f&chksm=cf21cee3f85647f5cf2ba728cc0838923140130a18ad117e248cf9843460614fc855d556968a&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java程序员必备:查看日志常用的linux命令](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487954&idx=1&sn=6c04ff4edfcfea52a82795bcb9ed8efd&chksm=cf21cefbf85647ed8df72a23307315be5d1b3d4974c128f111bfdaa84da37cf7b49ff65c1112&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [ThreadLocal的八个关键知识点](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247500784&idx=1&sn=6519d0e092be4ed9d6f4da8d90deef2c&chksm=cf221cd9f85595cf9123043241e92a19ca9c212aa8527cfb2aeb9a2472c6bdab9045cf40f22f&token=349136600&lang=zh_CN#rd) \ No newline at end of file diff --git "a/Java\345\237\272\347\241\200\345\255\246\344\271\240/README.MD.bak" "b/Java\345\237\272\347\241\200\345\255\246\344\271\240/README.MD.bak" new file mode 100644 index 0000000..4ba4024 --- /dev/null +++ "b/Java\345\237\272\347\241\200\345\255\246\344\271\240/README.MD.bak" @@ -0,0 +1,21 @@ +## Java基础篇(持续更新中) +​ +公众号:捡田螺的小男孩 +​ +- [一文读懂线程池的工作原理(故事白话文)](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488078&idx=1&sn=0a7cef472002f6582fd2354fba83706a&chksm=cf21cd67f85644716263c3a80cead9b7bb36d9677f6f8b06d0602077ece70fcafa9d20c1cffb&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Synchronized解析——如果你愿意一层一层剥开我的心](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487942&idx=1&sn=bbc68d1b9da23bf6474378e310b1ef1b&chksm=cf21ceeff85647f9ad7a08226849fcba3f9481387d13b17a5787fb94027647de81c349f9e390&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [异步编程利器:CompletableFuture详解](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490456&idx=1&sn=95836324db57673a4d7aea4fb233c0d2&chksm=cf21c4b1f8564da72dc7b39279362bcf965b1374540f3b339413d138599f7de59a5f977e3b0e&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java日常开发的21个坑,你踩过几个?](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488115&idx=1&sn=bdd4a4ca36bc7ea902106d058e8537fb&chksm=cf21cd5af856444cb36af600705615454b0aaa2b289b97ddb52d594556ac07a1915b73ecce19&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [一份Java程序员的珍藏书单,请您注意查收](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488066&idx=1&sn=44b5a90be1b69d7938dbcf516d85f041&chksm=cf21cd6bf856447d869278386250f59a926881375df848e54f86a21682bdab50f9e09ca56fbd&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java程序员必备基础:JDK 5-15都有哪些经典新特性](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488058&idx=1&sn=aab4d0dc9020cb62710086474ca90baf&chksm=cf21cd13f8564405040593daa45c62aec218e13f5ff42d679c59f768dd4fcc53ddcf34e0a454&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [程序员必备基础:Git 命令全方位学习](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488013&idx=1&sn=7011a51a347e3da2cf8f8540b4d9a5d6&chksm=cf21cd24f8564432d74bc13551ebdeae71a71ea31e339c7a8f1f42f181078b5192475d598626&token=162724582&ang=zh_CN&scene=21#wechat_redirect) +- [给你的Java程序拍个片子吧:jstack命令解析](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487990&idx=1&sn=b5b3c565392f39e5ac517696603b2ed9&chksm=cf21cedff85647c960407dce77fe04d08e51f8c7332310ccacd925be5567c187aa761dd1d1c8&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java程序员必备基础结构图](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487985&idx=1&sn=ead28c6c8d81b98e59603b848d250b30&chksm=cf21ced8f85647ce336f19016c7ff1936b21c81066815c8f28b830098716111548edb9767b21&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java程序员必备:序列化全方位解析](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487980&idx=1&sn=2a9ce519f87a1ffe1511022e6724208e&chksm=cf21cec5f85647d357c79860171fc1799ef3c44a2bdd0716e8437e31708a17d9000b4224bd36&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [优化if-else代码的八种方案](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487970&idx=1&sn=c296bb03419adf93955c6d0f27e56b29&chksm=cf21cecbf85647dd0ef5160559bc0d524a4be004a28bc5d2770a43409e3b090123c0930cf047&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java程序员必备基础:泛型解析](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487964&idx=1&sn=24d7228cc10afc98c52dbf35da61a7b9&chksm=cf21cef5f85647e3d2b3f1e126cdc46d9e889d2e30c09716e0aea016beee3ca6d4c321cf60ae&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java程序员必备基础:内部类解析](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487963&idx=1&sn=a0b49cd49a3dd51b6736c9ffa0a5997a&chksm=cf21cef2f85647e49a4bdb43f27583f03fb9ec4719767512dc084edd05675599c3bec44251fb&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [老是遇到乱码问题:它是如何产生的,又如何解决呢?](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487962&idx=1&sn=7424e843c80b228283fc08d4d24cc4bb&chksm=cf21cef3f85647e5a9c92d280624ad2564e885561a8b64cbf6722459f7c13da7421765321aa9&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [谈谈Java反射:从入门到实践,再到原理](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487959&idx=1&sn=778114d611f18b0f307a3f3ab6cd9117&chksm=cf21cefef85647e84b77c0e46620e91cf5ff079785b58a7dc66e5ed7419e21e0da9180699617&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java程序员必备的一些流程图](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487946&idx=1&sn=57a86e1d2fe1a9ecf00594a0bb6baf5f&chksm=cf21cee3f85647f5cf2ba728cc0838923140130a18ad117e248cf9843460614fc855d556968a&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java程序员必备:查看日志常用的linux命令](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487954&idx=1&sn=6c04ff4edfcfea52a82795bcb9ed8efd&chksm=cf21cefbf85647ed8df72a23307315be5d1b3d4974c128f111bfdaa84da37cf7b49ff65c1112&token=162724582&lang=zh_CN&scene=21#wechat_redirect) \ No newline at end of file diff --git "a/Java\347\250\213\345\272\217\345\221\230\351\234\200\350\246\201\347\234\213\345\223\252\344\272\233\344\271\246/README.MD" "b/Java\347\250\213\345\272\217\345\221\230\351\234\200\350\246\201\347\234\213\345\223\252\344\272\233\344\271\246/README.MD" new file mode 100644 index 0000000..5ee6e33 --- /dev/null +++ "b/Java\347\250\213\345\272\217\345\221\230\351\234\200\350\246\201\347\234\213\345\223\252\344\272\233\344\271\246/README.MD" @@ -0,0 +1,5 @@ +## Java程序员书单(持续更新中) +​ +公众号:捡田螺的小男孩 +​ +- [一份Java程序员的珍藏书单,请您注意查收](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488066&idx=1&sn=44b5a90be1b69d7938dbcf516d85f041&chksm=cf21cd6bf856447d869278386250f59a926881375df848e54f86a21682bdab50f9e09ca56fbd&token=162724582&lang=zh_CN&scene=21#wechat_redirect) diff --git "a/Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/README.MD" "b/Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/README.MD" new file mode 100644 index 0000000..7397d39 --- /dev/null +++ "b/Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/README.MD" @@ -0,0 +1,32 @@ +## 1. 面试真题 + +关注公众号:捡田螺的小男孩 +​ +- [oppo后端16连问](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498750&idx=1&sn=19fe8b4fff28fe81db14e733053bbc74&chksm=cf2224d7f855adc1d0984980a4e3de31fe33329164a472ca8d8255a8a80b69b2e23850811323&token=2001057130&lang=zh_CN#rd) +- [小厂后端十连问(附答案)](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498316&idx=1&sn=7749b78293b7b2af51eda99844e08a56&chksm=cf222565f855ac7324232e2af459f8b6e6eb5fd5b272c2b29bda08cc579421b6704a0de94b2e&token=2001057130&lang=zh_CN#rd) +- [腾讯云后端15连问!](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498171&idx=1&sn=f5a7ec25a569822be0f73fbcd413e8ba&chksm=cf222692f855af84fba419166fcd4235c0e78af3a2e1ec4c723a4efb1bd1ad6f8a5b9404c599&token=2001057130&lang=zh_CN#rd) +- [社招后端21连问(三年工作经验一面)](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498084&idx=1&sn=96c8148cfeeeb16668ed9e03fa9131cc&chksm=cf22264df855af5b6e81b93738cca28989226a53ec702fcfaa0cc5004dded4208c5ee5ea844a&token=2001057130&lang=zh_CN#rd) +- [一份热乎乎的字节面试真题](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497742&idx=1&sn=18765e7356f446a7f2521f45b467d5d3&chksm=cf222727f855ae31dd2029e3219814211336c41d9228d271a583d3691ddadca586529aca9302&token=2001057130&lang=zh_CN#rd) +- [面试必备:虾皮服务端15连问](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497256&idx=1&sn=3b799c2d514aa25e85a6faa60d639a0b&chksm=cf222901f855a017b73356b99b830b8800a7a9172fab891c5759d8dd69a270872ea9480c0b7c&token=2001057130&lang=zh_CN#rd) +- [宇宙条一面:十道经典面试题解析](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247495342&idx=1&sn=54e1c0c16a6467001524c34818025331&chksm=cf223187f855b89140db5ca429e6efc19d0111abf7f36b78a0ecd73b00fded1ff1e7ba32a6f1&token=2001057130&lang=zh_CN#rd) +- [蚂蚁金服一面:十道经典面试题解析](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247493270&idx=1&sn=1c78a81d6e1bd0f0fd947fe8c3a33e32&chksm=cf2239bff855b0a9627855f20a17799e0506eb7548a409bfa0ee0450328d7519ec70f7b962cc&token=2001057130&lang=zh_CN#rd) +​ +## 2. 必考经典面试题 +​ +- [Redis主从、哨兵、 Cluster集群一锅端!](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498254&idx=1&sn=6489360c3b226df9811e66cb40ec7656&chksm=cf222527f855ac3112628bcec7730064fee3fdbe869fbd0a7410c22766a0c036a7e5c1a69fa0&token=2001057130&lang=zh_CN#rd) +- [我们为什么要分库分表?](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498625&idx=1&sn=0d7bd9d1b46eeff4c715a6761355e9b0&chksm=cf2224a8f855adbea8931c8e011711f6c70cffeef8ddf8b87729c710eacef11b46eef80fda36&token=2001057130&lang=zh_CN#rd) +- [面试必备:聊聊MySQL的主从](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497982&idx=1&sn=bb589329cceb5462fc41f66ec63dbf56&chksm=cf2227d7f855aec16dd4d3b3425c0401850eeaf2c9cdc82e82722d38a00c24ee9ccfa3353774&token=2001057130&lang=zh_CN#rd) +- [消息队列经典十连问](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497847&idx=1&sn=29a32672b712e7dfadfa36c9902b2ec7&chksm=cf22275ef855ae484fb3f51a5726e9a4bc45222e8fbbd33631d177dc4b5619c36889ea178463&token=2001057130&lang=zh_CN#rd) +- [八种幂等设计](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497427&idx=1&sn=2ed160c9917ad989eee1ac60d6122855&chksm=cf2229faf855a0ecf5eb34c7335acdf6420426490ee99fc2b602d54ff4ffcecfdab24eeab0a3&token=2001057130&lang=zh_CN#rd) +- [看一遍就理解:零拷贝详解](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247496788&idx=1&sn=f65ddd10d16d8376efa0037762153932&chksm=cf222b7df855a26bad76249e7b77e28da3097b226f9165d79f5031516d9c345827fca901559c&token=2001057130&lang=zh_CN#rd) +- [看一遍就理解:IO模型详解](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247496448&idx=1&sn=cd502f850290a25949dd4a11ac55a039&chksm=cf222c29f855a53f094bde2868900fa252b07385e73564e9ee9f0510cb4e74387d9d23ab67e6&token=2001057130&lang=zh_CN#rd) +- [看一遍就理解:MVCC原理详解](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247495277&idx=1&sn=a1812febb4246f824ce54d778f672025&chksm=cf223144f855b8528ad6cce707dc3a1b4d387817bd751dfab4f79dda90c6640f9763d25f3f33&token=2001057130&lang=zh_CN#rd) +- [2W字!详解20道Redis经典面试题!(珍藏版)](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247494124&idx=1&sn=c185f7d999d5f006608d05707a8a7eea&chksm=cf2236c5f855bfd329c6e2ee27f23f8131ebcd312960190a10f1a819d67f07a21a08ad17f263&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [七种方案!探讨Redis分布式锁的正确使用姿势](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488142&idx=1&sn=79a304efae7a814b6f71bbbc53810c0c&chksm=cf21cda7f85644b11ff80323defb90193bc1780b45c1c6081f00da85d665fd9eb32cc934b5cf&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [面试必备!TCP协议经典十五连问!](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490868&idx=1&sn=96889bfe6a97f9200fa2d682cf2f5d89&chksm=cf21c21df8564b0b0757df584560a69340b1775fe1c70b867439565969ec3aed19c442ff4eeb&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [2W字!梳理50道经典计算机网络面试题(收藏版)](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247492832&idx=1&sn=601fa1c340a313bc0f74bb75cdb6a95a&chksm=cf223bc9f855b2dfb8d0e74f3360e2edfe25c3a728fe17e9e80b6022340994fd9d9e1ca83ca8&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [ZooKeeper的十二连问,你顶得了嘛?](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488047&idx=1&sn=4913c7e1c3b8835f7512d8dc6b845727&chksm=cf21cd06f8564410cce6121230256facb1ab3b5a9ed35579896f428d84bdea7b86836109d575&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [50道Java集合经典面试题(收藏版)](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488007&idx=1&sn=c5c16c8ec916c791e776216f3177c7e2&chksm=cf21cd2ef85644382a985e9fed1956d6ee60c86ce69e65f31f775318435fdb86bf368e26edf2&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [100道MySQL数据库经典面试题解析(收藏版)](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488000&idx=1&sn=1c38db7fd110bbcc1ffb2d72a56aaf25&chksm=cf21cd29f856443f25a3fe98ae8e888faceef9bee45df045969b2cffb105363dcc2a4480bb74&token=1495321435&lang=zh_CN&scene=21#wechat_redirect) +- [Spring 面试63问](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497672&idx=1&sn=6ff0350e23d014b29a47bdec79af9ef5&chksm=cf2228e1f855a1f70fa78d9bd85c53dfbe154c1325aa1e203e4c918132c430d51bb68e961eda&token=2001057130&lang=zh_CN#rd) +- [多线程50连问](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247501446&idx=1&sn=3d83f3c1035c963c1fda3f77ab750e71&chksm=cf2219aff85590b9ba054dc33956a5cafe1beaa77b231dc4dc0cf891be3e16ef367f6b2ac4ed&token=245109219&lang=zh_CN#rd) \ No newline at end of file diff --git "a/Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/README.MD.bak" "b/Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/README.MD.bak" new file mode 100644 index 0000000..cfb8d9d --- /dev/null +++ "b/Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/README.MD.bak" @@ -0,0 +1,31 @@ +## 1. 面试真题 + +关注公众号:捡田螺的小男孩 +​ +- [oppo后端16连问](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498750&idx=1&sn=19fe8b4fff28fe81db14e733053bbc74&chksm=cf2224d7f855adc1d0984980a4e3de31fe33329164a472ca8d8255a8a80b69b2e23850811323&token=2001057130&lang=zh_CN#rd) +- [小厂后端十连问(附答案)](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498316&idx=1&sn=7749b78293b7b2af51eda99844e08a56&chksm=cf222565f855ac7324232e2af459f8b6e6eb5fd5b272c2b29bda08cc579421b6704a0de94b2e&token=2001057130&lang=zh_CN#rd) +- [腾讯云后端15连问!](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498171&idx=1&sn=f5a7ec25a569822be0f73fbcd413e8ba&chksm=cf222692f855af84fba419166fcd4235c0e78af3a2e1ec4c723a4efb1bd1ad6f8a5b9404c599&token=2001057130&lang=zh_CN#rd) +- [社招后端21连问(三年工作经验一面)](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498084&idx=1&sn=96c8148cfeeeb16668ed9e03fa9131cc&chksm=cf22264df855af5b6e81b93738cca28989226a53ec702fcfaa0cc5004dded4208c5ee5ea844a&token=2001057130&lang=zh_CN#rd) +- [一份热乎乎的字节面试真题](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497742&idx=1&sn=18765e7356f446a7f2521f45b467d5d3&chksm=cf222727f855ae31dd2029e3219814211336c41d9228d271a583d3691ddadca586529aca9302&token=2001057130&lang=zh_CN#rd) +- [面试必备:虾皮服务端15连问](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497256&idx=1&sn=3b799c2d514aa25e85a6faa60d639a0b&chksm=cf222901f855a017b73356b99b830b8800a7a9172fab891c5759d8dd69a270872ea9480c0b7c&token=2001057130&lang=zh_CN#rd) +- [宇宙条一面:十道经典面试题解析](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247495342&idx=1&sn=54e1c0c16a6467001524c34818025331&chksm=cf223187f855b89140db5ca429e6efc19d0111abf7f36b78a0ecd73b00fded1ff1e7ba32a6f1&token=2001057130&lang=zh_CN#rd) +- [蚂蚁金服一面:十道经典面试题解析](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247493270&idx=1&sn=1c78a81d6e1bd0f0fd947fe8c3a33e32&chksm=cf2239bff855b0a9627855f20a17799e0506eb7548a409bfa0ee0450328d7519ec70f7b962cc&token=2001057130&lang=zh_CN#rd) +​ +## 2. 必考经典面试题 +​ +- [Redis主从、哨兵、 Cluster集群一锅端!](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498254&idx=1&sn=6489360c3b226df9811e66cb40ec7656&chksm=cf222527f855ac3112628bcec7730064fee3fdbe869fbd0a7410c22766a0c036a7e5c1a69fa0&token=2001057130&lang=zh_CN#rd) +- [我们为什么要分库分表?](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498625&idx=1&sn=0d7bd9d1b46eeff4c715a6761355e9b0&chksm=cf2224a8f855adbea8931c8e011711f6c70cffeef8ddf8b87729c710eacef11b46eef80fda36&token=2001057130&lang=zh_CN#rd) +- [面试必备:聊聊MySQL的主从](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497982&idx=1&sn=bb589329cceb5462fc41f66ec63dbf56&chksm=cf2227d7f855aec16dd4d3b3425c0401850eeaf2c9cdc82e82722d38a00c24ee9ccfa3353774&token=2001057130&lang=zh_CN#rd) +- [消息队列经典十连问](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497847&idx=1&sn=29a32672b712e7dfadfa36c9902b2ec7&chksm=cf22275ef855ae484fb3f51a5726e9a4bc45222e8fbbd33631d177dc4b5619c36889ea178463&token=2001057130&lang=zh_CN#rd) +- [八种幂等设计](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497427&idx=1&sn=2ed160c9917ad989eee1ac60d6122855&chksm=cf2229faf855a0ecf5eb34c7335acdf6420426490ee99fc2b602d54ff4ffcecfdab24eeab0a3&token=2001057130&lang=zh_CN#rd) +- [看一遍就理解:零拷贝详解](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247496788&idx=1&sn=f65ddd10d16d8376efa0037762153932&chksm=cf222b7df855a26bad76249e7b77e28da3097b226f9165d79f5031516d9c345827fca901559c&token=2001057130&lang=zh_CN#rd) +- [看一遍就理解:IO模型详解](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247496448&idx=1&sn=cd502f850290a25949dd4a11ac55a039&chksm=cf222c29f855a53f094bde2868900fa252b07385e73564e9ee9f0510cb4e74387d9d23ab67e6&token=2001057130&lang=zh_CN#rd) +- [看一遍就理解:MVCC原理详解](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247495277&idx=1&sn=a1812febb4246f824ce54d778f672025&chksm=cf223144f855b8528ad6cce707dc3a1b4d387817bd751dfab4f79dda90c6640f9763d25f3f33&token=2001057130&lang=zh_CN#rd) +- [2W字!详解20道Redis经典面试题!(珍藏版)](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247494124&idx=1&sn=c185f7d999d5f006608d05707a8a7eea&chksm=cf2236c5f855bfd329c6e2ee27f23f8131ebcd312960190a10f1a819d67f07a21a08ad17f263&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [七种方案!探讨Redis分布式锁的正确使用姿势](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488142&idx=1&sn=79a304efae7a814b6f71bbbc53810c0c&chksm=cf21cda7f85644b11ff80323defb90193bc1780b45c1c6081f00da85d665fd9eb32cc934b5cf&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [面试必备!TCP协议经典十五连问!](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490868&idx=1&sn=96889bfe6a97f9200fa2d682cf2f5d89&chksm=cf21c21df8564b0b0757df584560a69340b1775fe1c70b867439565969ec3aed19c442ff4eeb&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [2W字!梳理50道经典计算机网络面试题(收藏版)](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247492832&idx=1&sn=601fa1c340a313bc0f74bb75cdb6a95a&chksm=cf223bc9f855b2dfb8d0e74f3360e2edfe25c3a728fe17e9e80b6022340994fd9d9e1ca83ca8&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [ZooKeeper的十二连问,你顶得了嘛?](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488047&idx=1&sn=4913c7e1c3b8835f7512d8dc6b845727&chksm=cf21cd06f8564410cce6121230256facb1ab3b5a9ed35579896f428d84bdea7b86836109d575&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [50道Java集合经典面试题(收藏版)](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488007&idx=1&sn=c5c16c8ec916c791e776216f3177c7e2&chksm=cf21cd2ef85644382a985e9fed1956d6ee60c86ce69e65f31f775318435fdb86bf368e26edf2&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [100道MySQL数据库经典面试题解析(收藏版)](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488000&idx=1&sn=1c38db7fd110bbcc1ffb2d72a56aaf25&chksm=cf21cd29f856443f25a3fe98ae8e888faceef9bee45df045969b2cffb105363dcc2a4480bb74&token=1495321435&lang=zh_CN&scene=21#wechat_redirect) +- [Spring 面试63问](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497672&idx=1&sn=6ff0350e23d014b29a47bdec79af9ef5&chksm=cf2228e1f855a1f70fa78d9bd85c53dfbe154c1325aa1e203e4c918132c430d51bb68e961eda&token=2001057130&lang=zh_CN#rd) \ No newline at end of file diff --git "a/Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/\347\274\223\345\255\230,Redis/Redis\344\270\272\344\273\200\344\271\210\350\277\231\344\271\210\345\277\253.md" "b/Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/\347\274\223\345\255\230,Redis/Redis\344\270\272\344\273\200\344\271\210\350\277\231\344\271\210\345\277\253.md" new file mode 100644 index 0000000..a3f6b30 --- /dev/null +++ "b/Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/\347\274\223\345\255\230,Redis/Redis\344\270\272\344\273\200\344\271\210\350\277\231\344\271\210\345\277\253.md" @@ -0,0 +1,175 @@ + +## 前言 + +大家好呀,我是捡田螺的小男孩。我们都知道Redis很快,它QPS可达10万(每秒请求数)。**Redis为什么这么快呢**,本文将跟大家一起学习。 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3880491879ed4a228d8f4213d987f6a3~tplv-k3u1fbpfcp-zoom-1.image) + + +- 公众号:**捡田螺的小男孩** +- [github地址](https://github.com/whx123/JavaHome),感谢每一颗star + +## 基于内存实现 + +我们都知道内存读写是比磁盘读写快很多的。Redis是基于内存存储实现的数据库,相对于数据存在磁盘的数据库,就省去磁盘磁盘I/O的消耗。MySQL等磁盘数据库,需要建立索引来加快查询效率,而Redis数据存放在内存,直接操作内存,所以就很快。 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0d7be13173814a43a60960fe59a48c61~tplv-k3u1fbpfcp-zoom-1.image) + +## 高效的数据结构 + +我们知道,MySQL索引为了提高效率,选择了B+树的数据结构。其实合理的数据结构,就是可以让你的应用/程序更快。先看下Redis的数据结构&内部编码图: + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4ddd7723cc0e4953b746b13db7a5cea3~tplv-k3u1fbpfcp-zoom-1.image) + + +### SDS简单动态字符串 + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0e68a18c50f149dda136fc9b1aa73ab8~tplv-k3u1fbpfcp-zoom-1.image) + +``` +struct sdshdr { //SDS简单动态字符串 + int len; //记录buf中已使用的空间 + int free; // buf中空闲空间长度 + char buf[]; //存储的实际内容 +} +``` + + +#### 字符串长度处理 + +在C语言中,要获取```捡田螺的小男孩```这个字符串的长度,需要从头开始遍历,复杂度为O(n); +在Redis中, 已经有一个**len**字段记录当前字符串的长度啦,直接获取即可,时间复杂度为O(1)。 + +#### 减少内存重新分配的次数 + +在C语言中,修改一个字符串,需要重新分配内存,修改越频繁,内存分配就越频繁,而分配内存是会**消耗性能**的。而在Redis中,SDS提供了两种优化策略:空间预分配和惰性空间释放。 + +**空间预分配** + +当SDS简单动态字符串修改和空间扩充时,除了分配必需的内存空间,还会额外分配未使用的空间。分配规则是酱紫的: + +> - SDS修改后,len的长度小于1M,那么将额外分配与len相同长度的未使用空间。比如len=100,重新分配后,buf 的实际长度会变为100(已使用空间)+100(额外空间)+1(空字符)=201。 +> - SDS修改后, len长度大于1M,那么程序将分配1M的未使用空间。 + +**惰性空间释放** + +当SDS缩短时,不是回收多余的内存空间,而是用free记录下多余的空间。后续再有修改操作,直接使用free中的空间,减少内存分配。 + +#### 哈希 + +Redis 作为一个K-V的内存数据库,它使用用一张全局的哈希来保存所有的键值对。这张哈希表,有多个哈希桶组成,哈希桶中的entry元素保存了```*key```和```*value```指针,其中```*key```指向了实际的键,```*value```指向了实际的值。 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/13924387cd9e4a2d96d873dba1cc3ca9~tplv-k3u1fbpfcp-zoom-1.image) + +哈希表查找速率很快的,有点类似于Java中的**HashMap**,它让我们在**O(1)** 的时间复杂度快速找到键值对。首先通过key计算哈希值,找到对应的哈希桶位置,然后定位到entry,在entry找到对应的数据。 + +有些小伙伴可能会有疑问:你往哈希表中写入大量数据时,不是会遇到**哈希冲突**问题嘛,那效率就会降下来啦。 +> **哈希冲突:** 通过不同的key,计算出一样的哈希值,导致落在同一个哈希桶中。 + +Redis为了解决哈希冲突,采用了**链式哈希**。链式哈希是指同一个哈希桶中,多个元素用一个链表来保存,它们之间依次用指针连接。 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/131951cd80354c24b62584d71b8fe9f9~tplv-k3u1fbpfcp-zoom-1.image) + +有些小伙伴可能还会有疑问:哈希冲突链上的元素只能通过指针逐一查找再操作。当往哈希表插入数据很多,冲突也会越多,冲突链表就会越长,那查询效率就会降低了。 + +为了保持高效,Redis 会对哈希表做**rehash操作**,也就是增加哈希桶,减少冲突。为了rehash更高效,Redis还默认使用了两个全局哈希表,一个用于当前使用,称为主哈希表,一个用于扩容,称为备用哈希表。 + +#### 跳跃表 + +跳跃表是Redis特有的数据结构,它其实就是在**链表的基础上,增加多级索引**,以提高查找效率。跳跃表的简单原理图如下: + +![](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0b62d59ffbd945e18f6dfcbf650a6eed~tplv-k3u1fbpfcp-watermark.image) + +- 每一层都有一条有序的链表,最底层的链表包含了所有的元素。 +- 跳跃表支持平均 O(logN),最坏 O(N)复杂度的节点查找,还可以通过顺序性操作批量处理节点。 + + +#### 压缩列表ziplist + +压缩列表ziplist是列表键和字典键的的底层实现之一。它是由一系列特殊编码的内存块构成的列表, 一个ziplist可以包含多个entry, 每个entry可以保存一个长度受限的字符数组或者整数,如下: + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4ce3da7cddbe4e6e94a775151664ed93~tplv-k3u1fbpfcp-zoom-1.image) + +- zlbytes :记录整个压缩列表占用的内存字节数 +- zltail: 尾节点至起始节点的偏移量 +- zllen : 记录整个压缩列表包含的节点数量 +- entryX: 压缩列表包含的各个节点 +- zlend : 特殊值0xFF(十进制255),用于标记压缩列表末端 + +由于内存是**连续分配**的,所以遍历速度很快。。 + + +## 合理的数据编码 + +Redis支持多种数据基本类型,每种基本类型对应不同的数据结构,每种数据结构对应不一样的编码。为了提高性能,Redis设计者总结出,数据结构最适合的编码搭配。 + +Redis是使用对象(redisObject)来表示数据库中的键值,当我们在 Redis 中创建一个键值对时,至少创建两个对象,一个对象是用做键值对的键对象,另一个是键值对的值对象。 +``` +//关注公众号:捡田螺的小男孩 +typedef struct redisObject{ + //类型 + unsigned type:4; + //编码 + unsigned encoding:4; + //指向底层数据结构的指针 + void *ptr; + //... + }robj; +``` + +redisObject中,**type** 对应的是对象类型,包含String对象、List对象、Hash对象、Set对象、zset对象。**encoding** 对应的是编码。 + +- String:如果存储数字的话,是用int类型的编码;如果存储非数字,小于等于39字节的字符串,是embstr;大于39个字节,则是raw编码。 +- List:如果列表的元素个数小于512个,列表每个元素的值都小于64字节(默认),使用ziplist编码,否则使用linkedlist编码 +- Hash:哈希类型元素个数小于512个,所有值小于64字节的话,使用ziplist编码,否则使用hashtable编码。 +- Set:如果集合中的元素都是整数且元素个数小于512个,使用intset编码,否则使用hashtable编码。 +- Zset:当有序集合的元素个数小于128个,每个元素的值小于64字节时,使用ziplist编码,否则使用skiplist(跳跃表)编码 + +## 合理的线程模型 + + +### 单线程模型:避免了上下文切换 + +Redis是单线程的,其实是指**Redis的网络IO和键值对读写**是由一个线程来完成的。但Redis的其他功能,比如持久化、异步删除、集群数据同步等等,实际是由额外的线程执行的。 + +Redis的单线程模型,避免了**CPU不必要的上下文切换**和**竞争锁的消耗**。也正因为是单线程,如果某个命令执行过长(如hgetall命令),会造成阻塞。Redis是面向快速执行场景的内存数据库,所以要慎用如lrange和smembers、hgetall等命令。 + +什么是**上下文切换**?举个粟子: + +> - 比如你在看一本英文小说,你看到某一页,发现有个单词不会读,你加了个书签,然后去查字典。查完字典后,你回来从书签那里继续开始读,这个流程就很舒畅。 +> - 如果你一个人读这本书,肯定没啥问题。但是如果你去查字典的时候,别的小伙伴翻了一下你的书,然后溜了。你再回来看的时候,发现书不是你看的那一页了,你得花时间找到你的那一页。 +> - 一本书,你一个人怎么看怎么打标签都没事,但是人多了翻来翻去,这本书各种标记就很乱了。可能这个解释很粗糙,但是道理应该是一样的。 + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/053215e73f844b8da8c2880205947fc1~tplv-k3u1fbpfcp-zoom-1.image) + +### I/O 多路复用 + +什么是I/O多路复用? +- I/O :网络 I/O +- 多路 :多个网络连接 +- 复用:复用同一个线程。 +- IO多路复用其实就是一种同步IO模型,它实现了一个线程可以监视多个文件句柄;一旦某个文件句柄就绪,就能够通知应用程序进行相应的读写操作;而没有文件句柄就绪时,就会阻塞应用程序,交出cpu。 + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/07838d0a48ef4b38acccb7b52e5435e1~tplv-k3u1fbpfcp-zoom-1.image) + + +> 多路I/O复用技术可以让单个线程高效的处理多个连接请求,而Redis使用用epoll作为I/O多路复用技术的实现。并且Redis自身的事件处理模型将epoll中的连接、读写、关闭都转换为事件,不在网络I/O上浪费过多的时间。 + +## 虚拟内存机制 + +Redis直接自己构建了VM机制 ,不会像一般的系统会调用系统函数处理,会浪费一定的时间去移动和请求。 + +**Redis的虚拟内存机制是啥呢?** +> 虚拟内存机制就是暂时把不经常访问的数据(冷数据)从内存交换到磁盘中,从而腾出宝贵的内存空间用于其它需要访问的数据(热数据)。通过VM功能可以实现冷热数据分离,使热数据仍在内存中、冷数据保存到磁盘。这样就可以避免因为内存不足而造成访问速度下降的问题。 + +### 参考与感谢 + +- [Redis之VM机制](https://www.codenong.com/cs106843764/) +- [一文揭秘单线程的Redis为什么这么快?](https://zhuanlan.zhihu.com/p/57089960) +- [洞察|Redis是单线程的,但Redis为什么这么快?](https://zhuanlan.zhihu.com/p/42272979) + + diff --git "a/Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/TCP\345\215\217\350\256\25615\350\277\236\351\227\256.md" "b/Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/TCP\345\215\217\350\256\25615\350\277\236\351\227\256.md" new file mode 100644 index 0000000..eae7eec --- /dev/null +++ "b/Java\351\235\242\350\257\225\351\242\230\351\233\206\347\273\223\345\217\267/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/TCP\345\215\217\350\256\25615\350\277\236\351\227\256.md" @@ -0,0 +1,395 @@ +### 前言 + +TCP协议是大厂面试必问的知识点。整理了15道非常经典的TCP面试题,希望大家都找到理想的offer呀 + + +![](https://files.mdnice.com/user/3535/47429a24-7e0b-4bf6-8200-7e2ec1baad63.png) + + +- 公众号:**捡田螺的小男孩** + +### 1. 讲下TCP三次握手流程 + +![](https://files.mdnice.com/user/3535/43f4b02a-ad18-45e5-8d6e-52349cc371d6.png) + +开始客户端和服务器都处于CLOSED状态,然后服务端开始监听某个端口,进入LISTEN状态 + +- 第一次握手(SYN=1, seq=x),发送完毕后,客户端进入 SYN_SEND 状态 +- 第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1), 发送完毕后,服务器端进入 SYN_RCVD 状态。 +- 第三次握手(ACK=1,ACKnum=y+1),发送完毕后,客户端进入 ESTABLISHED 状态,当服务器端接收到这个包时,也进入 ESTABLISHED 状态,TCP 握手,即可以开始数据传输。 + +### 2.TCP握手为什么是三次,不能是两次?不能是四次? + +TCP握手为什么是三次呢?为了方便理解,我们以谈恋爱为例子:两个人能走到一起,最重要的事情就是相爱,就是**我爱你,并且我知道,你也爱我**,接下来我们以此来模拟三次握手的过程: + + +![](https://files.mdnice.com/user/3535/374acab7-d609-4c7b-9db6-6a40dbe42926.png) + + +**为什么握手不能是两次呢?** + +如果只有两次握手,女孩子可能就不知道,她的那句**我也爱你**,男孩子是否**收到**,恋爱关系就不能愉快展开。 + +**为什么握手不能是四次呢?** + +因为握手不能是四次呢?因为三次已经够了,三次已经能让双方都知道:你爱我,我也爱你。而四次就多余了。 + +### 3. 讲下TCP四次挥手过程 + +![](https://files.mdnice.com/user/3535/439e735c-c443-4b2f-96b1-b750004d8d05.png) + +1. 第一次挥手(FIN=1,seq=u),发送完毕后,客户端进入FIN_WAIT_1 状态 +2. 第二次挥手(ACK=1,ack=u+1,seq =v),发送完毕后,服务器端进入CLOSE_WAIT 状态,客户端接收到这个确认包之后,进入 FIN_WAIT_2 状态 +3. 第三次挥手(FIN=1,ACK1,seq=w,ack=u+1),发送完毕后,服务器端进入LAST_ACK 状态,等待来自客户端的最后一个ACK。 +4. 第四次挥手(ACK=1,seq=u+1,ack=w+1),客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入 TIME_WAIT状态,**等待了某个固定时间(两个最大段生命周期,2MSL,2 Maximum Segment Lifetime)之后**,没有收到服务器端的 ACK ,认为服务器端已经正常关闭连接,于是自己也关闭连接,进入 CLOSED 状态。服务器端接收到这个确认包之后,关闭连接,进入 CLOSED 状态。 + +### 4. TCP挥手为什么需要四次呢? + +举个例子吧! + +> 小明和小红打电话聊天,通话差不多要结束时,小红说“我没啥要说的了”,小明回答“我知道了”。但是小明可能还会有要说的话,小红不能要求小明跟着自己的节奏结束通话,于是小明可能又叽叽歪歪说了一通,最后小明说“我说完了”,小红回答“知道了”,这样通话才算结束。 + +![](https://files.mdnice.com/user/3535/966cef0c-1477-4eca-aadf-059219da0198.png) + +### 5. TIME-WAIT 状态为什么需要等待 2MSL + +![](https://files.mdnice.com/user/3535/f56000c8-da62-4370-9559-71bf312f6214.png) + +2MSL,2 Maximum Segment Lifetime,即两个最大段生命周期 + +> - 1个 MSL 保证四次挥手中主动关闭方最后的 ACK 报文能最终到达对端 +> - 1个 MSL 保证对端没有收到 ACK 那么进行重传的 FIN 报文能够到达 + +### 6.TCP 和 UDP 的区别 + +1. TCP面向连接((如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接。 +2. TCP要求安全性,提供可靠的服务,通过TCP连接传送的数据,不丢失、不重复、安全可靠。而UDP尽最大努力交付,即不保证可靠交付。 +3. TCP是点对点连接的,UDP一对一,一对多,多对多都可以 +4. TCP传输效率相对较低,而UDP传输效率高,它适用于对高速传输和实时性有较高的通信或广播通信。 +5. TCP适合用于网页,邮件等;UDP适合用于视频,语音广播等 +6. TCP面向字节流,UDP面向报文 + +### 7. TCP报文首部有哪些字段,说说其作用 + + +![](https://files.mdnice.com/user/3535/f9f25411-09d7-4441-bf64-3f0881c4fc01.png) + +- **16位端口号**:源端口号,主机该报文段是来自哪里;目标端口号,要传给哪个上层协议或应用程序 +- **32位序号**:一次TCP通信(从TCP连接建立到断开)过程中某一个传输方向上的字节流的每个字节的编号。 +- **32位确认号**:用作对另一方发送的tcp报文段的响应。其值是收到的TCP报文段的序号值加1。 +- **4位头部长度**:表示tcp头部有多少个32bit字(4字节)。因为4位最大能标识15,所以TCP头部最长是60字节。 +- **6位标志位**:URG(紧急指针是否有效),ACk(表示确认号是否有效),PSH(缓冲区尚未填满),RST(表示要求对方重新建立连接),SYN(建立连接消息标志接),FIN(表示告知对方本端要关闭连接了) +- **16位窗口大小**:是TCP流量控制的一个手段。这里说的窗口,指的是接收通告窗口。它告诉对方本端的TCP接收缓冲区还能容纳多少字节的数据,这样对方就可以控制发送数据的速度。 +- **16位校验和**:由发送端填充,接收端对TCP报文段执行CRC算法以检验TCP报文段在传输过程中是否损坏。注意,这个校验不仅包括TCP头部,也包括数据部分。这也是TCP可靠传输的一个重要保障。 +- **16位紧急指针**:一个正的偏移量。它和序号字段的值相加表示最后一个紧急数据的下一字节的序号。因此,确切地说,这个字段是紧急指针相对当前序号的偏移,不妨称之为紧急偏移。TCP的紧急指针是发送端向接收端发送紧急数据的方法。 + +### 8. TCP 是如何保证可靠性的 + + +![](https://files.mdnice.com/user/3535/fce5ee83-8664-4f82-a453-fe25bc35dd88.png) + + +- 首先,TCP的连接是基于**三次握手**,而断开则是**四次挥手**。确保连接和断开的可靠性。 +- 其次,TCP的可靠性,还体现在**有状态**;TCP会记录哪些数据发送了,哪些数据被接受了,哪些没有被接受,并且保证数据包按序到达,保证数据传输不出差错。 +- 再次,TCP的可靠性,还体现在**可控制**。它有报文校验、ACK应答、**超时重传(发送方)**、失序数据重传(接收方)、丢弃重复数据、流量控制(滑动窗口)和拥塞控制等机制。 + +### 9. TCP 重传机制 + +#### 超时重传 +TCP 为了实现可靠传输,实现了重传机制。最基本的重传机制,就是**超时重传**,即在发送数据报文时,设定一个定时器,每间隔一段时间,没有收到对方的ACK确认应答报文,就会重发该报文。 + +这个间隔时间,一般设置为多少呢?我们先来看下什么叫**RTT(Round-Trip Time,往返时间)**。 + +![](https://files.mdnice.com/user/3535/05b6c061-2515-4367-aa58-0526db10f6b6.png) + +RTT就是,一个数据包从发出去到回来的时间,即**数据包的一次往返时间**。超时重传时间,就是Retransmission Timeout ,简称**RTO**。 + +**RTO设置多久呢?** +- 如果RTO比较小,那很可能数据都没有丢失,就重发了,这会导致网络阻塞,会导致更多的超时出现。 +- 如果RTO比较大,等到花儿都谢了还是没有重发,那效果就不好了。 + +一般情况下,RTO略大于RTT,效果是最好的。一些小伙伴会问,超时时间有没有计算公式呢?有的!有个标准方法算RTO的公式,也叫**Jacobson / Karels 算法**。我们一起来看下计算RTO的公式 + +**1. 先计算SRTT(计算平滑的RTT)** + +``` +SRTT = (1 - α) * SRTT + α * RTT //求 SRTT 的加权平均 +``` + +**2. 再计算RTTVAR (round-trip time variation)** + + +``` +RTTVAR = (1 - β) * RTTVAR + β * (|RTT - SRTT|) //计算 SRTT 与真实值的差距 +``` + +**3. 最终的RTO** + +``` +RTO = µ * SRTT + ∂ * RTTVAR = SRTT + 4·RTTVAR +``` + +其中,```α = 0.125,β = 0.25, μ = 1,∂ = 4```,这些参数都是大量结果得出的最优参数。 + +但是,超时重传会有这些缺点: +> - 当一个报文段丢失时,会等待一定的超时周期然后才重传分组,增加了端到端的时延。 +> - 当一个报文段丢失时,在其等待超时的过程中,可能会出现这种情况:其后的报文段已经被接收端接收但却迟迟得不到确认,发送端会认为也丢失了,从而引起不必要的重传,既浪费资源也浪费时间。 + +并且,TCP有个策略,就是超时时间间隔会加倍。超时重传需要**等待很长时间**。因此,还可以使用**快速重传**机制。 + +#### 快速重传 + +**快速重传**机制,它不以时间驱动,而是以数据驱动。它基于接收端的反馈信息来引发重传。 + +一起来看下快速重传流程: + +![快速重传流程](https://files.mdnice.com/user/3535/2c172057-bb6c-40e1-8d64-b6a15818f596.png) + +发送端发送了 1,2,3,4,5,6 份数据: + +- 第一份 Seq=1 先送到了,于是就 Ack 回 2; +- 第二份 Seq=2 也送到了,假设也正常,于是ACK 回 3; +- 第三份 Seq=3 由于网络等其他原因,没送到; +- 第四份 Seq=4 也送到了,但是因为Seq3没收到。所以ACK回3; +- 后面的 Seq=4,5的也送到了,但是ACK还是回复3,因为Seq=3没收到。 +- 发送端连着收到三个重复冗余ACK=3的确认(实际上是4个,但是前面一个是正常的ACK,后面三个才是重复冗余的),便知道哪个报文段在传输过程中丢失了,于是在定时器过期之前,重传该报文段。 +- 最后,接收到收到了 Seq3,此时因为 Seq=4,5,6都收到了,于是ACK回7. + +但**快速重传**还可能会有个问题:ACK只向发送端告知最大的有序报文段,到底是哪个报文丢失了呢?**并不确定**!那到底该重传多少个包呢? +> 是重传 Seq3 呢?还是重传 Seq3、Seq4、Seq5、Seq6 呢?因为发送端并不清楚这三个连续的 ACK3 是谁传回来的。 + +#### 带选择确认的重传(SACK) + +为了解决快速重传的问题:**应该重传多少个包**? TCP提供了**SACK方法**(带选择确认的重传,Selective Acknowledgment)。 + +**SACK机制**就是,在快速重传的基础上,接收端返回最近收到的报文段的序列号范围,这样发送端就知道接收端哪些数据包没收到,酱紫就很清楚该重传哪些数据包啦。SACK标记是加在TCP头部**选项**字段里面的。 + +![SACK机制](https://files.mdnice.com/user/3535/9475e768-9d4d-46dd-97a5-ec2298c433bd.png) + +如上图中,发送端收到了三次同样的ACK=30的确认报文,于是就会触发快速重发机制,通过SACK信息发现只有```30~39```这段数据丢失,于是重发时就只选择了这个```30~39```的TCP报文段进行重发。 + +#### D-SACK + + D-SACK,即Duplicate SACK(重复SACK),在SACK的基础上做了一些扩展,,主要用来告诉发送方,有哪些数据包自己重复接受了。DSACK的目的是帮助发送方判断,是否发生了包失序、ACK丢失、包重复或伪重传。让TCP可以更好的做网络流控。来看个图吧: + +![D-SACK简要流程](https://files.mdnice.com/user/3535/d3647f5d-ce7c-4998-953a-04e8c8a9e71c.png) + +### 10. 聊聊TCP的滑动窗口 + +TCP 发送一个数据,需要收到确认应答,才会发送下一个数据。这样有个缺点,就是效率会比较低。 +> 这就好像我们面对面聊天,你说完一句,我应答后,你才会说下一句。那么,如果我在忙其他事情,没有能够及时回复你。你说完一句后,要等到我忙完回复你,你才说下句,这显然很不现实。 + +为了解决这个问题,TCP引入了**窗口**,它是操作系统开辟的一个缓存空间。窗口大小值表示无需等待确认应答,而可以继续发送数据的最大值。 + +TCP头部有个字段叫win,也即那个**16位的窗口大小**,它告诉对方本端的TCP接收缓冲区还能容纳多少字节的数据,这样对方就可以控制发送数据的速度,从而达到**流量控制**的目的。 +> 通俗点讲,就是接受方每次收到数据包,在发送确认报文的时候,同时告诉发送方,自己的缓存区还有多少空余空间,缓冲区的空余空间,我们就称之为接受窗口大小。这就是win。 + +TCP 滑动窗口分为两种: 发送窗口和接收窗口。**发送端的滑动窗口**包含四大部分,如下: +- 已发送且已收到ACK确认 +- 已发送但未收到ACK确认 +- 未发送但可以发送 +- 未发送也不可以发送 + +![](https://files.mdnice.com/user/3535/8f7d9784-f6e6-47d8-82bb-deb398431025.png) + +- 虚线矩形框,就是发送窗口。 +- SND.WND: 表示发送窗口的大小,上图虚线框的格子数就是14个。 +- SND.UNA: 一个绝对指针,它指向的是已发送但未确认的第一个字节的序列号。 +- SND.NXT:下一个发送的位置,它指向未发送但可以发送的第一个字节的序列号。 + +接收方的滑动窗口包含三大部分,如下: +- 已成功接收并确认 +- 未收到数据但可以接收 +- 未收到数据并不可以接收的数据 + +![](https://files.mdnice.com/user/3535/40b906fe-aa60-42f3-b7bf-b4fcaa9a0588.png) + +- 虚线矩形框,就是接收窗口。 +- REV.WND: 表示接收窗口的大小,上图虚线框的格子就是9个。 +- REV.NXT:下一个接收的位置,它指向未收到但可以接收的第一个字节的序列号。 + +### 11. 聊聊TCP的流量控制 + +TCP三次握手,发送端和接收端进入到ESTABLISHED状态,它们即可以愉快地传输数据啦。 + +但是发送端不能疯狂地向接收端发送数据,因为接收端接收不过来的话,接收方只能把处理不过来的数据存在缓存区里。如果缓存区都满了,发送方还在疯狂发送数据的话,接收方只能把收到的数据包丢掉,这就浪费了网络资源啦。 + +> TCP 提供一种机制可以让发送端根据接收端的实际接收能力控制发送的数据量,这就是**流量控制**。 + +TCP通过滑动窗口来控制流量,我们看下流量控制的**简要流程**吧: + +首先双方三次握手,初始化各自的窗口大小,均为 400 个字节。 + + +![TCP的流量控制](https://files.mdnice.com/user/3535/e233b594-72b5-4f9a-bc9c-23bb5c065bfe.png) + +1. 假如当前发送方给接收方发送了200个字节,那么,发送方的```SND.NXT```会右移200个字节,也就是说当前的可用窗口减少了200 个字节。 +2. 接受方收到后,放到缓冲队列里面,REV.WND =400-200=200字节,所以win=200字节返回给发送方。接收方会在 ACK 的报文首部带上缩小后的滑动窗口200字节 +3. 发送方又发送200字节过来,200字节到达,继续放到缓冲队列。不过这时候,由于大量负载的原因,接受方处理不了这么多字节,只能处理100字节,剩余的100字节继续放到缓冲队列。这时候,REV.WND = 400-200-100=100字节,即win=100返回发送方。 +4. 发送方继续干活,发送100字节过来,这时候,接受窗口win变为0。 +5. 发送方停止发送,开启一个定时任务,每隔一段时间,就去询问接受方,直到win大于0,才继续开始发送。 + +### 12. TCP的拥塞控制 + +拥塞控制是**作用于网络的,防止过多的数据包注入到网络中,避免出现网络负载过大的情况**。它的目标主要是最大化利用网络上瓶颈链路的带宽。它跟**流量控制**又有什么区别呢?流量控制是作用于接收者的,根据**接收端的实际接收能力控制发送速度**,防止分组丢失的。 + +我们可以把网络链路比喻成一根水管,如果我们想最大化利用网络来传输数据,那就是尽快让水管达到最佳充满状态。 + +![](https://files.mdnice.com/user/3535/f4b5b102-75db-47cc-8c1a-83fa01941dcc.png) + +发送方维护一个**拥塞窗口cwnd(congestion window)** 的变量,用来估算在一段时间内这条链路(水管)可以承载和运输的数据(水)的数量。它大小代表着网络的拥塞程度,并且是动态变化的,但是为了达到最大的传输效率,我们该如何知道这条水管的运送效率是多少呢? + +一个比较简单的方法就是不断增加传输的水量,直到水管快要爆裂为止(对应到网络上就是发生丢包),用 TCP 的描述就是: +> 只要网络中没有出现拥塞,拥塞窗口的值就可以再增大一些,以便把更多的数据包发送出去,但只要网络出现拥塞,拥塞窗口的值就应该减小一些,以减少注入到网络中的数据包数。 + +实际上,拥塞控制主要有这几种常用算法 +- 慢启动 +- 拥塞避免 +- 拥塞发生 +- 快速恢复 + +#### 慢启动算法 + +慢启动算法,表面意思就是,别急慢慢来。它表示TCP建立连接完成后,一开始不要发送大量的数据,而是先探测一下网络的拥塞程度。由小到大逐渐增加拥塞窗口的大小,如果没有出现丢包,**每收到一个ACK,就将拥塞窗口cwnd大小就加1(单位是MSS)**。**每轮次**发送窗口增加一倍,呈指数增长,如果出现丢包,拥塞窗口就减半,进入拥塞避免阶段。 + +- TCP连接完成,初始化cwnd = 1,表明可以传一个MSS单位大小的数据。 +- 每当收到一个ACK,cwnd就加一; +- 每当过了一个RTT,cwnd就增加一倍; 呈指数让升 + +![](https://files.mdnice.com/user/3535/c9edd5d1-0302-45b7-bee7-22d1e505b085.png) + +为了防止cwnd增长过大引起网络拥塞,还需设置一个**慢启动阀值ssthresh**(slow start threshold)状态变量。当```cwnd```到达该阀值后,就好像水管被关小了水龙头一样,减少拥塞状态。即当**cwnd >ssthresh**时,进入了**拥塞避免**算法。 + + +#### 拥塞避免算法 + +一般来说,慢启动阀值ssthresh是65535字节,```cwnd```到达**慢启动阀值**后 +- 每收到一个ACK时,cwnd = cwnd + 1/cwnd +- 当每过一个RTT时,cwnd = cwnd + 1 + +显然这是一个线性上升的算法,避免过快导致网络拥塞问题。 + +![](https://files.mdnice.com/user/3535/600ed914-5f98-4c01-9f1d-d7dcc12244b8.png) + +#### 拥塞发生 + +当网络拥塞发生**丢包**时,会有两种情况: + +- RTO超时重传 +- 快速重传 + +如果是发生了**RTO超时重传**,就会使用拥塞发生算法 + +- 慢启动阀值sshthresh = cwnd /2 +- cwnd 重置为 1 +- 进入新的慢启动过程 + + +![](https://files.mdnice.com/user/3535/9e54bfb4-ed83-42a9-aeb0-f98b44563067.png) + +这真的是**辛辛苦苦几十年,一朝回到解放前**。其实还有更好的处理方式,就是**快速重传**。发送方收到3个连续重复的ACK时,就会快速地重传,不必等待**RTO超时**再重传。 + +![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e5f5ca98465c40b0936ed83aba2ffc15~tplv-k3u1fbpfcp-watermark.image) + +慢启动阀值ssthresh 和 cwnd 变化如下: + +- 拥塞窗口大小 cwnd = cwnd/2 +- 慢启动阀值 ssthresh = cwnd +- 进入快速恢复算法 + +#### 快速恢复 + +快速重传和快速恢复算法一般同时使用。快速恢复算法认为,还有3个重复ACK收到,说明网络也没那么糟糕,所以没有必要像RTO超时那么强烈。 + +正如前面所说,进入快速恢复之前,cwnd 和 sshthresh已被更新: +``` +- cwnd = cwnd /2 +- sshthresh = cwnd +``` + +然后,真正的快速算法如下: + +- cwnd = sshthresh + 3 +- 重传重复的那几个ACK(即丢失的那几个数据包) +- 如果再收到重复的 ACK,那么 cwnd = cwnd +1 +- 如果收到新数据的 ACK 后, cwnd = sshthresh。因为收到新数据的 ACK,表明恢复过程已经结束,可以再次进入了拥塞避免的算法了。 + +![](https://files.mdnice.com/user/3535/1cb2de35-db67-4efa-8b64-1ea00d57c116.png) + +### 13. 半连接队列和 SYN Flood 攻击的关系 + +TCP进入三次握手前,服务端会从**CLOSED**状态变为**LISTEN**状态,同时在内部创建了两个队列:半连接队列(SYN队列)和全连接队列(ACCEPT队列)。 + +什么是**半连接队列(SYN队列)** 呢? 什么是**全连接队列(ACCEPT队列)** 呢?回忆下TCP三次握手的图: + +![三次握手](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/67e2444df1934f549e7509fb5ce4b561~tplv-k3u1fbpfcp-watermark.image) + +- TCP三次握手时,客户端发送SYN到服务端,服务端收到之后,便回复**ACK和SYN**,状态由**LISTEN变为SYN_RCVD**,此时这个连接就被推入了**SYN队列**,即半连接队列。 +- 当客户端回复ACK, 服务端接收后,三次握手就完成了。这时连接会等待被具体的应用取走,在被取走之前,它被推入ACCEPT队列,即全连接队列。 + +SYN Flood是一种典型的DoS (Denial of Service,拒绝服务) 攻击,它在短时间内,伪造**不存在的IP地址**,向服务器大量发起SYN报文。当服务器回复SYN+ACK报文后,不会收到ACK回应报文,导致服务器上建立大量的半连接半连接队列满了,这就无法处理正常的TCP请求啦。 + +主要有 **syn cookie**和**SYN Proxy防火墙**等方案应对。 + +- **syn cookie**:在收到SYN包后,服务器根据一定的方法,以数据包的源地址、端口等信息为参数计算出一个cookie值作为自己的SYNACK包的序列号,回复SYN+ACK后,服务器并不立即分配资源进行处理,等收到发送方的ACK包后,重新根据数据包的源地址、端口计算该包中的确认序列号是否正确,如果正确则建立连接,否则丢弃该包。 + +- **SYN Proxy防火墙**:服务器防火墙会对收到的每一个SYN报文进行代理和回应,并保持半连接。等发送方将ACK包返回后,再重新构造SYN包发到服务器,建立真正的TCP连接。 + +### 14. Nagle 算法与延迟确认 + +#### Nagle算法 + +如果发送端疯狂地向接收端发送很小的包,比如就1个字节,那么亲爱的小伙伴,你们觉得会有什么问题呢? + +> TCP/IP协议中,无论发送多少数据,总是要在数据前面加上协议头,同时,对方接收到数据,也需要发送ACK表示确认。为了尽可能的利用网络带宽,TCP总是希望尽可能的发送足够大的数据。**Nagle算法**就是为了尽可能发送大块数据,避免网络中充斥着许多小数据块。 + +Nagle算法的基本定义是:**任意时刻,最多只能有一个未被确认的小段**。 所谓“小段”,指的是小于MSS尺寸的数据块,所谓“未被确认”,是指一个数据块发送出去后,没有收到对方发送的ACK确认该数据已收到。 + +Nagle算法的实现规则: + +- 如果包长度达到MSS,则允许发送; +- 如果该包含有FIN,则允许发送; +- 设置了TCP_NODELAY选项,则允许发送; +- 未设置TCP_CORK选项时,若所有发出去的小数据包(包长度小于MSS)均被确认,则允许发送; +- 上述条件都未满足,但发生了超时(一般为200ms),则立即发送。 + +#### 延迟确认 + +如果接受方刚接收到发送方的数据包,在很短很短的时间内,又接收到第二个包。那么请问接收方是一个一个地回复好点,还是合并一起回复好呢? + +> 接收方收到数据包后,如果暂时没有数据要发给对端,它可以等一段时再确认(Linux上默认是40ms)。如果这段时间刚好有数据要传给对端,ACK就随着数据传输,而不需要单独发送一次ACK。如果超过时间还没有数据要发送,也发送ACK,避免对端以为丢包。 + +但是有些场景不能延迟确认,比如发现了**乱序包**、**接收到了大于一个 frame 的报文,且需要调整窗口大小**等。 + +一般情况下,**Nagle算法和延迟确认**不能一起使用,Nagle算法意味着延迟发,**延迟确认**意味着延迟接收,酱紫就会造成更大的延迟,会产生性能问题。 + +### 15. TCP的粘包和拆包 + +TCP是面向流,没有界限的一串数据。TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一**个完整的包可能会被TCP拆分成多个包进行发送**,**也有可能把多个小的包封装成一个大的数据包发送**,这就是所谓的TCP粘包和拆包问题。 + +![TCP的粘包和拆包](https://files.mdnice.com/user/3535/cf617d8f-70c3-4687-bb20-1bc3518bed11.png) + + +**为什么会产生粘包和拆包呢?** + +- 要发送的数据小于TCP发送缓冲区的大小,TCP将多次写入缓冲区的数据一次发送出去,将会发生粘包; +- 接收数据端的应用层没有及时读取接收缓冲区中的数据,将发生粘包; +- 要发送的数据大于TCP发送缓冲区剩余空间大小,将会发生拆包; +- 待发送数据大于MSS(最大报文长度),TCP在传输前将进行拆包。即TCP报文长度-TCP头部长度>MSS。 + +**解决方案:** + +- 发送端将每个数据包封装为固定长度 +- 在数据尾部增加特殊字符进行分割 +- 将数据分为两部分,一部分是头部,一部分是内容体;其中头部结构大小固定,且有一个字段声明内容体的大小。 + +### 参考与感谢 +- [TCP 的那些事儿(下)](https://coolshell.cn/articles/11609.html "TCP 的那些事儿(下)") +- [面试头条你需要懂的 TCP 拥塞控制原理](https://zhuanlan.zhihu.com/p/76023663 "面试头条你需要懂的 TCP 拥塞控制原理") +- [30张图解: TCP 重传、滑动窗口、流量控制、拥塞控制发愁](https://zhuanlan.zhihu.com/p/133307545 "30张图解: TCP 重传、滑动窗口、流量控制、拥塞控制发愁") +- [TCP协议灵魂之问,巩固你的网路底层基础](https://juejin.cn/post/6844904070889603085 "TCP协议灵魂之问,巩固你的网路底层基础") +- [TCP粘包和拆包](https://blog.csdn.net/ailunlee/article/details/95944377 "TCP粘包和拆包") +- 百度百科 + + + diff --git "a/Mysql\345\237\272\347\241\200\345\255\246\344\271\240/README.md" "b/Mysql\345\237\272\347\241\200\345\255\246\344\271\240/README.md" new file mode 100644 index 0000000..f335927 --- /dev/null +++ "b/Mysql\345\237\272\347\241\200\345\255\246\344\271\240/README.md" @@ -0,0 +1,2 @@ +- [聊聊select for update到底加了什么锁](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247506728&idx=1&sn=5526ee3984e971d4c3b251c2ad76d658&chksm=c1e026a4f697afb28224d5ce0ecca7432879b357cd6433834c66d94c72a1935ba13e2e3e274e&token=337310304&lang=zh_CN#rd) +- [数据库死锁排查思路分享](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247507770&idx=1&sn=b84b20aca057b34d511a501ff91941b5&chksm=c1e022b6f697aba05248128cb82f93aed341b1cc80e6d568c7150a4ffa6775692c7c9fa423a3&token=1822874069&lang=zh_CN#rd) diff --git "a/Mysql\345\237\272\347\241\200\345\255\246\344\271\240/order by\350\257\246\350\247\243.md" "b/Mysql\345\237\272\347\241\200\345\255\246\344\271\240/order by\350\257\246\350\247\243.md" new file mode 100644 index 0000000..3aeda16 --- /dev/null +++ "b/Mysql\345\237\272\347\241\200\345\255\246\344\271\240/order by\350\257\246\350\247\243.md" @@ -0,0 +1,348 @@ +## 前言 + +日常开发中,我们经常会使用到order by,亲爱的小伙伴,你是否知道order by 的工作原理呢?order by的优化思路是怎样的呢?使用order by有哪些注意的问题呢?本文将跟大家一起来学习,攻克order by~ + + +![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3b1eda4fbc6c458c9182545d93cb6f15~tplv-k3u1fbpfcp-watermark.image) + +- 微信公众号:**捡田螺的小男孩** +- [github地址,感谢每一颗star](https://github.com/whx123/JavaHome) +- 如果觉得有收获,帮忙点赞,转发下哈,感谢感谢 + + +## 一个使用order by 的简单例子 + +假设用一张员工表,表结构如下: + +``` +CREATE TABLE `staff` ( +`id` BIGINT ( 11 ) AUTO_INCREMENT COMMENT '主键id', +`id_card` VARCHAR ( 20 ) NOT NULL COMMENT '身份证号码', +`name` VARCHAR ( 64 ) NOT NULL COMMENT '姓名', +`age` INT ( 4 ) NOT NULL COMMENT '年龄', +`city` VARCHAR ( 64 ) NOT NULL COMMENT '城市', +PRIMARY KEY ( `id`), +INDEX idx_city ( `city` ) +) ENGINE = INNODB COMMENT '员工表'; + +``` + +表数据如下: + + +![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/aadfe321a1b74141a418f4a4c2f75e82~tplv-k3u1fbpfcp-watermark.image) + +我们现在有这么一个需求:**查询前10个,来自深圳员工的姓名、年龄、城市,并且按照年龄小到大排序**。对应的 SQL 语句就可以这么写: + +``` +select name,age,city from staff where city = '深圳' order by age limit 10; +``` + +这条语句的逻辑很清楚,但是它的**底层执行流程**是怎样的呢? + +## order by 工作原理 + +![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/582926f8d02e44d4b94e23a3fafc0ec8~tplv-k3u1fbpfcp-watermark.image) + +### explain 执行计划 + +我们先用**Explain**关键字查看一下执行计划 + + +![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2da79360c7204f5d8fada7f8ec2d21ba~tplv-k3u1fbpfcp-watermark.image) + +- 执行计划的**key**这个字段,表示使用到索引idx_city +- Extra 这个字段的 **Using index condition** 表示索引条件 +- Extra 这个字段的 **Using filesort**表示用到排序 + +我们可以发现,这条SQL使用到了索引,并且也用到排序。那么它是**怎么排序**的呢? + +### 全字段排序 + +MySQL 会给每个查询线程分配一块小**内存**,用于**排序**的,称为 **sort_buffer**。什么时候把字段放进去排序呢,其实是通过```idx_city```索引找到对应的数据,才把数据放进去啦。 + +我们回顾下索引是怎么找到匹配的数据的,现在先把索引树画出来吧,**idx_city**索引树如下: + + +![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/773e727c45254b7a858a780fdeff8a7c~tplv-k3u1fbpfcp-watermark.image) + +idx_city索引树,叶子节点存储的是**主键id**。 还有一棵id主键聚族索引树,我们再画出聚族索引树图吧: + + +![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f12ea50032b6428c899ee143663aa3de~tplv-k3u1fbpfcp-watermark.image) + + +**我们的查询语句是怎么找到匹配数据的呢**?先通过**idx_city**索引树,找到对应的主键id,然后再通过拿到的主键id,搜索**id主键索引树**,找到对应的行数据。 + +加上**order by**之后,整体的执行流程就是: + +1. MySQL 为对应的线程初始化**sort_buffer**,放入需要查询的name、age、city字段; +2. 从**索引树idx_city**, 找到第一个满足 city='深圳’条件的主键 id,也就是图中的id=9; +3. 到**主键 id 索引树**拿到id=9的这一行数据, 取name、age、city三个字段的值,存到sort_buffer; +4. 从**索引树idx_city** 拿到下一个记录的主键 id,即图中的id=13; +5. 重复步骤 3、4 直到**city的值不等于深圳**为止; +6. 前面5步已经查找到了所有**city为深圳**的数据,在 sort_buffer中,将所有数据根据age进行排序; +7. 按照排序结果取前10行返回给客户端。 + +执行示意图如下: + +![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6d8760fdf99741b492ab032cd3d0d87c~tplv-k3u1fbpfcp-watermark.image) + +将查询所需的字段全部读取到sort_buffer中,就是**全字段排序**。这里面,有些小伙伴可能会有个疑问,把查询的所有字段都放到sort_buffer,而sort_buffer是一块内存来的,如果数据量太大,sort_buffer放不下怎么办呢? + +### 磁盘临时文件辅助排序 + +实际上,sort_buffer的大小是由一个参数控制的:**sort_buffer_size**。如果要排序的数据小于sort_buffer_size,排序在**sort_buffer** 内存中完成,如果要排序的数据大于sort_buffer_size,则**借助磁盘文件来进行排序** + +如何确定是否使用了磁盘文件来进行排序呢? 可以使用以下这几个命令 + +``` +## 打开optimizer_trace,开启统计 +set optimizer_trace = "enabled=on"; +## 执行SQL语句 +select name,age,city from staff where city = '深圳' order by age limit 10; +## 查询输出的统计信息 +select * from information_schema.optimizer_trace +``` + +可以从 **number_of_tmp_files** 中看出,是否使用了临时文件。 + + + +![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c876d88537ce4b67bcf8f991df17aa94~tplv-k3u1fbpfcp-watermark.image) + +**number_of_tmp_files** 表示使用来排序的磁盘临时文件数。如果number_of_tmp_files>0,则表示使用了磁盘文件来进行排序。 + +使用了磁盘临时文件,整个排序过程又是怎样的呢? + +1. 从**主键Id索引树**,拿到需要的数据,并放到**sort_buffer内存**块中。当sort_buffer快要满时,就对sort_buffer中的数据排序,排完后,把数据临时放到磁盘一个小文件中。 +2. 继续回到主键 id 索引树取数据,继续放到sort_buffer内存中,排序后,也把这些数据写入到磁盘临时小文件中。 +3. 继续循环,直到取出所有满足条件的数据。最后把磁盘的临时排好序的小文件,合并成一个有序的大文件。 + + +**TPS:** 借助磁盘临时小文件排序,实际上使用的是**归并排序**算法。 + +小伙伴们可能会有个疑问,既然**sort_buffer**放不下,就需要用到临时磁盘文件,这会影响排序效率。那为什么还要把排序不相关的字段(name,city)放到sort_buffer中呢?只放排序相关的age字段,它**不香**吗? 可以了解下**rowid 排序**。 + + +### rowid 排序 + +rowid 排序就是,只把查询SQL**需要用于排序的字段和主键id**,放到sort_buffer中。那怎么确定走的是全字段排序还是rowid 排序排序呢? + +实际上有个参数控制的。这个参数就是**max_length_for_sort_data**,它表示MySQL用于排序行数据的长度的一个参数,如果单行的长度超过这个值,MySQL 就认为单行太大,就换rowid 排序。我们可以通过命令看下这个参数取值。 + + +``` +show variables like 'max_length_for_sort_data'; +``` + +![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ce8fc30884e74dd5b09c0028640ce7ea~tplv-k3u1fbpfcp-watermark.image) + +**max_length_for_sort_data** 默认值是1024。因为本文示例中name,age,city长度=64+4+64 =132 < 1024, 所以走的是全字段排序。我们来改下这个参数,改小一点, + +``` +## 修改排序数据最大单行长度为32 +set max_length_for_sort_data = 32; +## 执行查询SQL +select name,age,city from staff where city = '深圳' order by age limit 10; +``` + +使用rowid 排序的话,整个SQL执行流程又是怎样的呢? + +1. MySQL 为对应的线程初始化**sort_buffer**,放入需要排序的age字段,以及主键id; +2. 从**索引树idx_city**, 找到第一个满足 city='深圳’条件的主键 id,也就是图中的id=9; +3. 到**主键 id 索引树**拿到id=9的这一行数据, 取age和主键id的值,存到sort_buffer; +4. 从**索引树idx_city** 拿到下一个记录的主键 id,即图中的id=13; +5. 重复步骤 3、4 直到**city的值不等于深圳**为止; +6. 前面5步已经查找到了所有city为深圳的数据,在 **sort_buffer**中,将所有数据根据age进行排序; +7. 遍历排序结果,取前10行,并按照 id 的值**回到原表**中,取出city、name 和 age 三个字段返回给客户端。 + + +执行示意图如下: + + +![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2addcf67082741e19637dae2e69ee515~tplv-k3u1fbpfcp-watermark.image) + + +对比一下**全字段排序**的流程,rowid 排序多了一次**回表**。 + +> 什么是回表?拿到主键再回到主键索引查询的过程,就叫做回表 + + +我们通过**optimizer_trace**,可以看到是否使用了rowid排序的: + + +``` +## 打开optimizer_trace,开启统计 +set optimizer_trace = "enabled=on"; +## 执行SQL语句 +select name,age,city from staff where city = '深圳' order by age limit 10; +## 查询输出的统计信息 +select * from information_schema.optimizer_trace + +``` + +![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/446258ee4bfa40e6ad80596202c8d5a0~tplv-k3u1fbpfcp-watermark.image) + + +### 全字段排序与rowid排序对比 + + +- 全字段排序: sort_buffer内存不够的话,就需要用到磁盘临时文件,造成**磁盘访问**。 +- rowid排序: sort_buffer可以放更多数据,但是需要再回到原表去取数据,比全字段排序多一次**回表**。 + +一般情况下,对于InnoDB存储引擎,会优先使**用全字段**排序。可以发现 **max_length_for_sort_data** 参数设置为1024,这个数比较大的。一般情况下,排序字段不会超过这个值,也就是都会走**全字段**排序。 + + +## order by的一些优化思路 + +我们如何优化order by语句呢? + + +- 因为数据是无序的,所以就需要排序。如果数据本身是有序的,那就不用排了。而索引数据本身是有序的,我们通过建立**联合索引**,优化order by 语句。 +- 我们还可以通过调整**max_length_for_sort_data**等参数优化; + + +### 联合索引优化 + +再回顾下示例SQL的查询计划 + +``` +explain select name,age,city from staff where city = '深圳' order by age limit 10; +``` + +![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7fce894de9024dd5913e98116dca832f~tplv-k3u1fbpfcp-watermark.image) + +我们给查询条件```city```和排序字段```age```,加个联合索引**idx_city_age**。再去查看执行计划 + +``` +alter table staff add index idx_city_age(city,age); +explain select name,age,city from staff where city = '深圳' order by age limit 10; +``` + +![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/33621e91730b44e5bb88c27b74614b89~tplv-k3u1fbpfcp-watermark.image) + +可以发现,加上**idx_city_age**联合索引,就不需要**Using filesort**排序了。为什么呢?因为**索引本身是有序的**,我们可以看下**idx_city_age**联合索引示意图,如下: + + + +![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/19b368a039a34678aeea8e297eee05e8~tplv-k3u1fbpfcp-watermark.image) + +整个SQL执行流程变成酱紫: +1. 从索引idx_city_age找到满足**city='深圳’** 的主键 id +2. 到**主键 id索引**取出整行,拿到 name、city、age 三个字段的值,作为结果集的一部分直接返回 +3. 从索引**idx_city_age**取下一个记录主键id +4. 重复步骤 2、3,直到查到**第10条**记录,或者是**不满足city='深圳’** 条件时循环结束。 + +流程示意图如下: + +![image.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/95f6a85904934d9688598d436fbcc1ee~tplv-k3u1fbpfcp-watermark.image) + + +从示意图看来,还是有一次回表操作。针对本次示例,有没有更高效的方案呢?有的,可以使用**覆盖索引**: + +> 覆盖索引:在查询的数据列里面,不需要回表去查,直接从索引列就能取到想要的结果。换句话说,你SQL用到的索引列数据,覆盖了查询结果的列,就算上覆盖索引了。 + +我们给city,name,age 组成一个联合索引,即可用到了覆盖索引,这时候SQL执行时,连回表操作都可以省去啦。 + +### 调整参数优化 + +我们还可以通过调整参数,去优化order by的执行。比如可以调整sort_buffer_size的值。因为sort_buffer值太小,数据量大的话,会借助磁盘临时文件排序。如果MySQL服务器配置高的话,可以使用稍微调整大点。 + +我们还可以调整max_length_for_sort_data的值,这个值太小的话,order by会走rowid排序,会回表,降低查询性能。所以max_length_for_sort_data可以适当大一点。 + +当然,很多时候,这些MySQL参数值,我们直接采用默认值就可以了。 + +## 使用order by 的一些注意点 + +### 没有where条件,order by字段需要加索引吗 + +日常开发过程中,我们可能会遇到没有where条件的order by,那么,这时候order by后面的字段是否需要加索引呢。如有这么一个SQL,create_time是否需要加索引: + +``` +select * from A order by create_time; +``` + +无条件查询的话,即使create_time上有索引,也不会使用到。因为MySQL优化器认为走普通二级索引,再去回表成本比全表扫描排序更高。所以选择走全表扫描,然后根据全字段排序或者rowid排序来进行。 + +如果查询SQL修改一下: + +``` +select * from A order by create_time limit m; +``` +- 无条件查询,如果m值较小,是可以走索引的.因为MySQL优化器认为,根据索引有序性去回表查数据,然后得到m条数据,就可以终止循环,那么成本比全表扫描小,则选择走二级索引。 + + +### 分页limit过大时,会导致大量排序怎么办? + +假设SQL如下: +``` +select * from A order by a limit 100000,10 +``` + +- 可以记录上一页最后的id,下一页查询时,查询条件带上id,如: where id > 上一页最后id limit 10。 +- 也可以在业务允许的情况下,限制页数。 + + +### 索引存储顺序与order by不一致,如何优化? + +假设有联合索引 idx_age_name, 我们需求修改为这样:**查询前10个员工的姓名、年龄,并且按照年龄小到大排序,如果年龄相同,则按姓名降序排**。对应的 SQL 语句就可以这么写: + +``` +select name,age from staff order by age ,name desc limit 10; +``` +我们看下执行计划,发现使用到**Using filesort**。 + +![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/bdc45d41d0744567bc753892661789b7~tplv-k3u1fbpfcp-watermark.image) + +这是因为,idx_age_name索引树中,age从小到大排序,如果**age相同,再按name从小到大排序**。而order by 中,是按age从小到大排序,如果**age相同,再按name从大到小排序**。也就是说,索引存储顺序与order by不一致。 + +我们怎么优化呢?如果MySQL是8.0版本,支持**Descending Indexes**,可以这样修改索引: + +``` +CREATE TABLE `staff` ( + `id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT '主键id', + `id_card` varchar(20) NOT NULL COMMENT '身份证号码', + `name` varchar(64) NOT NULL COMMENT '姓名', + `age` int(4) NOT NULL COMMENT '年龄', + `city` varchar(64) NOT NULL COMMENT '城市', + PRIMARY KEY (`id`), + KEY `idx_age_name` (`age`,`name` desc) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8 COMMENT='员工表'; +``` + + +### 使用了in条件多个属性时,SQL执行是否有排序过程 + +如果我们有**联合索引idx_city_name**,执行这个SQL的话,是不会走排序过程的,如下: + +``` +select * from staff where city in ('深圳') order by age limit 10; +``` + +![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0d5c0099035f48529075b6bc9d396cca~tplv-k3u1fbpfcp-watermark.image) + + + +但是,如果使用in条件,并且有多个条件时,就会有排序过程。 + +``` + explain select * from staff where city in ('深圳','上海') order by age limit 10; +``` + +![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1813404917da4dc9898ab7a14afb811f~tplv-k3u1fbpfcp-watermark.image) + +这是因为:in有两个条件,在满足深圳时,age是排好序的,但是把满足上海的age也加进来,就不能保证满足所有的age都是排好序的。因此需要Using filesort。 + +## 最后 + +- 如果觉得有收获,帮忙点赞,转发下哈,感谢感谢 +- 微信搜索公众号:**捡田螺的小男孩**,加个好友,进技术交流群 + + +### 参考与感谢 + +- MySQL实战45讲 + + + diff --git a/README.md b/README.md index 6018cc3..7018310 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,46 @@ -整理一份超级详细的Java面试题+后端基础+日常工作总结,做最暖心的男孩子,后面会慢慢把答案完善,希望大家找到理想offer +## 前言 -## 个人公众号 +整理一份超级详细的Java面试题+后端基础+日常工作总结,做最暖心的男孩子,后面会慢慢完善,希望大家找到理想offer + +⭐ 点右上角给一个 Star,鼓励技术人输出更多干货,感谢感谢,爱了! ! + +作者捡田螺的小男孩,浪迹过几家大厂,**掘金优秀创作者**,CSDN博主,知乎博主。以下内容全部出自公众号:**捡田螺的小男孩**,欢迎关注。 + +- [田螺原创精品100篇](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497536&idx=1&sn=3ac9934f607d79e51457fd01f4c8a4ef&chksm=cf222869f855a17fc30c744e5b7ccdeca407f3b7ddcca46bae1c93b1436ffc6fe417ccb8aef4&token=1990771297&lang=zh_CN#rd) + +## 工作总结 -![image](https://user-gold-cdn.xitu.io/2019/7/28/16c381c89b127bbb?w=344&h=344&f=jpeg&s=8943) +- [盘点数据库主从延迟的9个原因以及解决方案](https://mp.weixin.qq.com/s/aT7YjsTrM_dhDbddr8TSjg?token=528541177&lang=zh_CN) +- [实战项目,是如何保证缓存跟数据库数据一致性的?](https://mp.weixin.qq.com/s/UVHMeFDO4NYTnSwHZc9f1A?token=528541177&lang=zh_CN) +- [工作总结!日志打印的15个建议](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247494838&idx=1&sn=cdb15fd346bddf3f8c1c99f0efbd67d8&chksm=cf22339ff855ba891616c79d4f4855e228e34a9fb45088d7acbe421ad511b8d090a90f5b019f&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [25种代码坏味道总结+优化示例](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490148&idx=1&sn=00a181bf74313f751b3ea15ebc303545&chksm=cf21c54df8564c5bc5b4600fce46619f175f7ae557956f449629c470a08e20580feef4ea8d53&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [聊聊日常开发中,如何减少bug呢?](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490662&idx=1&sn=d38a090611af7f64ee3c6a31331d5228&chksm=cf21c34ff8564a59e505e6edf3065a0fc506c6d2c96f492c8d8873cd46dedbe0704e43cb9c2e&token=1990771297&lang=zh_CN#rd) +- [工作四年,分享50个让你代码更好的小建议](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488708&idx=1&sn=6e2e0a740f5d42a59641487a0bf1e3bf&chksm=cf21cbedf85642fbb485fa1c7bf9af21923d8503f2542b6f8283ce79ddc683f7d9e45da83100&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [写代码有这16个好习惯,可以减少80%非业务的bug](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488097&idx=1&sn=eaca1f92ca3ccd9de00dbc4ef3e4029a&chksm=cf21cd48f856445e4cc24c1f8bcf18d1479bad0a37a87a2fb70717d8a4e65dcf7b4d5f83d24f&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java日常开发的21个坑,你踩过几个?](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488115&idx=1&sn=bdd4a4ca36bc7ea902106d058e8537fb&chksm=cf21cd5af856444cb36af600705615454b0aaa2b289b97ddb52d594556ac07a1915b73ecce19&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [CAS乐观锁解决并发问题的一次实践](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487937&idx=1&sn=206a37bf6d6a7aa1d05674c479ed7a72&chksm=cf21cee8f85647fe7a082049a41c0f640f54976d2cdf4302b24c5517ca42b854eb84b13ece10&token=1990771297&lang=zh_CN#rd) +- [写代码有这些想法,同事才不会认为你是复制粘贴程序员](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487961&idx=1&sn=e646231067968d9f58e6665914293f9a&chksm=cf21cef0f85647e6f3ff2feece004ac3bd979e37fe45103c88d0f299dfe632a5cf6dd547c1d9&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [程序员必备:Java日期处理的十个坑](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487973&idx=1&sn=0f713413098fb579e5f200b829f71e89&chksm=cf21ceccf85647da450765d79bf5943da551c3be950447063b9f8c77c21bf2a39b99387a949b&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [内存泄漏问题的分析和解决方案](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487986&idx=1&sn=d681a585ac489703788e3baa48eb9aa3&chksm=cf21cedbf85647cd23bbab9dfec63e6877f83c34efb19bd16075d5d90fea91d3f4a20fc77921&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [程序员必备基础:加签验签](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488022&idx=1&sn=70484a48173d36006c8db1dfb74ab64d&chksm=cf21cd3ff8564429a1205f6c1d78757faae543111c8461d16c71aaee092fe3e0fed870cc5e0e&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [记一次接口性能优化实践总结:优化接口性能的八个建议](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488004&idx=1&sn=00840efd9c0bd0a7f172b59eb2ca130f&chksm=cf21cd2df856443bf21d8e09cfe5c8452ecaf82e3c2210fca3b28829ded04defddcf63c0a59b&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [程序员必备基础:如何安全传输存储用户密码?](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488117&idx=1&sn=5d3d0eda0ed45f3f576e211de31ca3a9&chksm=cf21cd5cf856444af1407a94a2abf445265ca7c5f5855cfa1c223cb209e99040c7889621f231&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [一次代码优化实践,用了模板方法+策略+工厂方法模式](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488061&idx=1&sn=1d9ab7954b03521ab81ecf033c0e5e50&chksm=cf21cd14f8564402b213f0ef908bbdb0e12fed4b281c5803b8e539cacb1551654194becfb7d6&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [保证接口数据安全的10种方案](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247500285&idx=1&sn=7d0723f25d46e858859cfd79acb6fb9d&chksm=cf221ed4f85597c2093f81baa5fdedc65817bf2d23a7951236836b0f54c2335695cbed61cd13&token=1990771297&lang=zh_CN#rd) +- [实战总结!18种接口优化方案的总结](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247506674&idx=1&sn=8b2914d9aafa334029495b029b69d0b6&chksm=c1e0277ef697ae68e8c2bffe4bd7d9849be3165ef1a20286538f6a7569a6ba0879d517d55b87&token=337310304&lang=zh_CN#rd) +- [聊聊工作中常用的Lambda表达式](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247506654&idx=1&sn=4835e9f486e643765d4ad3b3fc93e079&chksm=c1e02752f697ae442f62fc122d7604f4b01979f6d1665df414bb499fd8ba211335ebc503c368&token=337310304&lang=zh_CN#rd) +- [21个MySQL表设计的经验准则](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247506621&idx=1&sn=afca898cb461827054d706a92f9b9250&chksm=c1e02731f697ae27a83e5637ee2184d1e26e5090caeaa58121d3cf5afab7d4d5832cac6d171a&token=337310304&lang=zh_CN#rd) +- [程序员必备基础:如何安全传输存储用户密码?](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247506023&idx=1&sn=b96dde436c1c9fe4bda745ca5ca1b170&source=41#wechat_redirect) + +## 福利 500+页原创面试题 + +- [田螺原创500+页面试题](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499943&idx=1&sn=fe869c0a97a306e42830336fe74e17a6&chksm=cf221f8ef8559698781709bfbccbb85087286e48434905fb18bec3a3ec0af7329c2a1632c230&token=1990771297&lang=zh_CN#rd) + + +## 个人公众号 -- 如果你是个爱学习的好孩子,可以关注我公众号,一起学习讨论哈~~ +微信搜公众号:**捡田螺的小男孩** -## 一分也是爱,谢谢大家的支持哈~ -![](https://user-gold-cdn.xitu.io/2020/7/15/1735311bf66cecd8?w=430&h=580&f=jpeg&s=35456) +- 小伙伴可以关注我的公众号(扫描下面二维码,还有**很多很多干货文章**),一起学习讨论哈~~ +![扫一扫](https://user-images.githubusercontent.com/20244922/179399354-8a9fd2a8-42ba-4303-9ce5-04891e899e6d.png) diff --git "a/letecode\350\247\243\351\242\230\347\256\227\346\263\225\344\273\213\347\273\215/README.MD" "b/letecode\350\247\243\351\242\230\347\256\227\346\263\225\344\273\213\347\273\215/README.MD" new file mode 100644 index 0000000..921f58b --- /dev/null +++ "b/letecode\350\247\243\351\242\230\347\256\227\346\263\225\344\273\213\347\273\215/README.MD" @@ -0,0 +1,13 @@ +## leetcode(持续更新中) + +关注公众号:捡田螺的小男孩 + +- [看一遍就理解:动态规划详解](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247489016&idx=1&sn=bba3fb1a7a864b6ccefeb9f633751811&chksm=cf21cad1f85643c716c8c9396d3a6711f7722f8f81c8f40f5a91c525c98f73f5c476b7d49dd4&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [程序员必备的基本算法:递归详解](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488073&idx=1&sn=ec81b4a1f8b11ea59264b55e571fed91&chksm=cf21cd60f8564476952c5abb8ffa93fc38fde354a61ca5596e1875d35760383f3a92b2879e30&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [看一遍就理解,图解单链表反转](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487967&idx=1&sn=e75373dcb0507081c242ba018b42ca82&chksm=cf21cef6f85647e0cbf0b2072eb1264a44abcaa9f4a0621ef8954a1b1d6719560f7f4cbbce60&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [面试必备:回溯算法详解](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497665&idx=1&sn=39011296fa99eda839ab2bbe83a42cdf&chksm=cf2228e8f855a1fe8f059130dc0b3d9ad34431a27bbe7e16f508b7e9340c24e2e4dfd8b414c2&token=1990771297&lang=zh_CN#rd) +- [leetcode必备算法:聊聊滑动窗口](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247496003&idx=1&sn=8c40eb3e611514f3bafb8d6873c03fda&chksm=cf222e6af855a77ce2fc36d4e4fc02945286300206f43975e30bc23b65c9ca67b6a1ac9806d1&token=1990771297&lang=zh_CN#rd) +- [五分钟搞定贪心算法,从此不惧大厂面试](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490681&idx=1&sn=0388da1492fe0fdfa3ed6b1a43511328&chksm=cf21c350f8564a466d89578f73886eb462c6dd485f42e7953f126be5f9af49b3fb0be3457d52&token=1990771297&lang=zh_CN#rd) +- [双指针+归并排序!图解排序链表!](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247496038&idx=1&sn=96a1a665e43ee9e3337e3d941db49f1e&chksm=cf222e4ff855a75919f0be68e78472199c44d0e9d94de6d5bf621a892ba211738d6f4dbd53ac&token=1990771297&lang=zh_CN#rd) +- [双指针技巧](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488116&idx=1&sn=aeec0553e2317bef76d158d2b0e0b5a5&chksm=cf21cd5df856444b8963efc2745bce6801df4bc547b679ae8366fa8c3cd293f1f7c60c18e4f6&token=1990771297&lang=zh_CN#rd) +- [字符串匹配算法详解](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247494506&idx=1&sn=1f13b0cc1f03af464e1063be8ef1cb57&chksm=cf223443f855bd5597898126d12c6039f64da47b8a95714018203ee5e453950c802ebecfabe1&token=1990771297&lang=zh_CN#rd) diff --git "a/\344\270\255\351\227\264\344\273\266/README.MD" "b/\344\270\255\351\227\264\344\273\266/README.MD" new file mode 100644 index 0000000..74d80b2 --- /dev/null +++ "b/\344\270\255\351\227\264\344\273\266/README.MD" @@ -0,0 +1,8 @@ +## 中间件 + +- [一文快速入门分库分表中间件 Sharding-JDBC (必修课)](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499781&idx=1&sn=74bbb25c9347408f1edf7f8c9c82d7cf&chksm=cf221f2cf855963a6549069deeabe93bb6d6e889bcd086668bf6f0e23327fa1ddb31adc6d10c&token=1990771297&lang=zh_CN#rd) +- [全方位对比Zookeeper、Eureka、Nacos、Consul和Etcd](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498268&idx=1&sn=7b24b8625fb4ff88d50c9bd55335f478&chksm=cf222535f855ac230dfca629127f93efec606641d7338c29a8d41e7d2016a7f0b6ec28a432a0&token=1990771297&lang=zh_CN#rd) +- [消息队列经典十连问](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497847&idx=1&sn=29a32672b712e7dfadfa36c9902b2ec7&chksm=cf22275ef855ae484fb3f51a5726e9a4bc45222e8fbbd33631d177dc4b5619c36889ea178463&token=1990771297&lang=zh_CN#rd) +- [Kafka性能篇:为何Kafka这么"快"?](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488717&idx=1&sn=006c65f9a9a5796961c42f3cafc37cb4&chksm=cf21cbe4f85642f2e8ff948f8de8a69508783cee6dafd22512d6a06cd03f7065001bd1d8d87b&token=1990771297&lang=zh_CN#rd) +- [后端程序员必备:RocketMQ相关流程图/原理图](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487949&idx=1&sn=888e0917884b2918a94053e5cd560e00&chksm=cf21cee4f85647f24877791d574f5ef3f979fc9c4c84ca3fd1ea1aa08ab30c1041ad3aaa5650&token=1990771297&lang=zh_CN#rd) +- [ZooKeeper的十二连问,你顶得了嘛?](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488047&idx=1&sn=4913c7e1c3b8835f7512d8dc6b845727&chksm=cf21cd06f8564410cce6121230256facb1ab3b5a9ed35579896f428d84bdea7b86836109d575&token=162724582&lang=zh_CN&scene=21#wechat_redirect) \ No newline at end of file diff --git "a/\345\210\206\345\270\203\345\274\217/README.MD" "b/\345\210\206\345\270\203\345\274\217/README.MD" new file mode 100644 index 0000000..1b5f507 --- /dev/null +++ "b/\345\210\206\345\270\203\345\274\217/README.MD" @@ -0,0 +1,12 @@ +## 分布式 + +关注公众号:捡田螺的小男孩 + +- [面试必备:聊聊分布式锁的多种实现!](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498595&idx=1&sn=4e5308930e151a609baa2df820e48a89&chksm=cf22244af855ad5c71822cb33e828ce652c6f34202096a9344922b86dcbc08076d7922acde5f&token=1990771297&lang=zh_CN#rd) +- [我们为什么要分库分表?](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498625&idx=1&sn=0d7bd9d1b46eeff4c715a6761355e9b0&chksm=cf2224a8f855adbea8931c8e011711f6c70cffeef8ddf8b87729c710eacef11b46eef80fda36&token=1990771297&lang=zh_CN#rd) +- [聊聊高可用的 11 个关键技巧](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498784&idx=1&sn=aad1c00d6eafb0c1f08959612c69959a&chksm=cf222309f855aa1f71ef9cf470bfa72ac73365c401ec7c7d0c3b241a9116c3112f83760793e8&token=1990771297&lang=zh_CN#rd) +- [看一遍就理解:分布式事务详解](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498358&idx=1&sn=aa6c7ceb61b73267d68d1b4fb7ccc2ed&chksm=cf22255ff855ac495861d57df276517e89779006267fa8413fe925cc15b0c3e0b0f1b1a5675e&token=1990771297&lang=zh_CN#rd) +- [几种主流的分布式定时任务,你知道哪些?](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498121&idx=1&sn=e3d7e4f5297c7b2390b412a9bafc3385&chksm=cf2226a0f855afb669cde8d7f400fb334bd4c75a8c672d1208667387d03d2dfd24884e60b825&token=1990771297&lang=zh_CN#rd) +- [redis分布式锁的8大坑,记得拿小本本记下来啦](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247495390&idx=1&sn=87cc1567c709cfa67b43dd8d273bb426&chksm=cf2231f7f855b8e17919f7763469d87c47d9b4c4ad25aba7e6ff60fa33b048bc47a4afd287fc&token=1990771297&lang=zh_CN#rd) +- [框架篇:分布式一致性解决方案](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490468&idx=2&sn=91b8e5dd2ce3db218708b5c736fce700&chksm=cf21c48df8564d9b30164e1dbf9b5ebcc1847a9450d08ee146c98eb53107af475149ad12a748&token=1990771297&lang=zh_CN#rd) +- [这三年被分布式坑惨了,曝光十大坑](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488553&idx=2&sn=fa13e9698e59f5a5485d3d3d4b8ef2b1&chksm=cf21cb00f8564216277806780c64e13c48fe32009f588349b3365afa8de97bd8ef192507bd50&token=1990771297&lang=zh_CN#rd) \ No newline at end of file diff --git "a/\345\210\267leetcode\345\277\205\345\244\207\347\256\227\346\263\225/\347\234\213\344\270\200\351\201\215\345\260\261\347\220\206\350\247\243\357\274\232\345\212\250\346\200\201\350\247\204\345\210\222\350\257\246\350\247\243.md" "b/\345\210\267leetcode\345\277\205\345\244\207\347\256\227\346\263\225/\347\234\213\344\270\200\351\201\215\345\260\261\347\220\206\350\247\243\357\274\232\345\212\250\346\200\201\350\247\204\345\210\222\350\257\246\350\247\243.md" deleted file mode 100644 index e8cc9b4..0000000 --- "a/\345\210\267leetcode\345\277\205\345\244\207\347\256\227\346\263\225/\347\234\213\344\270\200\351\201\215\345\260\261\347\220\206\350\247\243\357\274\232\345\212\250\346\200\201\350\247\204\345\210\222\350\257\246\350\247\243.md" +++ /dev/null @@ -1,440 +0,0 @@ - -### ǰ - -ˢleetcodeʱ򣬾̬滮Ŀ̬滮dzdz䣬Ҳмԣһ󳧶dzϲʡһѧϰ̬滮·вȷĵطӭָлл~ - -- ʲôǶ̬滮 -- ̬滮ĺ˼ -- һ߽̬滮 -- ̬滮Ľ· -- leetcode - - -![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/01fdad6c74864d7da07193203c2dcbf4~tplv-k3u1fbpfcp-zoom-1.image) - - -ںţ**ݵСк** - -### ʲôǶ̬滮 - - -̬滮ӢDynamic programming DPһѧѧѧѧϢѧʹõģͨԭֽΪԼ򵥵ķʽ⸴ķ̬滮صӽṹʵ⡣ - -> dynamic programming is a method for solving a complex problem by breaking it down into a collection of simpler subproblems. - -϶άٿƣое󡣼˵̬滮ʵǣһ⣬ǰһ⣬ֱֱӽȻأ𰸱Լظ㡣ٸ𰸷ƣóԭһַ -> һЩƣͨϵʽƳȻأ̬滮ڽÿһΣظ,쳲оͿԿżľ䶯̬滮⡣ - - -### ̬滮˼ - -̬滮ĵ˼룬**⣬סظ** - -![̬滮ڼס](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d26f967ff6e447d291b0b196c4edaa07~tplv-k3u1fbpfcp-watermark.image) - -£ϱȽеһӣ -> - A "1+1+1+1+1+1+1+1 =" -> - A "ʽֵǶ" -> - B "8" -> - A : ʽд "1+" أ -> - A : "ʱʽֵΪ" -> - B : ܿó "9" -> - A : "ôô֪" -> - A : "ֻҪ8Ļϼ1" -> - A : "㲻¼㣬Ϊס˵һʽֵΪ8!̬滮㷨Ҳ˵ 'סĽʡʱ'" - -### һӴ߽̬滮 -- - -#### ݹ - -> leetcodeԭ⣺һֻһο1̨ףҲ2̨סһ 10 ̨ܹж - -ЩСһμʱ򣬿ܻеȦ֪ôʵ룺 -> - Ҫ10̨ףҪô9Ȼ1̨ȥ;Ҫô8Ȼһ2̨ȥ -> - ͬҪ9̨ףҪô8Ȼ1̨ȥ;Ҫô7Ȼһ2̨ȥ -> - Ҫ8̨ףҪô7Ȼ1̨ȥ;Ҫô6Ȼһ2̨ȥ - -n̨׵ǶΪf(n)ȻͿԵó¹ʽ - -``` -f10 = f9+f(8) -f (9) = f(8) + f(7) -f (8) = f(7) + f(6) -... -f(3) = f(2) + f(1) - -ͨùʽΪ: f(n) = f(n-1) + f(n-2) -``` - -f(2) f(1) ڶأ -- ֻ2̨ʱһֱڶһȻһf(2) = 2; -- ֻ1̨ʱֻһf1= 1 - - -˿õݹȥ⣺ -``` -class Solution { - public int numWays(int n) { - if(n == 1){ - return 1; - } - if(n == 2){ - return 2; - } - return numWays(n-1) + numWays(n-2); - } -} -``` - -ȥleetcodeύһ£⣬ʱ - -![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3e0608ec89a246568e01c7ba4b8f50d8~tplv-k3u1fbpfcp-zoom-1.image) - - -ΪʲôʱأݹʱأȻ**ݹ** - - -![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2dd95840552e4a7db9536884b7a9b558~tplv-k3u1fbpfcp-zoom-1.image) - -- Ҫԭ f(10)Ҫȼ f(9) f(8) -- ȻҪ f(9)Ҫ f(8) f(7)Դơ -- һֱ f(2) f(1ݹֹ - -ݹʱ临ӶȰɣ - - -``` -ݹʱ临Ӷ = һʱ* -``` - -- һʱ = fn-1+fn-2ҲһӷIJԸӶ O(1) -- = ݹڵݹܽڵ = 2^n-1ǸӶO(2^n) - -ˣףݹⷨʱ临Ӷ = O(1) * O(2^n) = O(2^n)ָģըģnȽϴĻʱˡ - -عͷϸ۲ŵݹִᷢڴظ㣬f8Σf7ظ3...ݹ㷨Чԭ򣬾**ڴظ** - -Ȼڴظ㣬ôǿȰѼõĴ𰸴һ¼ȵ´ҪĻȥ¼һ£Уֱȡͺˣ¼ûвſʼ㣬ǾͿʡȥظĺʱǴ¼Ľⷨ - - - -#### ¼ĵݹⷨԶ£ - -һʹһһϣmap䵱**¼** -- һf10= f(9) + f(8)f(9) f8ҪȻټӵ¼У£ - - - -![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/94484290462e45c799609b0a581b14b0~tplv-k3u1fbpfcp-zoom-1.image) - -- ڶ f(9) = f8+ f7f8= f7+ f(6), Ϊ f(8) Ѿڱ¼Կʡf(7),f6Ҫӵ¼~ - - -![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/12900b17d77f4adfbdb71920f729d61a~tplv-k3u1fbpfcp-zoom-1.image) - - - f(8) = f7+ f(6),f(8)f(7),f6ȫڱ¼ˣԶԼ - - -![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9a8c7ba6b5ae413799c6a33490bb1f8f~tplv-k3u1fbpfcp-zoom-1.image) - -أ˱¼ݹ㷨ݹɹͺͺɿ£ - -![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/18a78d6b99a84ff8a1df834f3c085014~tplv-k3u1fbpfcp-zoom-1.image) - -**¼**ĵݹ㷨=ڵ=nһ⻹O(1),Դ**¼**ĵݹ㷨ʱ临ӶO(n)أô**¼**ĵݹ㷨ȥߣ룬ijʱ⿩~£ - - - -``` -public class Solution { - //ʹùϣmap䵱¼ - Map tempMap = new HashMap(); - public int numWays(int n) { - // n = 0 Ҳ1 - if (n == 0) { - return 1; - } - if (n <= 2) { - return n; - } - //жû¼û - if (tempMap.containsKey(n)) { - //¼Уֱӷ - return tempMap.get(n); - } else { - // ¼ûУûмִеݹ,Ұѽ浽¼mapУ1000000007ȡࣨleetcodeĿ涨ģ - tempMap.put(n, (numWays(n - 1) + numWays(n - 2)) % 1000000007); - return tempMap.get(n); - } - } -} -``` -ȥleetcodeύһ£ͼˣ - -![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e5f0fb1998c542dc8cb3826de800f443~tplv-k3u1fbpfcp-zoom-1.image) - -ʵö̬滮⡣ - -#### ԵϵĶ̬滮 - -̬滮¼ĵݹⷨ˼һµģǼظ㣬ʱ临ӶҲDzࡣأ -- ¼ĵݹ飬Ǵf(10)f(1ģҲΪ**Զ**Ľⷨ -- ̬滮ӽСĽ⣬ɽʣ𲽾߳ϴĽ⣬Ǵf(1)f(10⣬ԳΪ**Ե**Ľⷨ - - -̬滮м**ӽṹ״̬תƷ̡߽硢ص**У -- f(n-1)f(n-2) Ϊ f(n) ӽṹ -- f(n)= fn-1+fn-2ͳΪ״̬תƷ -- f(1) = 1, f(2) = 2 DZ߽ -- f(10)= f(9)+f(8),f(9) = f(8) + f(7) ,f(8)ص⡣ - -ԵϵĽⷨf(1)f(10DzֱһforѭͿԽ£ - -![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8e21b14d47e64afa958506d49972827b~tplv-k3u1fbpfcp-zoom-1.image) - -¼ĵݹⷨռ临ӶO(n)أϸ۲ͼԷ֣fnֻǰֻҪab洢Ϳˣ˿ռ临ӶO(1)Ϳ - -![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8b202b2364eb4aae9122cfa8474c045e~tplv-k3u1fbpfcp-zoom-1.image) - -̬滮ʵִ£ - -``` -public class Solution { - public int numWays(int n) { - if (n<= 1) { - return 1; - } - if (n == 2) { - return 2; - } - int a = 1; - int b = 2; - int temp = 0; - for (int i = 3; i <= n; i++) { - temp = (a + b)% 1000000007; - a = b; - b = temp; - } - return temp; - } - } -``` - -### ̬滮Ľ· - -#### ʲôԿʹö̬滮أ - -> һ⣬԰пܵĴٳٳ󣬷ִص⣬ͿԿʹö̬滮 - -һЩֵij**СС༭롢⡢Ǯ**ȵȣǶ̬滮ľӦó - - -### ̬滮Ľ˼· - - -̬滮ĺ˼**⣬סظ㡣** Ҷ̬滮һ㶼Եϵģ˵****⣬ܽһ̬滮˼· - -- ٷ -- ȷ߽ -- ҳɣȷӽṹ -- д״̬תƷ - - -#### 1. ٷ - - -- ̨1ʱһf1 =1 -- ֻ2̨ʱһֱڶһȻһf(2) = 2; -- ̨3ʱ3̨ףҪô2Ȼ1̨ȥҪô 1Ȼһ 2 ̨ȥf(3) = f(2) + f(1) =3 -- ̨4ʱ3̨ףҪô3Ȼ1̨ȥҪô 2Ȼһ 2 ̨ȥf(4) = f(3) + f(2) =5 -- ̨5ʱ...... - -![ԵϵĶ̬滮](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/29cd6d0d31514336baf9905f8084a624~tplv-k3u1fbpfcp-zoom-1.image) - - - -#### 2. ȷ߽ - -ͨٷǷ̨֣1ʱ2ʱ򣬿ȷ֪f1 =1f(2) = 2̨n>=3ʱѾֳf(3) = f(2) + f(1) =3f1 =1f(2) = 2׵ı߽硣 - - -#### 3. ҹɣȷӽṹ - -n>=3ʱѾֳ f(n) = f(n-1) + f(n-2) ˣf(n-1)f(n-2) Ϊ f(n) ӽṹʲôӽṹôһͣ - -> һ̬滮⣬ʵһ⡣赱ǰ߽f(n),ӽṹҪ f(n-k) ,ӽṹʾתƵn״̬ŵ,ľûйϵ,úľ߰ĵʹǰľֲŽһ - - -#### 4 д״̬תƷ - -ͨǰ3ٷȷ߽磬ӽṹǾͿԵó״̬תƷ - -![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4fb4cd7257ff4fcbac9d87be96f353bd~tplv-k3u1fbpfcp-zoom-1.image) - -#### 5. ʵ - -ʵִʱһעӵϱȻע±߽ռ临ӶȣҲͲ̬滮иܵģʵֵʱ򣬿Կʵοһ£ - - -``` -dp[0][0][...] = ֵ߽ -for(״̬1 ״̬1ֵ){ - for(״̬2 ״̬2ֵ){ - for(...){ - //״̬תƷ - dp[״̬1][״̬2][...] = ֵ - } - } -} -``` - - -### leetcode - -һһleetcodeĿ - -> һ nums ҵϸеijȡ - -ʾ 1 - -``` -룺nums = [10,9,2,5,3,7,101,18] -4 -ͣ [2,3,7,101]˳Ϊ 4 -``` - -ʾ 2 - - -``` -룺nums = [0,1,0,3,2,3] -4 -``` - -ǰ϶̬滮Ľ˼· - -- ٷ -- ȷ߽ -- ҹɣȷӽṹ -- ״̬תƷ - - -#### 1.ٷ - - -Ϊ̬滮˼**⣬סظ㡣** ˼ԭ⣺**num[i]гʱ**˼****ԭǷ****num[i-1]гйأ - -##### Զϵ - -۲ɣȻйϵģǻѭ̬滮**Ե**ԭ򣬻ʾ1ݣֻһԪؿʼ - -- numsֻһԪ10ʱ[10],1. -- numsҪһԪ9ʱ[10][9],1 -- numsټһԪ2ʱ[10][9][2],1 -- numsټһԪ5ʱ[2,5],2 -- numsټһԪ3ʱ[2,5][2,3],2 -- numsټһԪ7ʱ,[2,5,7][2,3,7],3 -- numsټһԪ101ʱ[2,5,7,101][2,3,7,101],4 -- numsټһԪ18ʱ[2,5,7,101][2,3,7,101][2,5,7,18][2,3,7,18],4 -- numsټһԪ7ʱ,[2,5,7,101][2,3,7,101][2,5,7,18][2,3,7,18],4. - -##### ҹɣ -ͨǿ**һ** - -¼һԪnums[i], Ҫô**nums[i]βĵ**Ҫô**nums[i-1]**DzǺܿģnums[i]Ѿ**** nums[i-1]йˡ - -``` -ԭnums[i] = nums[i-1]/nums[i]β -``` - -DzǸоɹһأ**ΰnums[i]βĵҲתΪӦ**أҪnums[i]βĵҲnums[i-1]йؾͺˡֻnums[i]βУǰnum[j]0= - nums[3]=5,```5```βо```[2,5]```,Ϊ±```03```ֻҵ```[2]``````5```СԾ```[2]+[5]``````dp[4]=2``` -> - nums[4]=3,```3```βо```[2,3]```,Ϊ±```04```ֻҵ```[2]``````3```СԾ```[2]+[3]``````dp[4]=2``` -> - nums[5]=7```7```βо```[2,5,7]``````[2,3,7]```,Ϊ±```05```ҵ```2,53```7СԾ```[2,7],[5,7],[3,7],[2,5,7][2,3,7]```ЩУо```[2,5,7][2,3,7]``````5```β```3```β+[7]ԣ**```dp[5]=3 =dp[3]+1=dp[4]+1```** - - -Ȼɣһnums[i]βnums -- j[0i-1],num[i]>num[j]ĻУdp(i) =max(dp(j))+1 - -#### 򵥵ı߽ - -numsֻһԪʱеijdp(1)=1,numsԪʱdp(2) =21 -˱߽dp(1)=1 - -#### ȷӽṹ - -ٷǿԵóµŽṹ - -``` -dp(i) =max(dp(j))+1j[0i-1],num[i]>num[j] -``` -**max(dp(j))** ӽṹ - -#### ״̬תƷ - -ͨǰǾͿԵó״̬תƷ - -![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/457ce281c1ec4e91b8c868aa593e41b6~tplv-k3u1fbpfcp-zoom-1.image) - -num[i]оǣ -``` - =max(dp[i]) -``` - - - - -#### ʵ - -``` -class Solution { - public int lengthOfLIS(int[] nums) { - if (nums.length == 0) { - return 0; - } - int[] dp = new int[nums.length]; - //ʼDZ߽ - dp[0] = 1; - int maxans = 1; - //Եϱ - for (int i = 1; i < nums.length; i++) { - dp[i] = 1; - //±0i - for (int j = 0; j < i; j++) { - //ҵǰnums[i]Сnums[j],dp[i]= dp[j]+1 - if (nums[j] < nums[i]) { - //ΪжСnums[i]ҲǻڶǾȡŵdp[i] - dp[i] = Math.max(dp[i], dp[j] + 1); - } - } - //dp[i]dpǸnums - maxans = Math.max(maxans, dp[i]); - } - return maxans; - } -} -``` - - - - - - - - - - - - - diff --git "a/\345\210\267leetcode\345\277\205\345\244\207\347\256\227\346\263\225/\351\200\222\345\275\222\350\257\246\350\247\243.md" "b/\345\210\267leetcode\345\277\205\345\244\207\347\256\227\346\263\225/\351\200\222\345\275\222\350\257\246\350\247\243.md" deleted file mode 100644 index fb5ecdb..0000000 --- "a/\345\210\267leetcode\345\277\205\345\244\207\347\256\227\346\263\225/\351\200\222\345\275\222\350\257\246\350\247\243.md" +++ /dev/null @@ -1,380 +0,0 @@ -### 前言 -递归是一种非常重要的算法思想,无论你是前端开发,还是后端开发,都需要掌握它。在日常工作中,统计文件夹大小,解析xml文件等等,都需要用到递归算法。它太基础太重要了,这也是为什么面试的时候,面试官经常让我们手写递归算法。本文呢,将跟大家一起学习递归算法~ - -- 什么是递归? -- 递归的特点 -- 递归与栈的关系 -- 递归应用场景 -- 递归解题思路 -- leetcode案例分析 -- 递归可能存在的问题以及解决方案 - - -**公众号:捡田螺的小男孩** - -### 什么是递归? - -递归,在计算机科学中是指一种通过重复将问题分解为同类的子问题而解决问题的方法。简单来说,递归表现为函数调用函数本身。在知乎看到一个比喻递归的例子,个人觉得非常形象,大家看一下: - -> 递归最恰当的比喻,就是查词典。我们使用的词典,本身就是递归,为了解释一个词,需要使用更多的词。当你查一个词,发现这个词的解释中某个词仍然不懂,于是你开始查这第二个词,可惜,第二个词里仍然有不懂的词,于是查第三个词,这样查下去,直到有一个词的解释是你完全能看懂的,那么递归走到了尽头,然后你开始后退,逐个明白之前查过的每一个词,最终,你明白了最开始那个词的意思。 - -来试试水,看一个递归的代码例子吧,如下: -``` -public int sum(int n) { - if (n <= 1) { - return 1; - } - return sum(n - 1) + n; -} -``` - -### 递归的特点 - -实际上,递归有两个显著的特征,终止条件和自身调用: -- 自身调用:原问题可以分解为子问题,子问题和原问题的求解方法是一致的,即都是调用自身的同一个函数。 -- 终止条件:递归必须有一个终止的条件,即不能无限循环地调用本身。 - -结合以上demo代码例子,看下递归的特点: - -![](https://imgkr2.cn-bj.ufileos.com/94f250ad-41ea-4760-ae79-060f91605aeb.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=gQGMVnPTDwM%252F5AX2OrH%252F0ugG9MA%253D&Expires=1602691176) - - -### 递归与栈的关系 -其实,递归的过程,可以理解为出入栈的过程的,这个比喻呢,只是为了方便读者朋友更好理解递归哈。以上代码例子计算sum(n=3)的出入栈图如下: -![](https://imgkr2.cn-bj.ufileos.com/d4f09883-727b-44b6-90e0-dfad9d768b8c.jpg?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=V%252BDCQxqTa24HsCxQcooMJ%252FzuOHc%253D&Expires=1602692111) - - -为了更容易理解一些,我们来看一下 函数sum(n=5)的递归执行过程,如下: -![](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f587c37fea484be192fec7710634ec47~tplv-k3u1fbpfcp-zoom-1.image) - -- 计算sum(5)时,先sum(5)入栈,然后原问题sum(5)拆分为子问题sum(4),再入栈,直到终止条件sum(n=1)=1,就开始出栈。 -- sum(1)出栈后,sum(2)开始出栈,接着sum(3)。 -- 最后呢,sum(1)就是后进先出,sum(5)是先进后出,因此递归过程可以理解为栈出入过程啦~ - - -### 递归的经典应用场景 -哪些问题我们可以考虑使用递归来解决呢?即递归的应用场景一般有哪些呢? -- 阶乘问题 -- 二叉树深度 -- 汉诺塔问题 -- 斐波那契数列 -- 快速排序、归并排序(分治算法也使用递归实现) -- 遍历文件,解析xml文件 - -### 递归解题思路 -解决递归问题一般就三步曲,分别是: -- 第一步,定义函数功能 -- 第二步,寻找递归终止条件 -- 第二步,递推函数的等价关系式 - -这个递归解题三板斧理解起来有点抽象,我们拿阶乘递归例子来喵喵吧~ - -#### 1.定义函数功能 -定义函数功能,就是说,你这个函数是干嘛的,做什么事情,换句话说,你要知道递归原问题是什么呀?比如你需要解决阶乘问题,定义的函数功能就是n的阶乘,如下: -``` -//n的阶乘(n为大于0的自然数) -int factorial (int n){ - -} -``` - -#### 2.寻找递归终止条件 -递归的一个典型特征就是必须有一个终止的条件,即不能无限循环地调用本身。所以,用递归思路去解决问题的时候,就需要寻找递归终止条件是什么。比如阶乘问题,当n=1的时候,不用再往下递归了,可以跳出循环啦,n=1就可以作为递归的终止条件,如下: -``` -//n的阶乘(n为大于0的自然数) -int factorial (int n){ - if(n==1){ - return 1; - } -} -``` - -#### 3.递推函数的等价关系式 -递归的**本义**,就是原问题可以拆为同类且更容易解决的子问题,即**原问题和子问题都可以用同一个函数关系表示。递推函数的等价关系式,这个步骤就等价于寻找原问题与子问题的关系,如何用一个公式把这个函数表达清楚**。阶乘的公式就可以表示为 f(n) = n * f(n-1), 因此,阶乘的递归程序代码就可以写成这样,如下: -``` -int factorial (int n){ - if(n==1){ - return 1; - } - return n * factorial(n-1); -} -``` -**注意啦**,不是所有递推函数的等价关系都像阶乘这么简单,一下子就能推导出来。需要我们多接触,多积累,多思考,多练习递归题目滴~ - -### leetcode案例分析 - -来分析一道leetcode递归的经典题目吧~ -> 原题链接在这里哈:https://leetcode-cn.com/problems/invert-binary-tree/ - -**题目:** 翻转一棵二叉树。 - -输入: -``` - 4 - / \ - 2 7 - / \ / \ -1 3 6 9 -``` -输出: -``` - 4 - / \ - 7 2 - / \ / \ -9 6 3 1 -``` - -我们按照以上递归解题的三板斧来: - -**1. 定义函数功能** - -函数功能(即这个递归原问题是),给出一颗树,然后翻转它,所以,函数可以定义为: -``` -//翻转一颗二叉树 -public TreeNode invertTree(TreeNode root) { -} - -/** - * Definition for a binary tree node. - * public class TreeNode { - * int val; - * TreeNode left; - * TreeNode right; - * TreeNode(int x) { val = x; } - * } - */ -``` - -**2.寻找递归终止条件** - -这棵树什么时候不用翻转呢?当然是当前节点为null或者当前节点为叶子节点的时候啦。因此,加上终止条件就是: -``` -//翻转一颗二叉树 -public TreeNode invertTree(TreeNode root) { - if(root==null || (root.left ==null && root.right ==null)){ - return root; - } -} -``` - -**3. 递推函数的等价关系式** - -原问题之你要翻转一颗树,是不是可以拆分为子问题,分别翻转它的左子树和右子树?子问题之翻转它的左子树,是不是又可以拆分为,翻转它左子树的左子树以及它左子树的右子树?然后一直翻转到叶子节点为止。嗯,看图理解一下咯~ -![](https://imgkr2.cn-bj.ufileos.com/938b0fcf-7ab2-4c8f-833f-382be7f8b46d.jpg?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=9BiTdqNsNnz%252FqynFWb52CMQkMnU%253D&Expires=1602692880) - - -首先,你要翻转根节点为4的树,就需要**翻转它的左子树(根节点为2)和右子树(根节点为7)**。这就是递归的**递**的过程啦 -![](https://imgkr2.cn-bj.ufileos.com/381538fe-fe34-4cae-9d1e-b5894ea542b2.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=HK51fa4jYvucnu6r3829BqFWcys%253D&Expires=1602693025) - - -然后呢,根节点为2的树,不是叶子节点,你需要继续**翻转它的左子树(根节点为1)和右子树(根节点为3)**。因为节点1和3都是**叶子节点**了,所以就返回啦。这也是递归的**递**的过程~ - -![](https://imgkr2.cn-bj.ufileos.com/c9195723-d803-4b76-9cb3-bec8192a696f.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=n5Ct31iSBnMmK2HJ7kB0I6ZhEYs%253D&Expires=1602693145) - -同理,根节点为7的树,也不是叶子节点,你需要翻转**它的左子树(根节点为6)和右子树(根节点为9)**。因为节点6和9都是叶子节点了,所以也返回啦。 - -![](https://imgkr2.cn-bj.ufileos.com/63333c60-747b-45d3-a8eb-dacf0cf36231.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=8NTb2Fj1PBlwVIxwe1InO5YqoWg%253D&Expires=1602693197) - - - -左子树(根节点为2)和右子树(根节点为7)都被翻转完后,这几个步骤就**归来**,即递归的归过程,翻转树的任务就完成了~ - -![](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/afada1b801734cdc899e896b0816b63f~tplv-k3u1fbpfcp-watermark.webp) - -显然,**递推关系式**就是: -``` -invertTree(root)= invertTree(root.left) + invertTree(root.right); -``` - -于是,很容易可以得出以下代码: -``` -//翻转一颗二叉树 -public TreeNode invertTree(TreeNode root) { - if(root==null || (root.left ==null && root.right ==null){ - return root; - } - //翻转左子树 - TreeNode left = invertTree(root.left); - //翻转右子树 - TreeNode right= invertTree(root.right); -} -``` -这里代码有个地方需要注意,就是翻转完一棵树的左右子树后,需要交换它左右子树的引用位置。 -``` - root.left = right; - root.right = left; -``` - -因此,leetcode这个递归经典题目的**终极解决代码**如下: -``` -class Solution { - public TreeNode invertTree(TreeNode root) { - if(root==null || (root.left ==null && root.right ==null)){ - return root; - } - //翻转左子树 - TreeNode left = invertTree(root.left); - //翻转右子树 - TreeNode right= invertTree(root.right); - //左右子树交换位置~ - root.left = right; - root.right = left; - return root; - } -} -``` -拿终极解决代码去leetcode提交一下,通过啦~ - - -![](https://imgkr2.cn-bj.ufileos.com/3c9bc7ba-1677-4b8b-a389-e7177fd2b747.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=oNJFxSVWmku%252FMg%252BKlGHop%252BQ%252BxIw%253D&Expires=1602693611) - - -### 递归存在的问题 -- 递归调用层级太多,导致栈溢出问题 -- 递归重复计算,导致效率低下 - -#### 栈溢出问题 -- 每一次函数调用在内存栈中分配空间,而每个进程的栈容量是有限的。 -- 当递归调用的层级太多时,就会超出栈的容量,从而导致调用栈溢出。 -- 其实,我们在前面小节也讨论了,递归过程类似于出栈入栈,如果递归次数过多,栈的深度就需要越深,最后栈容量真的不够咯 - -**代码例子如下:** -``` -/** - * 递归栈溢出测试 - */ -public class RecursionTest { - - public static void main(String[] args) { - sum(50000); - } - private static int sum(int n) { - if (n <= 1) { - return 1; - } - return sum(n - 1) + n; - } -} -``` -**运行结果:** -``` -Exception in thread "main" java.lang.StackOverflowError - at recursion.RecursionTest.sum(RecursionTest.java:13) -``` - -怎么解决这个栈溢出问题?首先需要**优化一下你的递归**,真的需要递归调用这么多次嘛?如果真的需要,先稍微**调大JVM的栈空间内存**,如果还是不行,那就需要弃用递归,**优化为其他方案**咯~ - -#### 重复计算,导致程序效率低下 -我们再来看一道经典的青蛙跳阶问题:一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。 - -绝大多数读者朋友,很容易就想到以下递归代码去解决: -``` -class Solution { - public int numWays(int n) { - if (n == 0){ - return 1; - } - if(n <= 2){ - return n; - } - return numWays(n-1) + numWays(n-2); - } -} -``` - -但是呢,去leetcode提交一下,就有问题啦,超出时间限制了 - - -![](https://imgkr2.cn-bj.ufileos.com/47049001-7fae-4c98-8f4c-2e55aca367f3.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=xELiHeOso7vAsXwthfHEIDarVGs%253D&Expires=1602693967) - - -为什么超时了呢?递归耗时在哪里呢?先画出**递归树**看看: - -![](https://imgkr2.cn-bj.ufileos.com/9539296a-f5b1-433e-94ba-2e23eddfc409.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=Rzlo2ChPE7UEkCSJhbMNTBbtfaA%253D&Expires=1602694031) - - -- 要计算原问题 f(10),就需要先计算出子问题 f(9) 和 f(8) -- 然后要计算 f(9),又要先算出子问题 f(8) 和 f(7),以此类推。 -- 一直到 f(2) 和 f(1),递归树才终止。 - -**递归时间复杂度 = 解决一个问题时间*问题个数** -- 一个问题时间 = f(n-1)+f(n-2),也就是一个加法的操作,所以复杂度是 **O(1)**; -- 问题个数 = 递归树节点的总数,递归树的总结点 = 2^n-1,所以是复杂度**O(2^n)**。 - -因此,青蛙跳阶,递归解法的时间复杂度 = O(1) * O(2^n) = O(2^n),就是指数级别的,**如果n比较大的话,超时很正常的了**。 - -你仔细观察这颗递归树,你会发现存在**大量重复计算**,比如f(8)被计算了两次,f(7)被重复计算了3次...所以这个递归算法低效的原因,就是存在大量的重复计算! - -**那么,怎么解决这个问题呢?** - -既然存在大量重复计算,那么我们可以先把计算好的答案存下来,即造一个备忘录,等到下次需要的话,先去**备忘录**查一下,如果有,就直接取就好了,备忘录没有才再去计算,那就可以省去重新重复计算的耗时啦!这就是**带备忘录的解法** - -我们来看一下**带备忘录的递归解法**吧~ - -一般使用一个数组或者一个哈希map充当这个**备忘录**。 - -假设f(10)求解加上**备忘录**,我们再来画一下递归树: - -**第一步**,f(10)= f(9) + f(8),f(9) 和f(8)都需要计算出来,然后再加到备忘录中,如下: - -![](https://imgkr2.cn-bj.ufileos.com/22fe0dc0-136e-4e8d-9b54-7f1ff2a9d066.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=gJl54y4g86XMhK2K1ZbaqmVl94Y%253D&Expires=1602694255) - - -**第二步,** f(9) = f(8)+ f(7),f(8)= f(7)+ f(6), 因为 f(8) 已经在备忘录中啦,所以可以省掉,f(7),f(6)都需要计算出来,加到备忘录中~ - -![](https://imgkr2.cn-bj.ufileos.com/f9b26b22-c745-4bad-b14d-d8b2b51075f4.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=RkOd5Zj5Wwqonn63eXfoWqStvx4%253D&Expires=1602694275) - - -**第三步,** f(8) = f(7)+ f(6),发现f(8),f(7),f(6)全部都在备忘录上了,所以都可以剪掉。 -![](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ec535ab8a0d3401eae5cb041dabac221~tplv-k3u1fbpfcp-watermark.image) - -所以呢,用了备忘录递归算法,递归树变成光秃秃的咯,如下: -![](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5b78faafe49b4ee0ab939194459cf386~tplv-k3u1fbpfcp-watermark.image) - -带「备忘录」的递归算法,子问题个数就为n了,解决一个子问题还是O(1),所以**带「备忘录」的递归算法的时间复杂度是O(n)**。接下来呢,我们用带「备忘录」的递归算法去撸代码,解决这个青蛙跳阶问题咯~,代码如下: - -``` -public class Solution { - //哈希map充当备忘录的作用 - Map tempMap = new HashMap(); - public int numWays(int n) { - // n = 0 也算1种 - if (n == 0) { - return 1; - } - if (n <= 2) { - return n; - } - //先判断有没计算过,即看看备忘录有没有 - if (tempMap.containsKey(n)) { - //备忘录有,即计算过,直接返回 - return tempMap.get(n); - } else { - // 备忘录没有,即没有计算过,执行递归计算,并且把结果保存到备忘录map中,对1000000007取余(这个是leetcode题目规定的) - tempMap.put(n, (numWays(n - 1) + numWays(n - 2)) % 1000000007); - return tempMap.get(n); - } - } -} -``` - -去leetcode提交一下,如图,稳了: - -![](https://imgkr2.cn-bj.ufileos.com/8208e494-07e6-467b-96a2-8acf77121737.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=zNVyzVvQaWVQaQmABckQvIVh1XE%253D&Expires=1602694530) - -啥叫「自顶向下」?注意我们刚才画的递归树(或者说图),是从上向下延伸,都是从一个规模较大的原问题比如说 f(20),向下逐渐分解规模,直到 f(1) 和 f(2) 触底,然后逐层返回答案,这就叫「自顶向下」。 - - -啥叫「自底向上」?反过来,我们直接从最底下,最简单,问题规模最小的 f(1) 和 f(2) 开始往上推,直到推到我们想要的答案 f(20),这就是动态规划的思路,这也是为什么动态规划一般都脱离了递归,而是由循环迭代完成计算。 - -动态规划问题,下期分解 - -### 参考与感谢 -- [一文学会递归解题](https://mp.weixin.qq.com/s/Hew44D8rdXb3pf8mZGk67w) -- [动态规划详解](https://mp.weixin.qq.com/s/1V3aHVonWBEXlNUvK3S28w) - -### 个人公众号 -![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e6b23c704fc94ca09207b779f953cce6~tplv-k3u1fbpfcp-zoom-1.image) -- 更多干货,关注公众号 - diff --git "a/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207/README.md" "b/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207/README.md" new file mode 100644 index 0000000..7f6092a --- /dev/null +++ "b/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207/README.md" @@ -0,0 +1,10 @@ +## 后端思维篇(持续更新中) + +公众号:捡田螺的小男孩 + +- [后端思想篇:设计好接口的36个锦囊!](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499388&idx=1&sn=49a22120a3238e13ad7c3d3b73d9e453&chksm=cf222155f855a8434026b2c460d963c406186578c2527ca8f2bb829bbe849d87a2392a525a9b&scene=178&cur_album_id=2396778860463161350#rd) +- [后端思维篇:手把手教你写一个并行调用模板](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499504&idx=1&sn=bb62226e6cffeb1859efb0100c796050&chksm=cf2221d9f855a8cf23f75cb51c1a407578fb0f279e96ddae74b5b8c84f2f5dc71762425b17cb&scene=178&cur_album_id=2396778860463161350#rd) +- [后端思维篇:如何应用设计模式优化代码](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499524&idx=1&sn=cb4cc48a3e8d9a54b0ebc4c7ad517f14&chksm=cf22202df855a93b37327856ee88b0bf5f6ed7da67964438fc2cf747666260d5026dd62d4a17&scene=178&cur_album_id=2396778860463161350#rd) +- [后端思维篇:统一参数校验、异常处理、结果返回](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499708&idx=1&sn=808979c495acd9344732d147c0ad40d3&chksm=cf222095f855a983f31d5f6abf401fa3b5967f8839c6775d35cefc5cc6244fb4135563ff1090&scene=178&cur_album_id=2396778860463161350#rd) +- [后端思维篇:如何抽一个观察者模板](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247500159&idx=1&sn=a5328372e580b22c939a5b3084aef164&chksm=cf221e56f85597401e8c99b8dd1bc1af97fcf69207ceaa04c5c26e028ac47d1658b79ae32291&scene=178&cur_album_id=2396778860463161350#rd) +- [后端思维篇:后端思维专栏:通过层层代码去重,我又搞了一个通用模板](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247506942&idx=1&sn=ae14ed5cc179f73ea0b2f37c73ad8da4&chksm=c1e02672f697af645943ea8ee53b7cef6257ebbc21d2b77058994e98bdb1e107ad313e29e8c3&token=134957671&lang=zh_CN#rd) diff --git "a/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207/\345\220\216\347\253\257\346\200\235\347\273\264\344\270\200\357\274\232\350\256\276\350\256\241\346\216\245\345\217\243\347\232\20436\344\270\252\351\224\246\345\233\212.md" "b/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207/\345\220\216\347\253\257\346\200\235\347\273\264\344\270\200\357\274\232\350\256\276\350\256\241\346\216\245\345\217\243\347\232\20436\344\270\252\351\224\246\345\233\212.md" new file mode 100644 index 0000000..f999d6b --- /dev/null +++ "b/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207/\345\220\216\347\253\257\346\200\235\347\273\264\344\270\200\357\274\232\350\256\276\350\256\241\346\216\245\345\217\243\347\232\20436\344\270\252\351\224\246\345\233\212.md" @@ -0,0 +1,540 @@ +## ǰ + +ҺãǼݵСкΪ˿ʲôԣ```Java``````Go``````C++```䱳ĺ˼붼Ƶġһ˼ļרҪ˵һЩơߺ˹淶صģϣԴճа + +˿ʦҪǣ**ΰһӿƺ**ԣ͸ҽܣƺýӿڵ36ҡľǺ˼רĵһƪ + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1bfc8123cee34de2ad82b736121165d2~tplv-k3u1fbpfcp-zoom-1.image) + +- ںţݵСк + + +## 1. ӿڲУ + +γУÿԱرĻƵĽӿڣУǷΪգγǷԤڳȡҪϰ߹ճУܶͼbugDzУµġ + +> ݿֶΪ```varchar(16)```,Էһ32λַ㲻У**ݿֱ쳣** + +Ҳǣ㶨ĽӿڱģDzΪյģĽӿڷزûУ飬ΪijЩԭֱرһ```null```ֵ + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/bfd3392f3ce6408daa1940cc185f0d5f~tplv-k3u1fbpfcp-zoom-1.image) + +## 2. ޸Ͻӿʱעӿڵļ + +ܶbugΪ޸˶ɽӿڣȴ****µġؼDZȽصģֱӵϵͳʧܵġֳԱ׷Ŷ~ + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/701ac23b5dd04149b277c4001721fb87~tplv-k3u1fbpfcp-zoom-1.image) + +ԣԭӿ޸ģӿǶṩĻһҪǽӿڼݡٸӰɣdubboӿڣԭֻABһCͿԿ + +``` +//Ͻӿ +void oldService(A,B){ + //½ӿڣnullC + newService(A,B,null); +} + +//½ӿڣʱɾϽӿڣҪݡ +void newService(A,B,C){ + ... +} +``` + +## 3. ƽӿʱֿǽӿڵĿչ + +Ҫʵҵ񳡾ƽӿڣֿǽӿڵĿչԡ + +ӵһûӻ޸ԱʱҪˢǷṩһԱύˢϢӿڣ˼ύˢDzͨأת˻һҪˢĻǷҪʵһӿأǵǰҵͻģ飬ӿھͺãӿڵĿչԡ + +ģ黮ֵĻδһֽˢĻٸһµĽӿڣֻҪö٣Ȼˢͨ̽ӿڣʵһˢIJ컯ɡ + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cd3ee52ecaa34de384bb529cbb358889~tplv-k3u1fbpfcp-zoom-1.image) + + +## 4.ӿڿǷҪش + +ǰظ߼δDzǿǽӿȥش + +ȻDzѯʵ÷ءǸ޸ĻתģҪظˡ򵥵㣬ʹRedisظͬ󷽣һʱڵͬ󣬿ǷˡȻתӿڣߵĻ**Ƽʹݿر****ΨһˮΪΨһ** + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/059928f565ba4d27a17c54f451b0235d~tplv-k3u1fbpfcp-zoom-1.image) + + +## 5. صӿڣ̳߳ظ롣 + +һЩ½ת˽סµҪӿڣ̳߳ظҵ񶼹һ̳߳أЩҵbug̳߳ĻǾͱˣ**ҵӰ**˽̳߳ظ룬Ҫҵһḷ́߳͸ñҪҵ + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1d30804afc044026b4eb7bad23689c42~tplv-k3u1fbpfcp-zoom-1.image) + + +## 6. õӿҪ쳣ͳʱ + +õӿڣ߷ֲʽԶ̷ĵĻҪǣ + +- 쳣 + +> 磬˵Ľӿڣ쳣ˣôԻǵʧܻǸ澯 + +- ӿڳʱ + +> ûԤԷӿһ÷أһøʱϿʱ䣬ԱĽӿڡ**֮ǰһ**httpòóʱʱ䣬Ӧ̼һֱռ̲߳ͷţϿ̳߳ء + +- Դ +> Ľӿڵʧܣ費ҪԣԼΣҪվҵϽǶ˼ + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/25ec61c10c324ada9252745fa4017ad6~tplv-k3u1fbpfcp-zoom-1.image) + + +## 7. ӿʵֿ۶Ϻͽ + +ǰϵͳһ㶼Ƿֲʽġֲʽϵͳоij񲻿ãյϵͳõ, 󱻳Ϊ**ѩЧӦ** + +ֲʽ·```A->B->C....```ͼʾ + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/65240791c94c44b6aab143178eeb790c~tplv-k3u1fbpfcp-zoom-1.image) + +> C⣬**ΪSQLµû**ǽBҲӳ٣ӶAҲӳ١סAռϵͳ̡߳IOԴ AķԽԽ࣬ռüԴҲԽԽ࣬ջᵼϵͳƿ֣ͬãҵϵͳ + +ΪӦԷѩ, **۶Ϻͽ**ǼӿؿƣϵͳʱؽٵϵͳѡÿԴ```Hystrix``` + +## 8. ־ӡãӿڵĹؼ룬Ҫ־ݻ + +ؼҵεأӦ㹻־ݻ +磺ʵתҵתȻתʧˣſͻͶߣȻ㻹ûдӡ־ˮȵ£ȴް취 + +ôתҵҪЩ־Ϣأ٣ǰҪӡҪɣӿڵúҪһ쳣ɣͬʱӡ쳣־ɣ£ +``` +public void transfer(TransferDTO transferDTO){ + log.info("invoke tranfer begin"); + //ӡ + log.info("invoke tranfer,paramters:{}",transferDTO); + try { + res= transferService.transfer(transferDTO); + }catch(Exception e){ + log.error("transfer fail,account{}", + transferDTO.getAccount) + log.error("transfer fail,exception:{}",e); + } + log.info("invoke tranfer end"); + } +``` + +֮ǰдһƪӡ־15飬ҿԿ[ܽᣡ־ӡ15](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247494838&idx=1&sn=cdb15fd346bddf3f8c1c99f0efbd67d8&chksm=cf22339ff855ba891616c79d4f4855e228e34a9fb45088d7acbe421ad511b8d090a90f5b019f&token=162724582&lang=zh_CN&scene=21#wechat_redirect) + +## 9. ӿڵĹܶҪ߱һ + +һָӿȽϵһרһһ½ӿڣֻУ˻룬Ȼ󷵻ص½ɹԼ```userId```ɡ**Ϊ˼ٽӿڽһЩעᡢһЩòѯȫŵ½ӿڣͲ̫ס** + +ʵҲ΢һЩ˼룬ӿڵĹܵһȷ綩񡢻֡ƷϢصĽӿڶǻֿġ΢ĻDzǾͱȽϼ + + +## 10.ӿЩʹ첽 + +ٸ򵥵ӣʵһûעĽӿڡûעɹʱʼ߶ȥ֪ͨûʼ߷ţ͸ʺ첽Ϊܲһ֪ͨʧܣעʧܰɡ + +첽ķʽ򵥵ľ**̳߳**ʹϢУûעɹ߲һעɹϢעɹϢͷ֪ͨ + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/585b098a67b349d495e6e8579ea85e4c~tplv-k3u1fbpfcp-zoom-1.image) + + +еĽӿڶʺΪͬӿڡҪһת˵Ĺܣǵʵתˣǿ԰ѽӿͬûתʱͻھȴת˽ͺáתˣһһǧʣһʵģ԰ѽӿΪ첽ûתʱ־ûɹȷɹȻûʮӻʮӵת˽ͺáֻߣת˳ɹٻصϵͳ + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1ae74868492344c4bcbab9b480904c47~tplv-k3u1fbpfcp-zoom-1.image) + + +## 11. ŻӿںʱԶ̴пǸIJе + +һAPPҳĽӿڣҪûϢҪbannerϢҪ鵯ϢȵȡһһӿڴеDzеأ + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d118e2b09e1f4fc6a1003fd44a43e4c7~tplv-k3u1fbpfcp-zoom-1.image) + +Ǵһһ飬ûϢ200msbannerϢ100ms鵯Ϣ50msһͺʱ```350ms```ˣϢǺʱ͸ˡֳǿԸΪеõġҲ˵ûϢbannerϢ鵯Ϣͬʱ + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/83561366219b48a2a85a6bb0419f82a3~tplv-k3u1fbpfcp-zoom-1.image) + +Javaи첽```CompletableFuture```ͿԺܺʵܡȤСԿ֮ǰ¹[CompletableFuture](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490456&idx=1&sn=95836324db57673a4d7aea4fb233c0d2&chksm=cf21c4b1f8564da72dc7b39279362bcf965b1374540f3b339413d138599f7de59a5f977e3b0e&token=1260947715&lang=zh_CN#rd) + +## 12. ӿںϲ˵˼ + +ݿԶ̵ʱͲҪforѭá +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/855cd5cf57d047be909dbc41ddacc021~tplv-k3u1fbpfcp-zoom-1.image) + +һӣƽʱһбϸݲݿʱҪforѭһһ룬һμ롣ͬԶ̵Ҳ뷨ѯӪǩǷУһǩһǩȥ飬Ҳǩȥ飬УЧʾ͸ + +``` +// +for(int i=0;i һЩƽʱ䶯С˵ƷϢԷŵ棬ʱȲѯ棬ûٲݿ⣬Ұݿݸµ档ǣʹûҪЩ㣺ݿһα֤Ⱥѩ洩͸⡣ + +- ֤ݿͻһԣ**ʱ˫ɾɾԻơȡbiglog첽ɾ** +- +- ѩRedisȺ߿áùʱ +- 洩͸ӿڲУ顢ѯΪøĬϿֵǡ¡ + +һ```Redis```ֲʽ棬ȻЩʱҲԿʹñػ棬```Guava CacheCaffeine```ȡʹñػЩȱ㣬޷дݴ洢Ӧý̵ʧЧ + +## 14. ӿڿȵݸ + +˲ʱĸ߲ܻϵͳһЩȵݵĸ롣**ҵ롢ϵͳ롢û롢ݸ**ȡ + +- ҵԣ12306ķʱƱȵݷɢϵͳѹ +- ϵͳ룺ϵͳֳûƷ顣ֱʹòͬݿ⣬ӽ㵽Ӧòٵݲȫ롣 +- û룺صûøõĻ +- ݸ룺ʹõĻ漯Ⱥݿȵݡ + +## 15. ɱûƤл + +Ʒ˸ʥڵʱ򣬺ƤΪʥصģڵʱΪںƤȡ + +ڴдƣ´룺 +``` +if(duringChristmas){ + img = redPacketChristmasSkin; +}else if(duringSpringFestival){ + img = redSpringFestivalSkin; +} +``` +ԪڵʱӪСͻȻ뷨ƤɵصģʱDzҪȥ޸Ĵˣ·ˣ + +һʼӿʱʵ**һźƤñ**ƤûأƤֻ޸һ±ݾͺˡ + +ȻһЩʺһЩûIJһҳơijʱЩԸ㵽û档**Ҳչ˼һ֡** + +## 16.ӿڿݵ + +ӿҪݵԵģתЩҪӿڡֱ۵ҵ񳡾**ûŵ**Ľӿû**holdס**Ϣгظѵҵ߼ôƣ + +£**ʲôݵȣ** + +> ѧУݵȱʾһκͶijһԴӦþͬĸã˵ӰһִеӰЧͬ + +ұ**غݵʵ**ҪΪ˱ظݣظɡݵƳѾ󣬻Ҫÿͬ󶼷һЧأܶʱǵĴ̡ƵĹ + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f8c3d0d5a653455198ba3259ef221387~tplv-k3u1fbpfcp-zoom-1.image) + + +ӿݵʵַҪ8֣ + +- select+insert+/Ψһͻ +- ֱinsert + /Ψһͻ +- ״̬ݵ +- ȡر +- token +- +- ֹ +- ֲʽ + +ҿԿƪ¹[ݵ](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497427&idx=1&sn=2ed160c9917ad989eee1ac60d6122855&chksm=cf2229faf855a0ecf5eb34c7335acdf6420426490ee99fc2b602d54ff4ffcecfdab24eeab0a3&token=1260947715&lang=zh_CN#rd) + +## 17. д룬ȿǶӿ⣬עӳ + +ǵݿⶼǼȺģҲдӿ⣬ǰһ㶼Ƕдġдݣ϶д⣬ǶڶȡʵʱҪ󲻸ߵݣȿǶӿ⣬ΪԷֵѹ + +ȡӿĻҪӳٵ⡣ + +## 18.ӿעⷵصҪҳ + +һӿڷرģӦðӣѹҲdzʵDZȽϴ󣬿ԷҳأǹܲصıģӦÿǽӿڲ֡ + +## 19. õĽӿʵ֣벻SQLŻ + +˵ģдһӿڣ벻SQLŻ + +SQLŻ⼸ά˼ + +- explain SQLѯƻصעtypeextrafilteredֶΣ +- show profile˽SQLִе̵߳״̬Լĵʱ +- Ż ǰ׺ԭʽתorder byԼgroup byŻjoinŻ +- ҳŻӳٹ¼һҳID +- ̫**ֱֿ**ͬesesѯ + +## 20.ȿƺ + +ʲôǼأ + +> ʵǾҪסķΧǶ󡣱ڼ䣬ֻҪסͿ˰ɣҪҶü˽Űɣļȡ + +дʱ漰ԴûбҪסġͺ䣬ðҶססžͿˡ + +磬ҵУһArrayListΪ漰̲߳ҪպһαȽϺʱIJе```slowNotShare```漰̰߳ȫ⣬μأ + + +``` +//漰Դ +private void slowNotShare() { + try { + TimeUnit.MILLISECONDS.sleep(100); + } catch (InterruptedException e) { + } +} + +//ļ +public int wrong() { + long beginTime = System.currentTimeMillis(); + IntStream.rangeClosed(1, 10000).parallel().forEach(i -> { + //̫ˣslowNotShareʵ漰Դ + synchronized (this) { + slowNotShare(); + data.add(i); + } + }); + log.info("cosume time:{}", System.currentTimeMillis() - beginTime); + return data.size(); +} +``` + + +``` +public int right() { + long beginTime = System.currentTimeMillis(); + IntStream.rangeClosed(1, 10000).parallel().forEach(i -> { + slowNotShare();//Բ + //ֻListⲿּ + synchronized (data) { + data.add(i); + } + }); + log.info("cosume time:{}", System.currentTimeMillis() - beginTime); + return data.size(); +} +``` + +## 21.ӿ״̬ʹҪͳһȷ + +ṩҪĽӿڵ״̬Ϣһת˽ӿڵdzɹʧܡлɹȣҪȷ߿ͻˡӿʧܣôʧܵԭʲôЩҪϢҪ߸ͻˣҪȷĴͶӦͬʱԱϢװһ£ҪѺ˵쳣Ϣȫ׳ͻˡ + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/20a1080126274c04aa31802178c01bb0~tplv-k3u1fbpfcp-zoom-1.image) + + +## 22.ӿҪ쳣 + +ʵһõĽӿڣ벻ŵ쳣쳣ʮСɣ + +- Ҫʹ```e.printStackTrace()```,ʹ```log```ӡΪ```e.printStackTrace()```ܻᵼڴռ +- ```catch```ס쳣ʱӡ```exception```ڸöλ +- Ҫһ```Exception```׽пܵ쳣 +- ǵʹ```finally```رԴֱʹ```try-with-resource``` +- 쳣׳쳣ȫƥ䣬߲쳣쳣ĸ +- 񵽵쳣ܺٴ־ +- ע쳣ĴνṹȾ +- Զװ쳣Ҫԭʼ쳣Ϣ```Throwable cause``` +- ʱ쳣```RuntimeException``` Ӧͨ```catch```ķʽԤ飬磺```NullPointerException``` +- ע쳣ƥ˳Ȳ쳣 + +СȤԿ֮ǰдƪ¹[Java 쳣ʮ](https://mp.weixin.qq.com/s/3mqY77c8iXWvJFzkVQi9Og) + +## 23. Ż߼ + +Ż߼黹ͦҪģҲ˵ʵֵҵ룬**DZȽϸӵĻעд**У߼뾡Ч + +> 磬ҪʹûϢԣsessionѾȡ```userId```ˣȻͰûϢݿѯʹ󣬺ҪõûϢԣЩСû̫࣬־Ͱ```userId```ٴȥٲһݿ⡣ĿУִ롣ֱӰû + +α룺 + +``` +public Response test(Session session){ + UserInfo user = UserDao.queryByUserId(session.getUserId()); + + if(user==null){ + reutrn new Response(); + } + + return do(session.getUserId()); +} + +public Response do(String UserId){ + //һݿ + UserInfo user = UserDao.queryByUserId(session.getUserId()); + ...... + return new Response(); +} + +``` + + + +``` +public Response test(Session session){ + UserInfo user = UserDao.queryByUserId(session.getUserId()); + + if(user==null){ + reutrn new Response(); + } + + return do(session.getUserId()); +} + +//ֱӴUserInfoɣٶһݿ +public Response do(UserInfo user){ + ...... + return new Response(); +} +``` + +ȻֻһЩСһӣкܶƵӣҪҿУ˼Ĺ + + +## 24. ӿʵֹ̻Уעļ񡢴 + +- ȡļʱҪ```Files.readAllBytes```ֱӶȡڴ棬OOMģʹ```BufferedReader```һһ +- ܵعʱ䳤ӳٵ⣬о +- עһЩʹãΪֱӽģᴥfullGC + +## 25. ĽӿڣҪ + +ϵͳÿ뿸ס1000һʮأǶȾ˵߲ʱˣϵͳijôأ + +ȡʩеϵͳCPUڴ桢Load쮵ĺܸߣе޷Ӧ + +ֳǿԲΪ˱ϵͳֱӶ + +壺 +> ڼУǿӿڷͻʣɷֹDoSWeb档Ҳơָϵͳٸ߲ߴ£µϵͳķʣӶ֤ϵͳȶԡ + +ʹGuava```RateLimiter```Ҳʹ```Redis```ֲʽʹð↑Դ```sentinel``` + +ҿԿ֮ǰƪ¹[4־㷨](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490393&idx=1&sn=98189caa486406f8fa94d84ba0667604&chksm=cf21c470f8564d665ce04ccb9dc7502633246da87a0541b07ba4ac99423b28ce544cdd6c036b&token=162724582&lang=zh_CN&scene=21#wechat_redirect) + + +## 26.ʵʱעʱ쳣ָ롢±Խȣ + +ճУҪȡʩ**ָ߽**ʱƴȽϳ +``` +String name = list.get(1).getName(); //listԽ磬Ϊһ2Ԫع +``` + +ӦòȡʩԤһ߽£ +``` +if(CollectionsUtil.isNotEmpty(list)&& list.size()>1){ + String name = list.get(1).getName(); +} +``` +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/10199365140845ea8f7b29a07fbaf3cc~tplv-k3u1fbpfcp-zoom-1.image) + + +## 27.֤ӿڰȫ + +APIӿǶṩģҪ֤ӿڵİȫԡ֤ӿڵİȫ**tokenƺͽӿǩ** + +**token֤**Ƚϼ򵥵ģ + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9b468f89cdaf4040b84e432182903fd9~tplv-k3u1fbpfcp-zoom-1.image) + +1. ͻ˷ȡtoken +2. ȫΨһtoken浽redisУһһʱ䣩Ȼ󷵻ظͻˡ +3. ͻ˴token +4. ȥredisȷtokenǷڣһ redis.del(token)ķʽڻɾɹҵ߼ɾʧܲҵ߼ֱӷؽ + +**ӿǩ**ķʽǰѽӿϢģʱ汾šappidȣͻ˽ԿǩȻùԿǩ֤ͨΪǺϷġûб۸Ĺ + +йڼǩǩģҿԿƪ¹[Աرǩǩ](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488022&idx=1&sn=70484a48173d36006c8db1dfb74ab64d&chksm=cf21cd3ff8564429a1205f6c1d78757faae543111c8461d16c71aaee092fe3e0fed870cc5e0e&token=162724582&lang=zh_CN&scene=21#wechat_redirect) + +**ǩǩtokenƣӿڱһҪܵ**ȻhttpsЭǻԱļܵġǷĻμӽأ +> ԲοHTTPSԭǷ˰ѹԿͻˣȻͻɶԳԿſͻ÷˵ĹԿܶԳԿٷˣԼ˽Կܣõͻ˵ĶԳԿʱͿ촫䱨ͻ**ԳԿ****öӦĶԳԿܱ** + +ʱ򣬽ӿڵİȫԣ**ֻš֤Ϣ**˵**û˽ݣ㱩¶** + +## 28.ֲʽα֤ + +> ֲʽ񣺾ָIJߡ֧ķԴԼֱλڲͬķֲʽϵͳIJͬڵ֮ϡ˵ֲʽָľǷֲʽϵͳеĴھΪ˱֤ͬݿڵһԡ + +ֲʽļֽ +- 2PC(׶ύ)3PC +- TCCTryConfirmCancel +- Ϣ +- Ŭ֪ͨ +- seata + +ҿԿƪ¹[һ⣺ֲʽ](https://mp.weixin.qq.com/s/3r9MfIz2RAtdFhYzwwZxjA) + +## 29. ʧЧһЩ䳡 + +ǵĽӿڿУҪʹõҪܿʧЧһЩ䳡 + +- ķȨޱpublicprivateȨޣʧЧ +- finalģᵼʧЧ +- ͬһеķֱڲãᵼʧЧ +- һûspringͲspring +- ̵߳ãͬһ߳УȡݿӲһġ +- Ĵ洢治֧ +- Լtry...catch쳣ʧЧ +- Ĵ + +Ƽҿƪ£[springʧЧ12ֳ̫](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247494570&idx=2&sn=17357bcd328b2d1d83f4a72c47daac1b&chksm=cf223483f855bd95351a778d5f48ddd37917ce2790ebbbcd1d6ee4f27f7f4b147f0d41101dcc&token=2044040586&lang=zh_CN&scene=21#wechat_redirect) + + +## 30. ճõģʽ + +ѴдãҪõģʽģʽģʽģ巽ģʽ۲ģʽȵȡģʽǴƾܽᡣʹģʽԿô롢ôױ⡢֤ɿԡ + +֮ǰдһƪܽṤгģʽ£дͦģҿԿ£[ʵսгõЩģʽ](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247495616&idx=1&sn=e74c733d26351eab22646e44ea74d233&chksm=cf2230e9f855b9ffe1ddb9fe15f72a273d5de02ed91cc97f3066d4162af027299718e2bf748e&token=1260947715&lang=zh_CN#rd) + +## 31. дʱ԰ȫ + +**߲**£```HashMap```ܻѭΪǷ԰ȫģԿʹ```ConcurrentHashMap```ҲϰߣҪ־һ```new HashMap()```; + +> - HashmapArraylistLinkedListTreeMapȶԲȫģ +> - VectorHashtableConcurrentHashMapȶ԰ȫ + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1ba0cab945874264a8d8e87b7d7c4a1b~tplv-k3u1fbpfcp-zoom-1.image) + + +## 32.ӿڶ׶淶 + +д룬ΪʵֵǰĹܣҲҪںά˵ά벻дԼģҲǸ˿ġԽӿڶҪ׶淶 + +## 33. ӿڵİ汾 + +ӿҪð汾ơ˵ģӦð```version```ӿڰ汾ֶΣδӿڼݡʵҲӿչԵһֵɡ + +ͻAPPijŻˣϰ汾Ṳ棬ʱǵ```version```汾žóˣ```version```ð汾ơ + +## 34. ע淶 + +עһЩĴ뻵ζ +- ظ루鹫÷ģʽ +- ࣨɷװһDTO +- С +- ж̫ࣨŻif...else +- ûõĴ +- עشʽ +- + +ĻζҶд[25ִ뻵ζܽ+Żʾ](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490148&idx=1&sn=00a181bf74313f751b3ea15ebc303545&chksm=cf21c54df8564c5bc5b4600fce46619f175f7ae557956f449629c470a08e20580feef4ea8d53&token=162724582&lang=zh_CN&scene=21#wechat_redirect) + +## 35.֤ӿȷԣʵDZ֤ٵbug + +֤ӿڵȷԣǶȽDZ֤ٵbugûbugԽӿڿһҪ**Բһ**ȻĻӿڵȷڣ̲߳ʱ**֤ݵȷ**,ȵȡһת˽ףۼʱ򣬿ͨCASֹķʽ֤ۼȷɡ + +ʵɱӿڣ÷ֹɡʹRedisֲʽֹ⡣ʹRedisֲʽмעҪ㣬ҿԿ֮ǰƪ¹[ַ̽Redisֲʽȷʹ](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488142&idx=1&sn=79a304efae7a814b6f71bbbc53810c0c&chksm=cf21cda7f85644b11ff80323defb90193bc1780b45c1c6081f00da85d665fd9eb32cc934b5cf&token=162724582&lang=zh_CN&scene=21#wechat_redirect) + +## 36.ѧṵͨǰ˹ͨƷͨ + +ҰһŵѧṵͨǷdzdzҪġ㿪ӿʱ**һԼͷѽӿڶ****Ҫͻȶӿ**һЩѵʱleader뷽ʵĹУʲô⣬ʱƷͨ + +֮ǣӿڹУһҪͨ~ + + +## (ע) + +ƪ¶ĻӭעҵĹںţݵСк + + diff --git "a/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207\344\272\214\357\274\232\346\211\213\346\212\212\346\211\213\346\225\231\344\275\240\345\256\236\347\216\260\344\270\200\344\270\252\345\271\266\350\241\214\350\260\203\347\224\250\346\250\241\346\235\277.md" "b/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207\344\272\214\357\274\232\346\211\213\346\212\212\346\211\213\346\225\231\344\275\240\345\256\236\347\216\260\344\270\200\344\270\252\345\271\266\350\241\214\350\260\203\347\224\250\346\250\241\346\235\277.md" new file mode 100644 index 0000000..762cb1b --- /dev/null +++ "b/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207/\345\220\216\347\253\257\346\200\235\347\273\264\347\257\207\344\272\214\357\274\232\346\211\213\346\212\212\346\211\213\346\225\231\344\275\240\345\256\236\347\216\260\344\270\200\344\270\252\345\271\266\350\241\214\350\260\203\347\224\250\346\250\241\346\235\277.md" @@ -0,0 +1,599 @@ +## ǰ + +ҺãǼݵСк + +Ǻ˼άרĵڶƪһƪ[36ƽӿڵĽ](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499388&idx=1&sn=49a22120a3238e13ad7c3d3b73d9e453&chksm=cf222155f855a8434026b2c460d963c406186578c2527ca8f2bb829bbe849d87a2392a525a9b&token=1380536362&lang=zh_CN#rd)õdzСϿɡ +36ƽӿڵĽҲᵽһ㣺**ʹòеŻӿ**ԽͿӱޣдڶƪְֽдһеģ塣 + +- һеõӣAppҳϢѯ +- CompletionServiceʵֲе +- ȡͨõIJе÷ +- ˼ԼģʽӦ +- ˼ܽ +- ںţ**ݵСк** + + +## 1. һеõ + +һAPPҳѯĽӿڣҪûϢҪ```banner```ϢҪǩϢȵȡһСʵ£ + +``` +public AppHeadInfoResponse queryAppHeadInfo(AppInfoReq req) { + //ûϢ + UserInfoParam userInfoParam = buildUserParam(req); + UserInfoDTO userInfoDTO = userService.queryUserInfo(userInfoParam); + //bannerϢ + BannerParam bannerParam = buildBannerParam(req); + BannerDTO bannerDTO = bannerService.queryBannerInfo(bannerParam); + //ǩϢ + LabelParam labelParam = buildLabelParam(req); + LabelDTO labelDTO = labelService.queryLabelInfo(labelParam); + //װ + return buildResponse(userInfoDTO,bannerDTO,labelDTO); +} +``` + +δʲô ʵһͦĴ룬ʵУѯûbannerǩϢ**Ǵе**ѯûϢ```200ms```ѯbannerϢ```100ms```ѯǩϢ```200ms```Ļʱ```500ms``` + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/35fa8e071a7048d5ae7d8e3e7f339532~tplv-k3u1fbpfcp-zoom-1.image) + +ʵΪŻܣǿ޸Ϊ**е**ķʽʱԽΪ```200ms```ͼʾ + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e8559cfd7bb2449dbab91c0b38a3d78e~tplv-k3u1fbpfcp-zoom-1.image) + + +## 2. CompletionServiceʵֲе + +ӣ**ʵֲеأ** + +С˵ʹ```Future+Callable```ʵֶIJеáִ̳߳ʱֵ```Futureget()```ȡģǰһִбȽϺʱĻ```get```γŶӵȴ + +```CompletionService```ǶԶ```ExecutorService```˰װһ,һ߻ȡķֵ·ִֿ,֮䲻ụԻȡɵ + + +> ```CompletionService```ʵԭȽϼ򵥣ײͨFutureTask+УʵɵĻȻȡҲ˵ִнɵȺ˳ɿŻȡڲһȽȳУڱѾִɵFuture```CompletionService```polltakeɻȡһѾִɵFutureͨFutureӿʵ```get```ȡյĽ + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/10e375f58f5d490193888b0c5375e0f0~tplv-k3u1fbpfcp-zoom-1.image) + + +£```CompletionService```ʵֲвѯAPPҳϢ˼£ + +1. ȰѲѯûϢ񣬷ŵ̳߳أ£ +``` +ExecutorService executor = Executors.newFixedThreadPool(10); +//ѯûϢ +CompletionService userDTOCompletionService = new ExecutorCompletionService(executor); +Callable userInfoDTOCallableTask = () -> { + UserInfoParam userInfoParam = buildUserParam(req); + return userService.queryUserInfo(userInfoParam); + }; +userDTOCompletionService.submit(userInfoDTOCallableTask); +``` + +2. Ѳѯ```banner```ϢҲŵ̳߳صĻֲ÷ˣΪͲһһ```UserInfoDTO```һ```BannerDTO```ʱDzǰѷΪObjectɣΪжǼ̳Objectģ£ + +``` +ExecutorService executor = Executors.newFixedThreadPool(10); +//ѯûϢ +CompletionService baseDTOCompletionService = new ExecutorCompletionService(executor); +Callable userInfoDTOCallableTask = () -> { + UserInfoParam userInfoParam = buildUserParam(req); + return userService.queryUserInfo(userInfoParam); +}; +//bannerϢ +Callable bannerDTOCallableTask = () -> { + BannerParam bannerParam = buildBannerParam(req); + return bannerService.queryBannerInfo(bannerParam); +}; + +//ύûϢ +baseDTOCompletionService.submit(userInfoDTOCallableTask); +//ύbannerϢ +baseDTOCompletionService.submit(bannerDTOCallableTask); +``` +3. и⣬ǻȡ**ֵʱ**Dz֪ĸ```Object```ûϢDTOĸ```BannerDTO```**ôأ**ʱǿڲչΪһBaseRspDTOٸͷObjectݵģȻBaseRspDTOиUserDTOBannerDTO**Ψһkey**£ + +``` +public class BaseRspDTO { + + //DTOصΨһǣUserInfoDTOBannerDTO + private String key; + //صdata + private T data; + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } +} + +//вѯAppҳϢ +public AppHeadInfoResponse parallelQueryAppHeadPageInfo(AppInfoReq req) { + + long beginTime = System.currentTimeMillis(); + System.out.println("ʼвѯappҳϢʼʱ䣺" + beginTime); + + ExecutorService executor = Executors.newFixedThreadPool(10); + CompletionService> baseDTOCompletionService = new ExecutorCompletionService>(executor); + + //ѯûϢ + Callable> userInfoDTOCallableTask = () -> { + UserInfoParam userInfoParam = buildUserParam(req); + UserInfoDTO userInfoDTO = userService.queryUserInfo(userInfoParam); + BaseRspDTO userBaseRspDTO = new BaseRspDTO(); + userBaseRspDTO.setKey("userInfoDTO"); + userBaseRspDTO.setData(userInfoDTO); + return userBaseRspDTO; + }; + + //bannerϢѯ + Callable> bannerDTOCallableTask = () -> { + BannerParam bannerParam = buildBannerParam(req); + BannerDTO bannerDTO = bannerService.queryBannerInfo(bannerParam); + BaseRspDTO bannerBaseRspDTO = new BaseRspDTO(); + bannerBaseRspDTO.setKey("bannerDTO"); + bannerBaseRspDTO.setData(bannerDTO); + return bannerBaseRspDTO; + }; + + //labelϢѯ + Callable> labelDTODTOCallableTask = () -> { + LabelParam labelParam = buildLabelParam(req); + LabelDTO labelDTO = labelService.queryLabelInfo(labelParam); + BaseRspDTO labelBaseRspDTO = new BaseRspDTO(); + labelBaseRspDTO.setKey("labelDTO"); + labelBaseRspDTO.setData(labelDTO); + return labelBaseRspDTO; + }; + + //ύûϢ + baseDTOCompletionService.submit(userInfoDTOCallableTask); + //ύbannerϢ + baseDTOCompletionService.submit(bannerDTOCallableTask); + //ύlabelϢ + baseDTOCompletionService.submit(labelDTODTOCallableTask); + + UserInfoDTO userInfoDTO = null; + BannerDTO bannerDTO = null; + LabelDTO labelDTO = null; + + try { + //Ϊύ3Իȡ3 + for (int i = 0; i < 3; i++) { + Future> baseRspDTOFuture = baseDTOCompletionService.poll(1, TimeUnit.SECONDS); + BaseRspDTO baseRspDTO = baseRspDTOFuture.get(); + if ("userInfoDTO".equals(baseRspDTO.getKey())) { + userInfoDTO = (UserInfoDTO) baseRspDTO.getData(); + } else if ("bannerDTO".equals(baseRspDTO.getKey())) { + bannerDTO = (BannerDTO) baseRspDTO.getData(); + } else if ("labelDTO".equals(baseRspDTO.getKey())) { + labelDTO = (LabelDTO) baseRspDTO.getData(); + } + } + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + e.printStackTrace(); + } + + System.out.println("вѯappҳϢ,ܺʱ" + (System.currentTimeMillis() - beginTime)); + return buildResponse(userInfoDTO, bannerDTO, labelDTO); +} +``` + +Ϊֹһ```CompletionService```ʵֲеõѾʵDzǺܿģ + +## 3. ȡͨõIJе÷ + +ǻع۲µ2СڣѯappҳϢdemo```CompletionService```ʵ˲еáûʲô뷨أ,ҵ񳡾ҲͨеŻDzҲøһƵ2СڵĴ롣ԣ**DzǿԳȡһͨõIJзñijҲã԰ɣǺ˼ά** + +ڵ2СڵĴ룬γȡͨòе÷ء + +ȣͨõIJе÷**ܸҵصԹҹ**԰ɣԷӦЩأ + +> Σ```Callable```԰ɡΪУ϶ǶCallableġԣӦһ```Callable```顣Ȼ󣬻APPҳѯӣ```Callable```ô```BaseRspDTO```ͣ԰ɣξ```List>> list``` + +Dzеõijأ ж```Callable```DzǵжӦķأˣijο```List>```dzȡͨòеģ壬Ϳдɽϣ + +``` + public List> executeTask(List>> taskList) { + + List> resultList = new ArrayList<>(); + //У + if (taskList == null || taskList.size() == 0) { + return resultList; + } + + ExecutorService executor = Executors.newFixedThreadPool(10); + CompletionService> baseDTOCompletionService = new ExecutorCompletionService>(executor); + //ύ + for (Callable> task : taskList) { + baseDTOCompletionService.submit(task); + } + + try { + //ȡ + for (int i = 0; i < taskList.size(); i++) { + Future> baseRspDTOFuture = baseDTOCompletionService.poll(2, TimeUnit.SECONDS); + resultList.add(baseRspDTOFuture.get()); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + e.printStackTrace(); + } + + return resultList; + } +``` +ȻdzȡͨõIJе÷ϵķǷ**ЩطҪĽ**أ + +- һŻĵط```executor̳߳```Щҵ񳡾```A̳߳```Щҵ```B̳߳```ôͲͨ԰ɡǿ԰̳߳Բʵṩ÷Լơ +- ڶŻĵط```CompletionService``````poll```ȡʱʱʱдġΪͬҵ񳡾ʱʱܲһԣʱʱҲǿԲʽų÷Լơ + +ٴŻһͨõIJеģ壬£ +``` +public List> executeTask(List>> taskList, long timeOut, ExecutorService executor) { + + List> resultList = new ArrayList<>(); + //У + if (taskList == null || taskList.size() == 0) { + return resultList; + } + if (executor == null) { + return resultList; + } + if (timeOut <= 0) { + return resultList; + } + + //ύ + CompletionService> baseDTOCompletionService = new ExecutorCompletionService>(executor); + for (Callable> task : taskList) { + baseDTOCompletionService.submit(task); + } + + try { + //ȡ + for (int i = 0; i < taskList.size(); i++) { + Future> baseRspDTOFuture = baseDTOCompletionService.poll(timeOut, TimeUnit.SECONDS); + resultList.add(baseRspDTOFuture.get()); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + e.printStackTrace(); + } + + return resultList; +} +``` + +ԺijҲҪõеõĻֱӵɣDzеССijɾ͸ + +## 4. ˼ԼģʽӦ + +ǰѳȡǸõIJе÷Ӧõ```AppҳϢѯ```ӣ£ + +``` +public AppHeadInfoResponse parallelQueryAppHeadPageInfo1(AppInfoReq req) { + + long beginTime = System.currentTimeMillis(); + System.out.println("ʼвѯappҳϢʼʱ䣺" + beginTime); + //ûϢѯ + Callable> userInfoDTOCallableTask = () -> { + UserInfoParam userInfoParam = buildUserParam(req); + UserInfoDTO userInfoDTO = userService.queryUserInfo(userInfoParam); + BaseRspDTO userBaseRspDTO = new BaseRspDTO(); + userBaseRspDTO.setKey("userInfoDTO"); + userBaseRspDTO.setData(userInfoDTO); + return userBaseRspDTO; + }; + + //bannerϢѯ + Callable> bannerDTOCallableTask = () -> { + BannerParam bannerParam = buildBannerParam(req); + BannerDTO bannerDTO = bannerService.queryBannerInfo(bannerParam); + BaseRspDTO bannerBaseRspDTO = new BaseRspDTO(); + bannerBaseRspDTO.setKey("bannerDTO"); + bannerBaseRspDTO.setData(bannerDTO); + return bannerBaseRspDTO; + }; + + //labelϢѯ + Callable> labelDTODTOCallableTask = () -> { + LabelParam labelParam = buildLabelParam(req); + LabelDTO labelDTO = labelService.queryLabelInfo(labelParam); + BaseRspDTO labelBaseRspDTO = new BaseRspDTO(); + labelBaseRspDTO.setKey("labelDTO"); + labelBaseRspDTO.setData(labelDTO); + return labelBaseRspDTO; + }; + + List>> taskList = new ArrayList<>(); + taskList.add(userInfoDTOCallableTask); + taskList.add(bannerDTOCallableTask); + taskList.add(labelDTODTOCallableTask); + ExecutorService executor = Executors.newFixedThreadPool(10); + List> resultList = parallelInvokeCommonService.executeTask(taskList, 3, executor); + if (resultList == null || resultList.size() == 0) { + return new AppHeadInfoResponse(); + } + + UserInfoDTO userInfoDTO = null; + BannerDTO bannerDTO = null; + LabelDTO labelDTO = null; + + // + for (int i = 0; i < resultList.size(); i++) { + BaseRspDTO baseRspDTO = resultList.get(i); + if ("userInfoDTO".equals(baseRspDTO.getKey())) { + userInfoDTO = (UserInfoDTO) baseRspDTO.getData(); + } else if ("bannerDTO".equals(baseRspDTO.getKey())) { + bannerDTO = (BannerDTO) baseRspDTO.getData(); + } else if ("labelDTO".equals(baseRspDTO.getKey())) { + labelDTO = (LabelDTO) baseRspDTO.getData(); + } + } + + System.out.println("вѯappҳϢ,ܺʱ" + (System.currentTimeMillis() - beginTime)); + return buildResponse(userInfoDTO, bannerDTO, labelDTO); + } + +``` + +ϴ룬СǣǷŻ뷨أ ⼸```Callable```ѯDzҲԳȡһ£ôӼࡣ + +> ˵ֱӽһ```BaseTaskCommand```࣬ʵ```Callable```ӿڣѲѯûϢѯbannerϢlabelǩϢIJѯŽȥ + +£ + +``` +public class BaseTaskCommand implements Callable> { + + private String key; + private AppInfoReq req; + private IUserService userService; + private IBannerService bannerService; + private ILabelService labelService; + + public BaseTaskCommand(String key, AppInfoReq req, IUserService userService, IBannerService bannerService, ILabelService labelService) { + this.key = key; + this.req = req; + this.userService = userService; + this.bannerService = bannerService; + this.labelService = labelService; + } + + @Override + public BaseRspDTO call() throws Exception { + + if ("userInfoDTO".equals(key)) { + UserInfoParam userInfoParam = buildUserParam(req); + UserInfoDTO userInfoDTO = userService.queryUserInfo(userInfoParam); + BaseRspDTO userBaseRspDTO = new BaseRspDTO(); + userBaseRspDTO.setKey("userInfoDTO"); + userBaseRspDTO.setData(userInfoDTO); + return userBaseRspDTO; + } else if ("bannerDTO".equals(key)) { + BannerParam bannerParam = buildBannerParam(req); + BannerDTO bannerDTO = bannerService.queryBannerInfo(bannerParam); + BaseRspDTO bannerBaseRspDTO = new BaseRspDTO(); + bannerBaseRspDTO.setKey("bannerDTO"); + bannerBaseRspDTO.setData(bannerDTO); + return bannerBaseRspDTO; + } else if ("labelDTO".equals(key)) { + LabelParam labelParam = buildLabelParam(req); + LabelDTO labelDTO = labelService.queryLabelInfo(labelParam); + BaseRspDTO labelBaseRspDTO = new BaseRspDTO(); + labelBaseRspDTO.setKey("labelDTO"); + labelBaseRspDTO.setData(labelDTO); + return labelBaseRspDTO; + } + + return null; + } + + + private UserInfoParam buildUserParam(AppInfoReq req) { + return new UserInfoParam(); + } + + private BannerParam buildBannerParam(AppInfoReq req) { + return new BannerParam(); + } + + private LabelParam buildLabelParam(AppInfoReq req) { + return new LabelParam(); + } +} +``` +룬캯**Ƚ϶IJ**```call()```Уж```if...else...```,һ֧**ѯϢ**ֵ```call```޸ˣ**BaseTaskCommandĹҲҪ޸** + +> Ƿӡ󣬶гֶif...else...ʱǾͿԿʹ**ģʽ+ģʽ**Ż + +ʵ࣬£ + +``` + +public interface IBaseTask { + + //ÿkey + String getTaskType(); + + BaseRspDTO execute(AppInfoReq req); + +} + +//ûϢ +@Service +public class UserInfoStrategyTask implements IBaseTask { + + @Autowired + private IUserService userService; + + @Override + public String getTaskType() { + return "userInfoDTO"; + } + + @Override + public BaseRspDTO execute(AppInfoReq req) { + UserInfoParam userInfoParam = userService.buildUserParam(req); + UserInfoDTO userInfoDTO = userService.queryUserInfo(userInfoParam); + BaseRspDTO userBaseRspDTO = new BaseRspDTO(); + userBaseRspDTO.setKey(getTaskType()); + userBaseRspDTO.setData(userBaseRspDTO); + return userBaseRspDTO; + } +} + +/** + * bannerϢʵ + **/ +@Service +public class BannerStrategyTask implements IBaseTask { + + @Autowired + private IBannerService bannerService; + + @Override + public String getTaskType() { + return "bannerDTO"; + } + + @Override + public BaseRspDTO execute(AppInfoReq req) { + BannerParam bannerParam = bannerService.buildBannerParam(req); + BannerDTO bannerDTO = bannerService.queryBannerInfo(bannerParam); + BaseRspDTO bannerBaseRspDTO = new BaseRspDTO(); + bannerBaseRspDTO.setKey(getTaskType()); + bannerBaseRspDTO.setData(bannerDTO); + return bannerBaseRspDTO; + } +} + +... +``` +Ȼ⼸ʵ࣬ô```spring```أ ǿʵ```ApplicationContextAware```ӿڣѲԵʵע뵽һmapȻ󷽲ͬIJ(DTOͣȥʵֲͬIJáʵڹģʽ˼롣£ + +``` +/** + * Թ + **/ +@Component +public class TaskStrategyFactory implements ApplicationContextAware { + + private Map map = new ConcurrentHashMap<>(); + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + Map tempMap = applicationContext.getBeansOfType(IBaseTask.class); + tempMap.values().forEach(iBaseTask -> { + map.put(iBaseTask.getTaskType(), iBaseTask); + }); + } + + public BaseRspDTO executeTask(String key, AppInfoReq req) { + IBaseTask baseTask = map.get(key); + if (baseTask != null) { + System.out.println("ʵִ"); + return baseTask.execute(req); + } + return null; + } +} +``` + +˲Թ```TaskStrategyFactory```ٻŻ```BaseTaskCommand```Ĵ롣ĹѾҪ```IUserService userService, IBannerService bannerService, ILabelService labelService```ֻҪԹ```TaskStrategyFactory```ɡͬʱҲҪ```if...else...```жˣòԹ```TaskStrategyFactory```漴ɡŻĴ£ + +``` +public class BaseTaskCommand implements Callable> { + + private String key; + private AppInfoReq req; + private TaskStrategyFactory taskStrategyFactory; + + public BaseTaskCommand(String key, AppInfoReq req, TaskStrategyFactory taskStrategyFactory) { + this.key = key; + this.req = req; + this.taskStrategyFactory = taskStrategyFactory; + } + + @Override + public BaseRspDTO call() throws Exception { + return taskStrategyFactory.executeTask(key, req); + } +} +``` + +```appҳϢ```ѯͿŻ£ + +``` +public AppHeadInfoResponse parallelQueryAppHeadPageInfo2(AppInfoReq req) { + long beginTime = System.currentTimeMillis(); + System.out.println("ʼвѯappҳϢհ汾ʼʱ䣺" + beginTime); + List>> taskList = new ArrayList<>(); + //ûϢѯ + taskList.add(new BaseTaskCommand("userInfoDTO", req, taskStrategyFactory)); + //bannerѯ + taskList.add(new BaseTaskCommand("bannerDTO", req, taskStrategyFactory)); + //ǩѯ + taskList.add(new BaseTaskCommand("labelDTO", req, taskStrategyFactory)); + + ExecutorService executor = Executors.newFixedThreadPool(10); + List> resultList = parallelInvokeCommonService.executeTask(taskList, 3, executor); + + if (resultList == null || resultList.size() == 0) { + return new AppHeadInfoResponse(); + } + + UserInfoDTO userInfoDTO = null; + BannerDTO bannerDTO = null; + LabelDTO labelDTO = null; + + for (BaseRspDTO baseRspDTO : resultList) { + if ("userInfoDTO".equals(baseRspDTO.getKey())) { + userInfoDTO = (UserInfoDTO) baseRspDTO.getData(); + } else if ("bannerDTO".equals(baseRspDTO.getKey())) { + bannerDTO = (BannerDTO) baseRspDTO.getData(); + } else if ("labelDTO".equals(baseRspDTO.getKey())) { + labelDTO = (LabelDTO) baseRspDTO.getData(); + } + } + + System.out.println("вѯappҳϢհ汾,ܺʱ" + (System.currentTimeMillis() - beginTime)); + return buildResponse(userInfoDTO, bannerDTO, labelDTO); + } +``` + + +## 5. ˼ܽ + +ϴŻѾܼǻûбŻ˼·ء +> ʵеģ磬Ψһǵ```key```Ϊö٣дַ```"userInfoDTO""bannerDTO""labelDTO"```У```CompletionService```ЩСϲ```CompletableFuture```ʵвеá + +ĴѧЩ֪ʶأ +1. ŻӿܣijЩ£ʹòеô洮С +2. ʵֲеأ ʹ```CompletionService``` +3. ѧĺ˼άǣ ճУҪѧȡͨõķ߹ߡ +4. ģʽ͹ģʽӦ + +ĵĻģʽ黹ǺϸȻһƪҽдϣȡģʽĹȻҪĵĻԹעҵĹںţ**ݵСк**ҵϵʽ + + + + + diff --git "a/\345\244\247\345\216\202\351\235\242\350\257\225\347\234\237\351\242\230/README.MD" "b/\345\244\247\345\216\202\351\235\242\350\257\225\347\234\237\351\242\230/README.MD" new file mode 100644 index 0000000..04f4506 --- /dev/null +++ "b/\345\244\247\345\216\202\351\235\242\350\257\225\347\234\237\351\242\230/README.MD" @@ -0,0 +1,13 @@ +## 1. 面试真题 + +关注公众号:捡田螺的小男孩 +​ +- [oppo后端16连问](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498750&idx=1&sn=19fe8b4fff28fe81db14e733053bbc74&chksm=cf2224d7f855adc1d0984980a4e3de31fe33329164a472ca8d8255a8a80b69b2e23850811323&token=2001057130&lang=zh_CN#rd) +- [小厂后端十连问(附答案)](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498316&idx=1&sn=7749b78293b7b2af51eda99844e08a56&chksm=cf222565f855ac7324232e2af459f8b6e6eb5fd5b272c2b29bda08cc579421b6704a0de94b2e&token=2001057130&lang=zh_CN#rd) +- [腾讯云后端15连问!](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498171&idx=1&sn=f5a7ec25a569822be0f73fbcd413e8ba&chksm=cf222692f855af84fba419166fcd4235c0e78af3a2e1ec4c723a4efb1bd1ad6f8a5b9404c599&token=2001057130&lang=zh_CN#rd) +- [社招后端21连问(三年工作经验一面)](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498084&idx=1&sn=96c8148cfeeeb16668ed9e03fa9131cc&chksm=cf22264df855af5b6e81b93738cca28989226a53ec702fcfaa0cc5004dded4208c5ee5ea844a&token=2001057130&lang=zh_CN#rd) +- [一份热乎乎的字节面试真题](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497742&idx=1&sn=18765e7356f446a7f2521f45b467d5d3&chksm=cf222727f855ae31dd2029e3219814211336c41d9228d271a583d3691ddadca586529aca9302&token=2001057130&lang=zh_CN#rd) +- [面试必备:虾皮服务端15连问](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497256&idx=1&sn=3b799c2d514aa25e85a6faa60d639a0b&chksm=cf222901f855a017b73356b99b830b8800a7a9172fab891c5759d8dd69a270872ea9480c0b7c&token=2001057130&lang=zh_CN#rd) +- [宇宙条一面:十道经典面试题解析](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247495342&idx=1&sn=54e1c0c16a6467001524c34818025331&chksm=cf223187f855b89140db5ca429e6efc19d0111abf7f36b78a0ecd73b00fded1ff1e7ba32a6f1&token=2001057130&lang=zh_CN#rd) +- [蚂蚁金服一面:十道经典面试题解析](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247493270&idx=1&sn=1c78a81d6e1bd0f0fd947fe8c3a33e32&chksm=cf2239bff855b0a9627855f20a17799e0506eb7548a409bfa0ee0450328d7519ec70f7b962cc&token=2001057130&lang=zh_CN#rd) +- [田螺精品面试PDF发布](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499943&idx=1&sn=fe869c0a97a306e42830336fe74e17a6&chksm=cf221f8ef8559698781709bfbccbb85087286e48434905fb18bec3a3ec0af7329c2a1632c230&token=1990771297&lang=zh_CN#rd) \ No newline at end of file diff --git "a/\345\267\245\344\275\234\346\200\273\347\273\223/READEME.MD" "b/\345\267\245\344\275\234\346\200\273\347\273\223/READEME.MD" new file mode 100644 index 0000000..6c258b9 --- /dev/null +++ "b/\345\267\245\344\275\234\346\200\273\347\273\223/READEME.MD" @@ -0,0 +1,17 @@ +## 工作总结 + +- [工作总结!日志打印的15个建议](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247494838&idx=1&sn=cdb15fd346bddf3f8c1c99f0efbd67d8&chksm=cf22339ff855ba891616c79d4f4855e228e34a9fb45088d7acbe421ad511b8d090a90f5b019f&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [25种代码坏味道总结+优化示例](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490148&idx=1&sn=00a181bf74313f751b3ea15ebc303545&chksm=cf21c54df8564c5bc5b4600fce46619f175f7ae557956f449629c470a08e20580feef4ea8d53&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [聊聊日常开发中,如何减少bug呢?](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490662&idx=1&sn=d38a090611af7f64ee3c6a31331d5228&chksm=cf21c34ff8564a59e505e6edf3065a0fc506c6d2c96f492c8d8873cd46dedbe0704e43cb9c2e&token=1990771297&lang=zh_CN#rd) +- [工作四年,分享50个让你代码更好的小建议](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488708&idx=1&sn=6e2e0a740f5d42a59641487a0bf1e3bf&chksm=cf21cbedf85642fbb485fa1c7bf9af21923d8503f2542b6f8283ce79ddc683f7d9e45da83100&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [写代码有这16个好习惯,可以减少80%非业务的bug](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488097&idx=1&sn=eaca1f92ca3ccd9de00dbc4ef3e4029a&chksm=cf21cd48f856445e4cc24c1f8bcf18d1479bad0a37a87a2fb70717d8a4e65dcf7b4d5f83d24f&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [Java日常开发的21个坑,你踩过几个?](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488115&idx=1&sn=bdd4a4ca36bc7ea902106d058e8537fb&chksm=cf21cd5af856444cb36af600705615454b0aaa2b289b97ddb52d594556ac07a1915b73ecce19&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [CAS乐观锁解决并发问题的一次实践](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487937&idx=1&sn=206a37bf6d6a7aa1d05674c479ed7a72&chksm=cf21cee8f85647fe7a082049a41c0f640f54976d2cdf4302b24c5517ca42b854eb84b13ece10&token=1990771297&lang=zh_CN#rd) +- [写代码有这些想法,同事才不会认为你是复制粘贴程序员](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487961&idx=1&sn=e646231067968d9f58e6665914293f9a&chksm=cf21cef0f85647e6f3ff2feece004ac3bd979e37fe45103c88d0f299dfe632a5cf6dd547c1d9&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [程序员必备:Java日期处理的十个坑](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487973&idx=1&sn=0f713413098fb579e5f200b829f71e89&chksm=cf21ceccf85647da450765d79bf5943da551c3be950447063b9f8c77c21bf2a39b99387a949b&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [内存泄漏问题的分析和解决方案](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487986&idx=1&sn=d681a585ac489703788e3baa48eb9aa3&chksm=cf21cedbf85647cd23bbab9dfec63e6877f83c34efb19bd16075d5d90fea91d3f4a20fc77921&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [程序员必备基础:加签验签](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488022&idx=1&sn=70484a48173d36006c8db1dfb74ab64d&chksm=cf21cd3ff8564429a1205f6c1d78757faae543111c8461d16c71aaee092fe3e0fed870cc5e0e&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [记一次接口性能优化实践总结:优化接口性能的八个建议](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488004&idx=1&sn=00840efd9c0bd0a7f172b59eb2ca130f&chksm=cf21cd2df856443bf21d8e09cfe5c8452ecaf82e3c2210fca3b28829ded04defddcf63c0a59b&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [程序员必备基础:如何安全传输存储用户密码?](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488117&idx=1&sn=5d3d0eda0ed45f3f576e211de31ca3a9&chksm=cf21cd5cf856444af1407a94a2abf445265ca7c5f5855cfa1c223cb209e99040c7889621f231&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [一次代码优化实践,用了模板方法+策略+工厂方法模式](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488061&idx=1&sn=1d9ab7954b03521ab81ecf033c0e5e50&chksm=cf21cd14f8564402b213f0ef908bbdb0e12fed4b281c5803b8e539cacb1551654194becfb7d6&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [保证接口数据安全的10种方案](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247500285&idx=1&sn=7d0723f25d46e858859cfd79acb6fb9d&chksm=cf221ed4f85597c2093f81baa5fdedc65817bf2d23a7951236836b0f54c2335695cbed61cd13&token=1990771297&lang=zh_CN#rd) \ No newline at end of file diff --git "a/\345\267\245\344\275\234\346\200\273\347\273\223/\346\227\245\345\277\227\346\211\223\345\215\260\350\247\204\350\214\203.md" "b/\345\267\245\344\275\234\346\200\273\347\273\223/\346\227\245\345\277\227\346\211\223\345\215\260\350\247\204\350\214\203.md" new file mode 100644 index 0000000..4577332 --- /dev/null +++ "b/\345\267\245\344\275\234\346\200\273\347\273\223/\346\227\245\345\277\227\346\211\223\345\215\260\350\247\204\350\214\203.md" @@ -0,0 +1,269 @@ +## ǰ + +Һã**ݵСк**־ǿٶλĺð֣**˺ƺ˦**ӡ־dzҪ**־ӡ**15ý~ + +- ںţ**ݵСк** + + +## 1. ѡǡ־ + +־5ֱ֣errorwarninfodebugtraceճУҪѡǡ־𣬲Ҫ־Ǵӡinfo~ + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c4502943568747e79ac4091b4d2868ea~tplv-k3u1fbpfcp-zoom-1.image) + +- error־ָȽصĴ󣬶ҵӰ죬Ҫ**άüص** +- warn־һĴ󣬶ҵӰ첻󣬵Ҫ**ע** +- infoϢ־¼ŲĹؼϢʱ䡢εȵȣ +- debugڿDEBUGģؼ߼ʱݣ +- traceϸϢһЩϢֻ¼־ļС + + +## 2. ־ҪӡΡ + +DzҪӡܶܶ־ֻҪӡ**ٶλЧ־**Ч־˦ + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c59f66bfc09d42ffa8528c16145952b8~tplv-k3u1fbpfcp-zoom-1.image) + +Щõ**Чؼ**־أ˵ʱ򣬴ӡ****Ȼأڷصʱ򣬾**ӡΣֵ**εĻһ**userIdbizSeqЩؼ**Ϣ£ + +``` +public String testLogMethod(Document doc, Mode mode){ + log.debug(method enter param{},userId); + String id = "666"; + log.debug(method exit param{},id); + return id; +} +``` + + +## 3. ѡʵ־ʽ + +־ʽӦЩϢ統**ǰʱ**һ뾫ȷȣ**־****߳**ȵȡlogback־ôã + +``` + + + %d{HH:mm:ss.SSS} %-5level [%thread][%logger{0}] %m%n + + +``` + +ǵ־ʽǰʱ䶼]м¼**ʱ㶼֪** + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6ecfebbe1a0b411e8186d46edaddbd38~tplv-k3u1fbpfcp-zoom-1.image) + + +## 4. if...else...ʱÿ֧жӡ־ + +**if...else...switch**ʱڷ֧оʹӡ־ŲʱͿͨ־ȷĸ֧߼ҲŲˡ + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/60bc12dfb6324c089b86a9dc05acc2f3~tplv-k3u1fbpfcp-zoom-1.image) + + + +``` +if(user.isVip()){ + log.info("ûǻԱ,Id:{},ʼԱ߼",user,getUserId()); + //Ա߼ +}else{ + log.info("ûǷǻԱ,Id:{},ʼǻԱ߼",user,getUserId()) + //ǻԱ߼ +} +``` + +## 5.־Ƚϵʱ־ж + +trace/debugЩȽϵ͵־𣬱־Ŀжϡ + + +``` +User user = new User(666L, "ں", "ݵСк"); +if (log.isDebugEnabled()) { + log.debug("userId is: {}", user.getId()); +} +``` + +Ϊǰµ־룺 +``` +logger.debug("Processing trade with id: " + id + " and symbol: " + symbol); +``` + +**õ־warn**Ļ־ӡǻִַƴӲ```symbol```Ƕ +ִ```toString()```˷ϵͳԴִ־ȴûдӡ˽**־жϡ** + +## 6. ֱʹ־ϵͳLog4jLogbackе APIʹ־SLF4JеAPI + +SLF4J ģʽ־ܣά͸־ʽͳһҿڱ֤޸Ĵ£ܷʵֵײ־ܵĸ + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9846b8d9ddd2485483e41b7134954f91~tplv-k3u1fbpfcp-zoom-1.image) + + +``` +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +private static final Logger logger = LoggerFactory.getLogger(TianLuoBoy.class); +``` + +## 7. ʹòռλ{}+ƴӡ + + +``` +logger.info("Processing trade with id: " + id + " and symbol: " + symbol); +``` + +Уʹ```+```ַƴӣһ**** + +£ +``` +logger.info("Processing trade with id: {} and symbol : {} ", id, symbol); +``` +ʹ˴```{}```Ϊ־еռλʹ```+```żࡣң**ڷ**ʹռλ滻Чܡ + +## 8. ʹ첽ķʽ־ + +- ־ջļеģIOܻҪġ첽ͿIOܡ +- ҪҪȻʹ첽ķʽ־logbackΪɣҪ첽ܼ򵥣ʹAsyncAppender +``` + + + +``` + +## 9. Ҫʹe.printStackTrace() + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e2aeaca5e0f44c08ad25fb92e75222dc~tplv-k3u1fbpfcp-zoom-1.image) + + + +``` +try{ + // ҵ봦 +}catch(Exception e){ + e.printStackTrace(); +} +``` + +``` +try{ + // ҵ봦 +}catch(Exception e){ + log.error("ij쳣",e); +} +``` + +**ɣ** + +- e.printStackTrace()ӡĶջ־ҵ־ǽһģͨŲ쳣־̫㡣 +- e.printStackTrace()ַ¼ǶջϢϢַ̫̫࣬ڵڴûпռ,ڴˣôûͿס~ + +## 10. 쳣־Ҫֻһ룬ҪȫϢ + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/420f0da65bac44b5b340a96facfd5c11~tplv-k3u1fbpfcp-zoom-1.image) + +1 + +``` +try { + //ҵ봦 +} catch (Exception e) { + // + LOG.error('ij쳣'); +} + +``` +- 쳣eûдӡѹ֪ʲô͵쳣 + +2 +``` +try { + //ҵ봦 +} catch (Exception e) { + // + LOG.error('ij쳣', e.getMessage()); +} +``` + +- ```e.getMessage()```¼ϸĶջ쳣Ϣֻ¼ϢŲ⡣ + + + +``` +try { + //ҵ봦 +} catch (Exception e) { + // + LOG.error('ij쳣', e); +} +``` + +## 11. ֹϻ debug + +ֹϻdebugһdzҪ + + +Ϊһϵͳdebug־ܶ࣬ҸֿҲʹ debug־Ͽdebugÿܻ̣ӰҵϵͳС + +## 12.Ҫ¼쳣׳쳣 + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/671289ecaa4b4eb39dca1139b657f8cd~tplv-k3u1fbpfcp-zoom-1.image) + + +£ +``` +log.error("IO exception", e); +throw new MyException(e); +``` + +- ʵֵĻͨջϢӡΡΪMyException쳣ĵطٴӡһΡ +- ־¼߰װ׳ȥҪͬʱʹã־˺Ի + + +## 13.ظӡ־ + +ظӡ־ϻ˷Ѵ̿ռ䡣Ѿһ־˼**ӡ**£ + +``` +if(user.isVip()){ + log.info("ûǻԱ,Id:{}",user,getUserId()); + //࣬Ըǰ־ϲһ + log.info("ʼԱ߼,id:{}",user,getUserId()); + //Ա߼ +}else{ + //ǻԱ߼ +} +``` + +ʹlog4j־ܣ```log4j.xml``` additivity=falseΪԱظӡ־ + + +``` + +``` + +## 14.־ļ + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/12a2cbe6cf7f4ba981ba7103f9d81858~tplv-k3u1fbpfcp-zoom-1.image) + + +- ǿ԰Ѳͬ͵־ȥaccess.logerrorerror.logԵӡһļ档 +- ȻҲԸݲͬҵģ飬ӡͬ־ļŲͳƵʱ򣬶ȽϷ + + +## 15. Ĺģ飬ӡ־ + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c6f26259cda042edb98400145d208d12~tplv-k3u1fbpfcp-zoom-1.image) + + +- ճУĻ߼ӵĴ룬ϸעͣԼϸ־ +- ־ҪϸأԶһ£ĺijһˣͨ־ԶλǾͿ + + + + + + diff --git "a/\345\267\245\344\275\234\346\200\273\347\273\223/\350\201\212\350\201\212\346\227\245\345\270\270\345\274\200\345\217\221\344\270\255\357\274\214\345\246\202\344\275\225\345\207\217\345\260\221bug\345\221\242\357\274\237.md" "b/\345\267\245\344\275\234\346\200\273\347\273\223/\350\201\212\350\201\212\346\227\245\345\270\270\345\274\200\345\217\221\344\270\255\357\274\214\345\246\202\344\275\225\345\207\217\345\260\221bug\345\221\242\357\274\237.md" new file mode 100644 index 0000000..0c47dce --- /dev/null +++ "b/\345\267\245\344\275\234\346\200\273\347\273\223/\350\201\212\350\201\212\346\227\245\345\270\270\345\274\200\345\217\221\344\270\255\357\274\214\345\246\202\344\275\225\345\207\217\345\260\221bug\345\221\242\357\274\237.md" @@ -0,0 +1,663 @@ +## ǰ + +Һѽ~ ǼݵСкճУμbugĽ**ݿ⡢桢ʹƪ**3ܽһ60ע㣬ҳΪ֮ǡ +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/41bd0d208d054f87a99f6c7df514f35d~tplv-k3u1fbpfcp-zoom-1.image) + +- ӭעںţ**ݵСк** +- [githubַ](https://github.com/whx123/JavaHome)лÿһstar + +## 1. ݿƪ + +![ѯ](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a05dccf50dc3403c8c665d3395cdcc91~tplv-k3u1fbpfcp-zoom-1.image) + +ݿƪĻЩط׵bugأܽ7棺**ѯݿֶע㡢ʧЧijӳ١ݼݡһЩSQLע** + +### 1.1 ѯ + +![ѯ.gif](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8d38c462aa484b47b9fcfded5f4f2140~tplv-k3u1fbpfcp-watermark.image) + +#### 1.1.1 Ƿ +ѯϾͻ뵽һSQLûûĻͻѯ + +**ЩʧЧ** + +- ѯorܵʧЧ +- ֶַwhereʱһʧЧ +- likeͨܵʧЧ +- ѯʱвеĵһУʧЧ +- ʹmysqlúʧЧ +- 㣨磬+-*/ʧЧ +- ֶʹã= < >not inʱܻᵼʧЧ +- ֶʹis null is not nullܵʧЧ +- ӲѯӲѯѯֶαʽһܵʧЧ +- mysqlʹȫɨҪʹ,ʹ + + +#### 1.1.2 󣬿Ƿֱֿ + +̫󣬾ͻӰSQLִܡ֪ݽṹһB+һø߶Ϊ3B+ſԴ洢ǧݡĻB+Ҫߣѯܻ½ + +ˣʱ򣬽ֱֱֿֿм**mycatsharding-jdbc** + + +#### 1.1.3 SQL + +ճУ߼ܶ಻SQLһSQLȻ**6**,̫ӰѯܣٱһȻ**10**ȵȡǻή˲͸SQLܣһ㲻̫࣬һ㲻ܳ + + +### 1.2 ݿֶע + +ݿֶݣ׳bug磬Ի޸˱ṹijֶΣǰѽűǷ϶ˡ + +#### 1.2.1 ֶǷᳬ + +ݿֶǣ + +``` +`name` varchar(255) DEFAULT NOT NULL +``` + +˱nameֶγ300Dzʱ****ˡҪУֶֹγ + +#### 1.2.2 ֶΪգǷᵼ¿ָ + +ݿֶεʱ,ֶΪ**not null** + +- Σһʹ0-1ΪĬֵ +- ַĬϿַ + +ݿֶΪ```NULL```ֵ׵³ָ룻ݿֶΪ```NULL```ֵҪע**count()** ʹãпӡ + +#### 1.2.3 ֶȱʧ + +ǵճڲԻԱ޸ģһֶΣҪSQLűֶȱʧ + + +#### 1.2.4 ֶǷֱ֧ + +һֶҪֱ֧洢ʹ**utf8mb4** + +#### 1.2.5 ʹtextblobֶ + +Ҫһֶδ洢ļ**洢ļ·**ļȥʹtextʱ漰ѯʱעⴴ**ǰ׺** + +### 1.3 ʧЧij + +#### 1.3.1 @Transactional ڷpublicεķʧЧ + + +@Transactionalע⣬ڷpublicεķϣDzЧġspringǽAOP˼룬Ҳ̬ͨʵֵġspringԼڵö̬֮ǰѾԷpublicˣԷpublicЧ + +#### 1.3.2 طֱӵ + @TransactionalҲЧ +``` +public class TransactionTest{ + public void A(){ + //һ + //÷B (صãʧЧ) + B(); + } + + @Transactional + public void B(){ + // + } +} +``` + +#### 1.3.3 쳣try...catchˣʧЧ + + +``` +@Transactional +public void method(){ + try{ + //һ + insertA(); + //һ + updateB(); + }catch(Exception e){ + logger.error("쳣ˣʧЧ",e); + } +} + +``` + +#### 1.3.4 rollbackForô + +SpringĬ׳δ```unchecked```쳣̳RuntimeException 쳣ErrorŻع쳣ᴥع׳͵쳣Ҫָ```rollbackFor```ԡ + +#### 1.3.5 ײݿ治֧ + +MyISAM洢治֧InnoDb֧ + +#### 1.3.6 springҵ߼һ߳ + +ҵҪspringԴͬһ߳УŻspringĿơ룬motheḍ߳ڲִеmothedspringĿƣһҪע⡣ΪspringʵʹThreadLocalʵͬһ߳ݹ + +``` +@Transactional +public void mothed() { + new Thread() { + + }.start(); +} +``` + + +### 1.4 + +ָͬһԴ໥ռãԷԴӶ¶ѭ + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3513a3fd3ef64e318f157dd51ec280ef~tplv-k3u1fbpfcp-zoom-1.image) + + +MySQLڲһƣһعһһִȥ**Դʽ̵͡òȷ**Σ + +#### 1.4.1 9SQL + +ҪҪѧһSQLļνе?һSQLԷ9֣̽ + +- һidRC뼶 +- ϶idǶΨһRC뼶 +- idǶΨһRC뼶 +- ģidûRC뼶 +- 壺idRR뼶 +- idǶΨһRR뼶 +- ߣidǶΨһRR뼶 +- ϰˣidûRR뼶 +- ϾţSerializable뼶 + + +#### 1.4.2 η + +IJ£ + +- ģ +- show engine innodb status;鿴־ +- ҳSQL +- SQLȥ +- ־ʲôȴʲô +- ϤģʽݾInnoDB洢ļԾ + +ȤС飬Կ֮ǰдƪ£[ְֽMysql](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487979&idx=1&sn=588c83d77a8851f3b3c18cd68ed9c454&chksm=cf21cec2f85647d4a77cc239ae9a4cfd31bb8832be3d98540a08ea8b4a1f46b38cf736210a02&token=1327808550&lang=zh_CN#rd) + + +### 1.5 ӳ⿼ + +Ȳ룬žȥѯ,߼Ƚϳܻġһݿⶼ⣬ӿġдĻд⣬һǶӿ⡣ӳ٣ܿܳɹˣѯ + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/560555c31cfe42a0b07dd9bcad24c0e1~tplv-k3u1fbpfcp-zoom-1.image) + + +#### 1.5.1 ҪǿһԣǶ + +ҪҵҪǿһԣֱӶ + +#### 1.5.2 Ҫǿһԣӿ + +һҵ񣬿ԽܶݵݲһµĻȿǶӿ⡣ΪӿԷֵĶдѹϵͳܡ + +### 1.6 ݼ + +#### 1.6.1 ¼ӵֶΣǴݵĬֵ + +ճУҵҪijݿӸֶΡijAPPñҪӸֶΣ```scene_type```,öֵ ```010203```ǾҪҵ룬ӵֶΣʲôĬֵΪջĬ01Ϊ```NULL```ĻҪÿָ봦 + +#### 1.6.2 ҵϵֶΣݵֵǷп + +ǿУҪݿֶΣдݣǾҪϴݿֵǷпӡDZиuser_role_code ֶΣϵУöֵ ``` 01Ա 02Ա 03һû```ҵ**һû**Ϊ**03ѯû04û**ڿУҪݵ + +### 1.7 һЩSQLľע + +#### 1.7.1 limitҳ + +limitҳһdzSQL⣬һ3ֶӦĽ + +**һ** idģϴβѯ¼(ƫ)limit + + +``` +select id,name from employee where id>1000000 limit 10. +``` + +**:** ҵҳ + +ҵۣûбҪôķҳΪû̫ҳȸҳҲҳ˲limitҳ⡣ + +**** ӳٹӲѯŻҳȿٶλҪȡidΣȻٹ + +``` +SELECT a.* FROM employee a, (select id from employee where LIMIT 1000000,10 ) b where a.id=b.id +``` + +#### 1.7.2 ޸ġѯʱǷС + +Ǹ»߲ѯݿʱѭȥݿ⣬ԿǷСҪ10ݵĻһβ500 + +**** +``` +remoteBatchQuery(param); +``` +**** + +``` + +for(int i=0;i<100000;i++){ + remoteSingleQuery(param) +} +``` + + +## 2. ƪ + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/819c4665e0064db5bb3441c5bee4cb7a~tplv-k3u1fbpfcp-zoom-1.image) + +### 2.1 ϸ + +![ϸ.gif](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/aaa1fee8efa745d39a2ef869caa55b4f~tplv-k3u1fbpfcp-watermark.image) + +#### 2.1.1 Ϳָ + +DZʱҪע͵Ŀָ + +- װ͵Ŀָ +- õĿָ +- EqualsߵĿָ +- ConcurrentHashMap ֧ k-vΪ null +- ϣֱӻȡԪ +- ֱӻȡ + + +``` +if(object!=null){ + String name = object.getName(); +} +``` + +#### 2.1.2 ̳߳ʹע + +- ʹ Executors.newFixedThreadPoolܻOOM⣬Ϊʹõ޽ +- ʹԶ̳߳أø̳߳һŲ +- ͬҵ̳߳ظ룬еҵһ̳߳ء +- ̳߳쳣ҪǺ + +#### 2.1.3 ԰ȫļϡ + +ڸ߲£```HashMap```ܻѭΪǷ԰ȫģԿʹ```ConcurrentHashMap```ʹЩϵʱҪעDz԰ȫġ + +- HashmapArraylistLinkedListTreeMapȶԲȫģ +- VectorHashtableConcurrentHashMapȶ԰ȫ + +#### 2.1.4 ڸʽȵ + +ճҪڸʽأΪYYYYдʱпӵŶ + + +``` +Calendar calendar = Calendar.getInstance(); +calendar.set(2019, Calendar.DECEMBER, 31); + +Date testDate = calendar.getTime(); + +SimpleDateFormat dtf = new SimpleDateFormat("YYYY-MM-dd"); +System.out.println("2019-12-31 ת YYYY-MM-dd ʽ " + dtf.format(testDate)); +``` +н + +``` +2019-12-31 ת YYYY-MM-dd ʽ 2020-12-31 +``` + +нҲȽϳҪע⾫⣺ + + +``` +public class DoubleTest { + public static void main(String[] args) { + System.out.println(0.1+0.2); + System.out.println(1.0-0.8); + System.out.println(4.015*100); + System.out.println(123.3/100); + + double amount1 = 3.15; + double amount2 = 2.10; + if (amount1 - amount2 == 1.05){ + System.out.println("OK"); + } + } +} + +``` +н + + +``` +0.30000000000000004 +0.19999999999999996 +401.49999999999994 +1.2329999999999999 +``` + + + +#### 2.1.5 ļ + + +ȡļʱ򣬲Ҫ```Files.readAllBytes```ֱӶڴ棬OOMģʹ```BufferedReader ```һһʹ```NIO``` + + +#### 2.1.6 ʹIOԴҪر + + +ʹtry-with-resourceдļҪر + +``` +/* + * עںţݵСк + */ +try (FileInputStream inputStream = new FileInputStream(new File("jay.txt")) { + // use resources +} catch (FileNotFoundException e) { + log.error(e); +} catch (IOException e) { + log.error(e); +} +``` + + +#### 2.1.7 try...catch쳣ʹõһЩ + +- Ҫʹe.printStackTrace()ӡַܵڴռռ +- catch쳣ʹlogӡ +- ҪһException׽пܵ쳣 +- ҪѲ쳣ҵ߼ + + +#### 2.1.8 Ȳѯٸ/ɾIJһ + + +ճУִʵ־ɼȲѯǷʣõƱȥƱ + + +``` +if(selectIsAvailable(ticketId){ + 1deleteTicketById(ticketId) + 2ֽӲ +}else{ + return ûпֽȯ +} +``` + +DzִУܿģӦݿ/ɾԭԣ£ + +``` +if(deleteAvailableTicketById(ticketId) == 1){ + 1ֽӲ +}else{ + return ûпֽȯ +} +``` + + +### 2.2 ṩӿ + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/818d79dfadab43e5a2bddf26a3ea2870~tplv-k3u1fbpfcp-zoom-1.image) + + +#### 2.2.1 УϷ + +ṩĽӿڣṩͻˡǰˣֻDZϵͳãҪУһεĺϷԡ + +> ݿֶΪvarchar(16),Էһ32λַ㲻Уȣݿֱ쳣ˡ + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4f4649f1bb3b43418ef808b8c5599c76~tplv-k3u1fbpfcp-watermark.image) + +#### 2.2.2 Ͻӿڼ + +ܶbugΪ޸˶ϽӿڣȴݵµġؼDZȽصģֱӵϵͳʧܵġֳԱ׷Ŷ~ + +иdubboķֲʽӿڣ޸ΣҪϽӿڼݡԭֻABһCͿԿ + + +``` +//Ͻӿ +void oldService(A,B){ + //½ӿڣnullC + newService(A,B,null); +} + +//½ӿڣʱɾϽӿڣҪݡ +void newService(A,B,C); +``` + + + +#### 2.2.3 ֹѹϵͳ + +˲ĴѹϵͳΪ˱ǵϵͳһҪʹ**guava ratelimiter** Ҳð↑Դ**Sentinel** + +#### 2.2.4 ӿڰȫԣǩǩȨ + + +ת˵͵ĽӿڣһҪעⰲȫԡһҪȨ**ǩǩ**Ϊûױݻ + + +#### 2.2.5 ǽӿݵ + +ӿҪݵԵģתЩҪӿڡֱ۵ҵ񳡾**ûŵ**Ľӿûholdס + +> 1. ݵȣidempotentidempotenceһѧѧڳС +> 2. ڱ.һݵȲصִӰһִеӰͬݵȺݵȷָʹͬظִУܻͬĺ + + +һ㡸ݵȼ⼸: + +1. ѯ +2. Ψһ +3. tokenƣֹظύ +4. ݿdeleteɾ +5. ֹ +6. +7. Rediszookeeper ֲʽǰRedisֲʽ +8. ״̬ݵ + +![ӿݵ.gif](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/55e09e293249431a85d68f8b217d9a8d~tplv-k3u1fbpfcp-watermark.image) + +### 2.3 õӿ + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/41e0a0d34083431ca0d44f3354dca2f5~tplv-k3u1fbpfcp-zoom-1.image) + +#### 2.3.1 ʱ + +ǵñ˵Ľӿڣʱôأ + +> ٸӣǵһԶת˽ӿڣAͻBͻת100򣬳ɹʱͰѱתˮΪɹʧܵʱͰѱˮΪʧܡתϵͳʱأôأΪɹʧأ**ʱҪǺ**ҪȻʽʧˡֳ£ӿڳʱǾͿ**±תˮ**״̬·ѯԶת󣬲ѯת˳ɹļ¼ٸ±״̬״̬ + + + +#### 2.3.2 Ի + +ǵһԶhttpdubboӿڣʧˣǿԿԻơʱ·һ£ӿھ͵ʧˣԻƿû顣ԻҪЩӿڲ֧ݵȣͲʺԵġ + +#### 2.3.3 Ƿ񽵼 + + +ϵͳһṩעķûעɹ֮󣬵ԶAӿڷţԶBӿڷʼע״̬Ϊɹ + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d2a2180e624d4f8fadcf8fc8f63651bf~tplv-k3u1fbpfcp-zoom-1.image) + + +ýӿBʼʧܣûעʧܣҵܾͲͬˡʱǿԿǸBӿ****ṩ****Ҳ˵BӿʧܣȲʼûעɹʱʼͺ + +#### 2.3.4 Ƿ첽 + +һʹϸСڵ**ûע**ӡǿԿ첽߳ȥAӿڷţ첽BӿڷʼǼʹABӿڵʧܣǻǿԱ֤ûעɹ + +ѷЩ֪ͨӿڣŵ첽̴߳ԽͽӿںʱûŶ + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/07eef178cfe04048ade9fbed2f465d12~tplv-k3u1fbpfcp-zoom-1.image) + + + +#### 2.3.5 ӿ쳣 + +ǵһԶ̽ӿڣһҪ˼£˽ӿ쳣ҪôôףԻǵʧܣô֤ݵһԵȵȡ + + +## 3. ƪ + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f84d96671e8e451d936e110a53bf9cf6~tplv-k3u1fbpfcp-zoom-1.image) + +### 3.1 ݿ뻺һ + +ʹû棬Խͺʱṩϵͳܡǣʹû棬һԵ⡣ + +#### 3.1.1 ֻʹģʽ + +- Cache-Aside Pattern·ģʽ +- Read-Through/Write-Throughд͸ +- Write- behind 첽д룩 + +һʹû棬**·ģʽ**: + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/38f7efc4d066409dbf65a56eb10eb90e~tplv-k3u1fbpfcp-zoom-1.image) + + +- ʱȶ棬еĻֱӷ +- ûеĻȥݿ⣬ݿȡݣ뻺ͬʱӦ + +·ģʽд̣ +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c80f0df22739439088d6a47ced7b6ae0~tplv-k3u1fbpfcp-zoom-1.image) + + +#### 3.1.2 ɾأǸ»棿 + +ڲʱ򣬵Ӧɾ滹Ǹ»أӣ + + +![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b0a52a30ec994ca7b66cf83fba5398a2~tplv-k3u1fbpfcp-zoom-1.image) + + +1. ߳Aȷһдһȸݿ +2. ߳Bٷһдڶݿ +3. ԭ߳Bȸ˻ +4. ߳A»档 + +ʱ򣬻汣AݣݣݿⱣBݣݣݲһˣݳɾȡ»򲻻⡣ + + +#### 3.1.3 Ȳݿ⻹Ȳ + +˫д£Ȳݿ⻹Ȳ棿һӣABA²Bѯȡ + +![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/95b0b2cd05d34ff1b66a8aa0a768cc04~tplv-k3u1fbpfcp-watermark.image) + +1. ߳Aһдһdel cache +2. ʱ߳Bһcache miss +3. ߳BDBһ +4. Ȼ߳Bcache +5. ߳AдDBµ + +Ͼݿݲһˡ汣ݣݿⱣݡˣCache-AsideģʽѡȲݿȲ档 + + +#### 3.1.4 α֤һ + +- ʱ˫ɾ +- ɾԻ +- ȡbiglog첽ɾ + + + +### 3.2 洩͸ + +> 洩͸ָѯһһڵݣڻ治ʱҪݿѯ鲻д뻺棬⽫ڵÿҪݿȥѯݿѹ + +洩͸һ㶼⼸ģ**ҵ񲻺ơҵ/ά/ʧIJڿͷǷ󹥻** +α⻺洩͸أ һַ + +- ǷǷAPIڣ**ԲУ**˷Ƿֵ +- ѯݿΪգǿ**øֵĬֵ**дĻҪ»Ա֤һԣͬʱʵĹʱ䡣ҵϱȽϳãЧ +- ʹ**¡**жǷڡһѯʱͨ¡жֵǷڣڲż²顣 + +### 3.3 ѩ + +> ѩָݴʱ䣬ѯ޴ݿѹdown + +- ѩһڴͬʱɵģԭ򣬿ͨ**ùʱùʱɢһ**һϴ̶ֵ+һСֵ5Сʱ+01800뽴ϡ +- **Redis 崻Ҳ𻺴ѩ**ҪRedis߿üȺ + + +### 3.4 + +> ָȵkeyijʱڵʱ򣬶ǡʱKeyдIJӶdb + +е񻺴ѩʵǣѩָݿѹdownֻǴDBݿ档ΪǻѩһӼɡЩΪڻijһȵkey棬ѩǺܶkey + + +֣ + +1. **ʹû**ʧЧʱȥdbݣʹijЩɹصԭӲ(Redissetnxȥɹʱȥdbݿݺû档ȥԻȡ档 +2. **ڡ**ָûùʱ䣬ȵݿҪʱ첽߳ȥºùʱ䡣 + + +### 3.5 Key + +RedisУǰѷƵʸߵkeyΪȵkeyijһȵkey󵽷ʱر󣬿ܻᵼԴ㣬崻ӶӰķ + +νkey⣿ + +- **RedisȺ**ӷƬ +- **keyhashɢ**罫һkeyΪkey1,key2keyNͬNݣNݷֲͬƬʱNеһһֵ +- **ʹö**JVMػ,RedisĶ + +### 3.6 ڴ濼 + +#### 3.6.1 + +ʹõRedisRedisڴDZȽϰģDzҪʲôݶRedisһRedisֻѯȽƵݡͬʱҪRedisҲƵsetǣ˹ʱkeyʧЧ + +ʹõDZػ棬guavaıػ棬ҲҪ + + +#### 3.6.2 Redisİڴ̭ + +Ϊ˱Redisڴ治ãRedis8ڴ̭ԱԼ~ + +> - volatile-lruڴ治дʱ˹ʱkeyʹLRUʹã㷨̭ +> - allkeys-lruڴ治дʱkeyʹLRUʹã㷨̭ +> - volatile-lfu4.0汾ڴ治дʱڹڵkeyУʹLFU㷨ɾkey +> - allkeys-lfu4.0汾ڴ治дʱkeyʹLFU㷨̭ +> - volatile-randomڴ治дʱ˹ʱkeyУ̭ݣ +> - allkeys-randomڴ治дʱkey̭ݡ +> - volatile-ttlڴ治дʱ˹ʱkeyУݹʱ̭Խڵȱ̭ +> - noevictionĬϲԣڴ治дʱдᱨ + +#### 3.6.3 ͬҵ񳡾Redisѡʺϵݽṹ + +- аʺzset +- ûϢһhash +- ϢУбlist +- ûǩ罻һset +- ֲʽһString + +### 3.7 RedisһЩпӵ + +1. ʹ keysָ +2. O(n)Ӷhgetall +3. Redismonitor +4. ֹʹflushallflushdb +5. עʹdel + +## + +ܽ60bugıע㣬ճķϣԴа⣬ +עںţ**ݵСк**ظ**˼άͼ****ȡĵĸ˼άͼ** + + diff --git "a/\345\210\267leetcode\345\277\205\345\244\207\347\256\227\346\263\225/\347\234\213\344\270\200\351\201\215\345\260\261\347\220\206\350\247\243\357\274\232\345\212\250\346\200\201\350\247\204\345\210\222\350\257\246\350\247\243.md.bak" "b/\345\267\245\344\275\234\346\200\273\347\273\223/\350\201\212\350\201\212\346\227\245\345\270\270\345\274\200\345\217\221\344\270\255\357\274\214\345\246\202\344\275\225\345\207\217\345\260\221bug\345\221\242\357\274\237.md.bak" similarity index 100% rename from "\345\210\267leetcode\345\277\205\345\244\207\347\256\227\346\263\225/\347\234\213\344\270\200\351\201\215\345\260\261\347\220\206\350\247\243\357\274\232\345\212\250\346\200\201\350\247\204\345\210\222\350\257\246\350\247\243.md.bak" rename to "\345\267\245\344\275\234\346\200\273\347\273\223/\350\201\212\350\201\212\346\227\245\345\270\270\345\274\200\345\217\221\344\270\255\357\274\214\345\246\202\344\275\225\345\207\217\345\260\221bug\345\221\242\357\274\237.md.bak" diff --git "a/\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" "b/\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" new file mode 100644 index 0000000..e986b15 --- /dev/null +++ "b/\346\226\271\346\241\210\350\256\276\350\256\241/README.MD" @@ -0,0 +1,9 @@ +- [实现一个刷数任务,需要思考哪些维度?](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247508890&idx=1&sn=919b8a794eb4902d958ae13d1f424737&chksm=c1e05e16f697d700ee9f79e087279de6312222b8e45887d976a572b01599f1177b358ade265b&token=337310304&lang=zh_CN#rd) +- [手把手教你写设计方案](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247507937&idx=1&sn=33fd37f28675ce756e5d048b99254fcb&chksm=c1e0226df697ab7b4907fb2815c8dd2d195ea04c03a2f8fd0697c9a15a81fc639e5c5f7dab1b&token=337310304&lang=zh_CN#rd) +- [简易版,基于JWT 实现登录认证](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247508057&idx=1&sn=06b6fee69c63afbe7ebd2f81a3627341&chksm=c1e05dd5f697d4c32e38bcb58c2ecba8115ea7f94a17bc197bcb7b042a18ef07fef0f0e03878&token=337310304&lang=zh_CN#rd) +- [高并发系统设计的15个建议](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247508062&idx=1&sn=71e9647479ea71e8660d6ba48616c122&chksm=c1e05dd2f697d4c45ffd09e07fd40770e3d11591fa2b53161cd38da908cd55e41a38d5192605&token=337310304&lang=zh_CN#rd) +- [面试必备:聊聊分布式锁的多种实现!](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247506434&idx=1&sn=c6ae1ec19558626897295bbe41304b62&chksm=c1e0278ef697ae989b14f4746d1049be976d1d5744e4f9c7ec6e17d006f206edcc1c47a3e862&token=337310304&lang=zh_CN#rd) +- [并发环境下,先操作数据库还是先操作缓存?](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247508208&idx=1&sn=ac92523e33b478ad83560471338742f4&chksm=c1e05d7cf697d46aba95dc6661a8acbea0c894e44a793d054648b552a73b404aa3344d8a4826&token=337310304&lang=zh_CN#rd) + + + diff --git "a/\347\224\237\344\272\247\351\227\256\351\242\230\345\210\206\346\236\220/README.MD" "b/\347\224\237\344\272\247\351\227\256\351\242\230\345\210\206\346\236\220/README.MD" new file mode 100644 index 0000000..9d21f55 --- /dev/null +++ "b/\347\224\237\344\272\247\351\227\256\351\242\230\345\210\206\346\236\220/README.MD" @@ -0,0 +1,9 @@ +## 生产问题分析 + +- [内存泄漏问题的分析和解决方案](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487986&idx=1&sn=d681a585ac489703788e3baa48eb9aa3&chksm=cf21cedbf85647cd23bbab9dfec63e6877f83c34efb19bd16075d5d90fea91d3f4a20fc77921&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [生产问题分析!delete in子查询不走索引?!](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247495170&idx=1&sn=ce914de3abdb0d887e286b680b25111f&chksm=cf22312bf855b83d31a00da110626747df8e69fca1bc310642c56e39d663b006a8105f9fb1e1&token=1495321435&lang=zh_CN&scene=21#wechat_redirect) +- [手把手教你分析Mysql死锁问题](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487979&idx=1&sn=588c83d77a8851f3b3c18cd68ed9c454&chksm=cf21cec2f85647d4a77cc239ae9a4cfd31bb8832be3d98540a08ea8b4a1f46b38cf736210a02&token=1495321435&lang=zh_CN&scene=21#wechat_redirect) +- [线程池运用不当的一次线上事故](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487992&idx=1&sn=733335f2f69d743712915abc99f83b1d&chksm=cf21ced1f85647c7ab8c5d8bc4e8206b04acb5fd4feb94b8d088a782ed458b82aab69dba82aa&token=1990771297&lang=zh_CN#rd) +- [盘点MySQL慢查询的12个原因](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247499624&idx=1&sn=561b9cb7fe831ca7cb2d9fd65691e85e&chksm=cf222041f855a957ac50c0a53baaec6d26be32427259b2974450620f33a8c834419fe535e83d&token=1990771297&lang=zh_CN#rd) +- [线程池如何监控,才能帮助开发者快速定位线上错误?](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497444&idx=1&sn=1b2cc8b4685413149e46c814e468c6e6&chksm=cf2229cdf855a0db5f2da881d27c69f11c69480552985baa2a08cbe4d5a48bad7fb31a78dd5a&token=1990771297&lang=zh_CN#rd) +- [数据库死锁排查思路分享](https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247507770&idx=1&sn=b84b20aca057b34d511a501ff91941b5&chksm=c1e022b6f697aba05248128cb82f93aed341b1cc80e6d568c7150a4ffa6775692c7c9fa423a3&token=337310304&lang=zh_CN#rd) diff --git "a/\347\250\213\345\272\217\344\272\272\347\224\237&\351\235\242\350\257\225\345\273\272\350\256\256/README.MD" "b/\347\250\213\345\272\217\344\272\272\347\224\237&\351\235\242\350\257\225\345\273\272\350\256\256/README.MD" new file mode 100644 index 0000000..ae9424d --- /dev/null +++ "b/\347\250\213\345\272\217\344\272\272\347\224\237&\351\235\242\350\257\225\345\273\272\350\256\256/README.MD" @@ -0,0 +1,6 @@ +## 程序人生 + +- [跟大家聊聊天,我周末都在干啥](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247493222&idx=1&sn=29eb95b01b54bed2abbcf5a72285b38a&chksm=cf22394ff855b059b29ffb562e22d8ecc048caa743eb5c6257ad474676940ba8d36840f075ed&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [跟大家聊聊如何学习](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247495313&idx=1&sn=7f521db08e84b07177d847c60071d709&chksm=cf2231b8f855b8ae765f2dd584994836c0b74ce0ef761653233c3af04f38b4a1aa1833f7a55a&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [写了两年文章,终于破万!](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247489788&idx=1&sn=66efbc1b718915bfd8996b521d317a55&chksm=cf21c7d5f8564ec3928957d3c23959f5cb99d9f9bd2c1bab0dcf1750a6a017c3869189a3651a&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [夏天的风,我永远记得~](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247487989&idx=2&sn=9eb923d4c8c22bee1a408e4f86983f65&chksm=cf21cedcf85647cac6fe4bfa6d732856fd0335f4fcadad4d1e0dd10702e95905e06c9e38e8e8&token=162724582&lang=zh_CN&scene=21#wechat_redirect) \ No newline at end of file diff --git "a/\347\250\213\345\272\217\345\221\230\345\277\205\345\244\207\345\267\245\345\205\267\347\257\207/README.MD" "b/\347\250\213\345\272\217\345\221\230\345\277\205\345\244\207\345\267\245\345\205\267\347\257\207/README.MD" new file mode 100644 index 0000000..73e3dce --- /dev/null +++ "b/\347\250\213\345\272\217\345\221\230\345\277\205\345\244\207\345\267\245\345\205\267\347\257\207/README.MD" @@ -0,0 +1,8 @@ + +## 程序员工具篇 + +- [用代码画时序图!YYDS](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247500478&idx=1&sn=ec674e3eadba9bb87849292f46f84989&chksm=cf221d97f8559481fae8f0e1871ae19499568b3e49980e92018c4a5acdcf743a37da79c2436d&token=1990771297&lang=zh_CN#rd) +- [程序员必备基础:Git 命令全方位学习](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488013&idx=1&sn=7011a51a347e3da2cf8f8540b4d9a5d6&chksm=cf21cd24f8564432d74bc13551ebdeae71a71ea31e339c7a8f1f42f181078b5192475d598626&token=1569911403&lang=zh_CN&scene=21#wechat_redirect) +- [MyBatis 插件原理与实战](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498815&idx=1&sn=737e8f92ff526dac408af7a409f3a3d4&chksm=cf222316f855aa007fe16f7bca0636c552f238deb766bb54c34db7b633c13451fc91a4fe8a3e&token=1990771297&lang=zh_CN#rd) +- [更快的Maven来了,速度提升了8倍!](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497470&idx=1&sn=7a3a5bb48f7d3b1a627460b698e7e9a0&chksm=cf2229d7f855a0c1e892c23f7690e6ab1a745040142672b982a3934c8307901d0be03dff3cff&token=1990771297&lang=zh_CN#rd) +- [因为知道了30+款在线工具,我的工作效率提升500%!](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488041&idx=1&sn=26d55c23ecd439860c4d9865bec61976&chksm=cf21cd00f8564416fe991974d24a51798d925b2e79d62935accf02aa6895c7b02adf48e9e207&token=1990771297&lang=zh_CN#rd) \ No newline at end of file diff --git "a/\347\274\223\345\255\230Redis\346\200\273\347\273\223/README.MD" "b/\347\274\223\345\255\230Redis\346\200\273\347\273\223/README.MD" new file mode 100644 index 0000000..996dc81 --- /dev/null +++ "b/\347\274\223\345\255\230Redis\346\200\273\347\273\223/README.MD" @@ -0,0 +1,7 @@ +## 缓存 + +- [大厂经典面试题:Redis为什么这么快?](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490736&idx=1&sn=95377e729b27f0afefbaa5f20239fc9d&chksm=cf21c399f8564a8ff5239fbaa86d616a48086b47b3bb03c8ccc1d3cc066e41c75e16638c3fc8&token=1495321435&lang=zh_CN&scene=21#wechat_redirect) +- [美团二面:Redis与MySQL双写一致性如何保证?](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490243&idx=1&sn=ff11c3aab9ada3b16d7f2b57c846d567&chksm=cf21c5eaf8564cfc59e3d0d56fd02b0f5513015005f498381be4d12db462442a49aabe4159ef&token=1495321435&lang=zh_CN&scene=21#wechat_redirect) +- [使用Redis,你必须知道的21个注意要点](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488325&idx=1&sn=6d9bbe5bf2f2f2904755de5c786fb21b&chksm=cf21cc6cf856457a9d23b3e25ec48107a582e709f05964dfdb5ba77e9a239d8307334c485fdf&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [七种方案!探讨Redis分布式锁的正确使用姿势](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247488142&idx=1&sn=79a304efae7a814b6f71bbbc53810c0c&chksm=cf21cda7f85644b11ff80323defb90193bc1780b45c1c6081f00da85d665fd9eb32cc934b5cf&token=162724582&lang=zh_CN&scene=21#wechat_redirect) +- [2W字!详解20道Redis经典面试题!(珍藏版)](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247494124&idx=1&sn=c185f7d999d5f006608d05707a8a7eea&chksm=cf2236c5f855bfd329c6e2ee27f23f8131ebcd312960190a10f1a819d67f07a21a08ad17f263&token=162724582&lang=zh_CN&scene=21#wechat_redirect) \ No newline at end of file diff --git "a/\351\253\230\345\271\266\345\217\221/README.MD" "b/\351\253\230\345\271\266\345\217\221/README.MD" new file mode 100644 index 0000000..0ce39a5 --- /dev/null +++ "b/\351\253\230\345\271\266\345\217\221/README.MD" @@ -0,0 +1,7 @@ +## 高并发 +- [美团二面:Redis与MySQL双写一致性如何保证?](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247490243&idx=1&sn=ff11c3aab9ada3b16d7f2b57c846d567&chksm=cf21c5eaf8564cfc59e3d0d56fd02b0f5513015005f498381be4d12db462442a49aabe4159ef&token=1495321435&lang=zh_CN&scene=21#wechat_redirect) +- [Redis主从、哨兵、 Cluster集群一锅端!](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247498254&idx=1&sn=6489360c3b226df9811e66cb40ec7656&chksm=cf222527f855ac3112628bcec7730064fee3fdbe869fbd0a7410c22766a0c036a7e5c1a69fa0&token=1990771297&lang=zh_CN#rd) +- [面试必备:聊聊MySQL的主从](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497982&idx=1&sn=bb589329cceb5462fc41f66ec63dbf56&chksm=cf2227d7f855aec16dd4d3b3425c0401850eeaf2c9cdc82e82722d38a00c24ee9ccfa3353774&token=1990771297&lang=zh_CN#rd) +- [聊聊幂等设计](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497427&idx=1&sn=2ed160c9917ad989eee1ac60d6122855&chksm=cf2229faf855a0ecf5eb34c7335acdf6420426490ee99fc2b602d54ff4ffcecfdab24eeab0a3&token=1990771297&lang=zh_CN#rd) +- [聊聊接口性能优化的11个小技巧](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247497361&idx=1&sn=a0a2b0f92804921ba3d31b6236f275c2&chksm=cf2229b8f855a0aec650f4e0c3f105aa08e52fabbc54807dd37fefc4873749698b2b1445b59f&token=1990771297&lang=zh_CN#rd) +- [面试必备:秒杀场景九个细节](https://mp.weixin.qq.com/s?__biz=Mzg3NzU5NTIwNg==&mid=2247493227&idx=1&sn=10e5064d7d224c69dce400e90cd44de6&chksm=cf223942f855b0541ada22a312e0d4ffbc99df463678247a0dede3ef16eb81e3344a4a54ceaf&token=1990771297&lang=zh_CN#rd) \ No newline at end of file