[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"sysconfig-fetch":3,"theme-fetch":23,"friends":318,"article:mybatis-quick-review":478,"stats-fetch":503},{"basic":4,"upload":17,"oauth":20},{"author":5,"author_avatar":6,"author_desc":7,"blog_url":8,"cravatar_url":9,"description":10,"emojis":11,"favicon":11,"icp":12,"keywords":13,"meting_api":14,"police_record":11,"subtitle":15,"title":16},"星辰","https:\u002F\u002Fblog.strarry.top\u002Fuploads\u002Fsite\u002F2026\u002F07\u002F20260712161111_dszm8ofv.jpg","前景可待 未来可期","https:\u002F\u002Fblog.strarry.top","https:\u002F\u002Fcravatar.cn\u002Favatar\u002F%s?s=200&d=robohash","星辰の笔记，分享Java、Python、Spring Cloud、Vue前端、ES6等编程实战教程与技术笔记，记录从校园到职场的成长历程，融合技术开发与人文思考。","","冀ICP备2025110107号","博客,技术,编程,Java,Vue,星辰","https:\u002F\u002Fmeting.strarry.top\u002Fapi","StrarryBLOG","星辰の笔记",{"local_path":18,"max_file_size":19},".\u002Fuploads","5",{"github.enabled":21,"google.enabled":21,"microsoft.enabled":21,"oidc.enabled":21,"qq.enabled":22,"wechat.enabled":21},"false","true",{"slug":24,"name":25,"version":26,"author":27,"description":28,"license":29,"repo":30,"is_active":31,"config":32,"menus":154},"default","默认主题","1.0.0","Talen","StarryBlog 默认主题","MIT","https:\u002F\u002Fgithub.com\u002Ftalen8\u002FStarryBlog",true,{"font":11,"slogan":33,"home_url":34,"screenshot":35,"about_story":36,"author_desc":11,"description":10,"established":37,"home_layout":38,"wechat_name":11,"about_unions":39,"announcement":49,"author_email":50,"author_photo":11,"footer_links":51,"moments_size":55,"typing_texts":56,"about_profile":63,"footer_social":87,"wechat_qrcode":11,"about_creation":103,"about_describe":110,"about_versions":111,"sidebar_social":120,"about_motto_sub":132,"about_socialize":133,"message_content":11,"about_exhibition":11,"about_motto_main":138,"background_image":143,"donation_methods":144,"theme_dark_start":150,"about_personality":151,"theme_light_start":152,"about_describe_tips":153},"Code | Think | Share | Repeat","https:\u002F\u002Fstrarry.top","https:\u002F\u002Fblog.strarry.top\u002Fuploads\u002Fsiteshot.jpg","欢迎来到我的个人博客！这里是我分享技术、记录生活、积累知识的小天地。希望这些内容能对你有所帮助。如果你有任何想法或建议，欢迎随时与我交流！","2025-07-20","waterfall",[40,43,46],{"url":41,"name":42},"https:\u002F\u002Fbf.zzxworld.com","BlogFinder",{"url":44,"name":45},"https:\u002F\u002Fstoreweb.cn","个站商店",{"url":47,"name":48},"https:\u002F\u002Fwww.boyouquan.com","博友圈","欢迎来到我的博客\u003Cbr>\u003Cstrong>记录技术、生活与思考\u003C\u002Fstrong>\u003Cbr>\u003Cspan style=\"color:#e03131\">内容持续更新中\u003C\u002Fspan>\u003Cbr>\u003Ca href=\"\u002Fabout\">了解更多\u003C\u002Fa>","1628773490@qq.com",[52],{"url":53,"name":54},"\u002Fsubscribe","订阅",30,[57,59,61],{"value":58},"是微风，是晚霞，是心跳，是无可替代",{"value":60},"先努力让自己发光，对的人才能迎着光而来",{"value":62},"我走的很慢，但从不放弃",[64,67,71,75,79,83],{"color":65,"label":66,"value":5},"#43a6c6","姓名",{"color":68,"label":69,"value":70},"#c69043","生于","2002",{"color":72,"label":73,"value":74},"#d44040","故乡","中国",{"color":76,"label":77,"value":78},"#b04fe6","职业","全栈开发者",{"color":80,"label":81,"value":82},"#43c66f","兴趣","编程与创作",{"color":84,"label":85,"value":86},"#c643b3","梦想","创造价值",[88,93,96,100],{"url":89,"icon":90,"name":91,"position":92},"1","ri-mail-line","Email","left",{"url":89,"icon":94,"name":95,"position":92},"ri-twitter-x-line","X",{"url":89,"icon":97,"name":98,"position":99},"ri-github-line","GitHub","right",{"url":89,"icon":101,"name":102,"position":99},"ri-bilibili-line","Bilibili",[104,107],{"url":105,"name":106},"https:\u002F\u002Fjuejin.cn","掘金",{"url":108,"name":109},"https:\u002F\u002Fzhihu.com","知乎","持续学习的终身践行者，用代码和文字构建小小世界。在这里记录技术洞见、思考碎片和生活灵感。保持好奇，步履不停。",[112,114,117],{"name":113,"version":26},"StarryBLOG",{"name":115,"version":116},"Vue","3.5.34",{"name":118,"version":119},"Go","1.23",[121,123,124,127,129],{"url":122,"icon":97,"name":98},"https:\u002F\u002Fgithub.com\u002Fsongyuesheng",{"url":89,"icon":90,"name":91},{"url":89,"icon":125,"name":126},"ri-qq-line","QQ",{"url":89,"icon":101,"name":128},"BiliBili",{"url":89,"icon":130,"name":131},"ri-tiktok-line","抖音","用代码和文字记录生活，分享知识。",[134,136],{"url":135,"name":98},"https:\u002F\u002Fgithub.com",{"url":137,"name":91},"mailto:contact@example.com",[139,141],{"value":140},"前景可待，",{"value":142},"未来可期。","\u002Fuploads\u002Fbackgrounds\u002Fa0e2d9d2-ee81-4eba-aece-67d4bb4c6997.png",[145,148],{"name":146,"qrcode":11,"description":147},"微信","扫一扫，支持作者",{"name":149,"qrcode":11,"description":147},"支付宝","22:00","INFJ-A","06:00","开发者 · 创作者 · 终身学习者",{"aggregate":155,"footer":177,"navigation":260},[156],{"id":157,"title":158,"url":11,"icon":11,"sort":159,"is_enabled":31,"children":160},10,"个站",1,[161,166,172],{"id":162,"title":163,"url":164,"icon":11,"sort":159,"is_enabled":31,"children":165},11,"关于博主","\u002Fabout",[],{"id":167,"title":168,"url":169,"icon":11,"sort":170,"is_enabled":31,"children":171},29,"友情链接","\u002Ffriend",2,[],{"id":55,"title":173,"url":174,"icon":11,"sort":175,"is_enabled":31,"children":176},"网站统计","\u002Fstatistics",3,[],[178,203,212,226,250],{"id":179,"title":180,"url":11,"icon":11,"sort":159,"is_enabled":31,"children":181},12,"导航",[182,187,192,197],{"id":183,"title":184,"url":185,"icon":11,"sort":159,"is_enabled":31,"children":186},13,"文章归档","\u002Farchive",[],{"id":188,"title":189,"url":190,"icon":11,"sort":170,"is_enabled":31,"children":191},14,"文章分类","\u002Fcategories",[],{"id":193,"title":194,"url":195,"icon":11,"sort":175,"is_enabled":31,"children":196},15,"文章标签","\u002Ftags",[],{"id":198,"title":199,"url":200,"icon":11,"sort":201,"is_enabled":31,"children":202},16,"即时动态","\u002Fmoment",4,[],{"id":204,"title":205,"url":11,"icon":11,"sort":170,"is_enabled":31,"children":206},17,"直达",[207],{"id":208,"title":209,"url":210,"icon":11,"sort":159,"is_enabled":31,"children":211},18,"申请友链","\u002Ffriend#apply",[],{"id":213,"title":214,"url":11,"icon":11,"sort":175,"is_enabled":31,"children":215},19,"服务",[216,221],{"id":217,"title":218,"url":219,"icon":11,"sort":159,"is_enabled":31,"children":220},20,"服务状态","\u002Fstatus",[],{"id":222,"title":223,"url":224,"icon":11,"sort":170,"is_enabled":31,"children":225},21,"反馈投诉","\u002Ffeedback",[],{"id":227,"title":228,"url":11,"icon":11,"sort":201,"is_enabled":31,"children":229},22,"协议",[230,235,240,245],{"id":231,"title":232,"url":233,"icon":11,"sort":159,"is_enabled":31,"children":234},23,"Cookies","\u002Fcookies",[],{"id":236,"title":237,"url":238,"icon":11,"sort":170,"is_enabled":31,"children":239},24,"隐私协议","\u002Fprivacy",[],{"id":241,"title":242,"url":243,"icon":11,"sort":175,"is_enabled":31,"children":244},25,"版权协议","\u002Fcopyright",[],{"id":246,"title":247,"url":248,"icon":11,"sort":201,"is_enabled":31,"children":249},26,"提问须知","\u002Fask",[],{"id":251,"title":252,"url":11,"icon":11,"sort":253,"is_enabled":31,"children":254},27,"支持",5,[255],{"id":256,"title":257,"url":258,"icon":11,"sort":159,"is_enabled":31,"children":259},28,"腾讯云","https:\u002F\u002Fcloud.tencent.com",[],[261,264,267,270,282,285,290,303],{"id":159,"title":262,"url":185,"icon":11,"sort":159,"is_enabled":31,"children":263},"归档",[],{"id":170,"title":265,"url":190,"icon":11,"sort":170,"is_enabled":31,"children":266},"分类",[],{"id":175,"title":268,"url":195,"icon":11,"sort":175,"is_enabled":31,"children":269},"标签",[],{"id":201,"title":271,"url":11,"icon":11,"sort":201,"is_enabled":31,"children":272},"友链",[273,277],{"id":274,"title":275,"url":169,"icon":11,"sort":253,"is_enabled":31,"children":276},34,"友链展示",[],{"id":278,"title":279,"url":280,"icon":11,"sort":253,"is_enabled":31,"children":281},35,"朋友动态","\u002Ffcircle",[],{"id":253,"title":283,"url":200,"icon":11,"sort":253,"is_enabled":31,"children":284},"动态",[],{"id":286,"title":287,"url":288,"icon":11,"sort":286,"is_enabled":31,"children":289},6,"留言","\u002Fmessage",[],{"id":291,"title":292,"url":164,"icon":11,"sort":291,"is_enabled":31,"children":293},7,"关于",[294,298],{"id":295,"title":296,"url":164,"icon":11,"sort":253,"is_enabled":31,"children":297},36,"关于站长",[],{"id":299,"title":300,"url":301,"icon":11,"sort":253,"is_enabled":31,"children":302},37,"我的设备","\u002Fdevices",[],{"id":304,"title":305,"url":11,"icon":11,"sort":306,"is_enabled":31,"children":307},31,"工具",8,[308,313],{"id":309,"title":310,"url":311,"icon":11,"sort":253,"is_enabled":31,"children":312},32,"成长记录工具","https:\u002F\u002Fbecomingme.cn\u002F",[],{"id":314,"title":315,"url":316,"icon":11,"sort":253,"is_enabled":31,"children":317},33,"布丁简历","https:\u002F\u002Fresume.strarry.top",[],[319],{"type_id":159,"type_name":320,"type_sort":159,"friends":321},"默认分组",[322,329,335,341,347,353,359,365,371,377,383,389,395,401,407,413,419,425,432,438,444,450,456,461,466,472],{"id":227,"name":323,"url":324,"description":325,"avatar":326,"screenshot":327,"sort":227,"is_invalid":328},"yunsen2025 的小窝","https:\u002F\u002Fwww.yunsen2025.top","计算机爱好者","https:\u002F\u002Fimg.alicdn.com\u002Fbao\u002Fuploaded\u002Fi4\u002FO1CN01TWOpM42DSyY5nC0hM_!!0-mtopupload.jpg","https:\u002F\u002Fs0.wp.com\u002Fmshots\u002Fv1\u002Fhttps:\u002F\u002Fwww.yunsen2025.top\u002F?w=400&h=300",false,{"id":193,"name":330,"url":331,"description":332,"avatar":333,"screenshot":334,"sort":193,"is_invalid":328},"undefim blog","https:\u002F\u002Fundefi.me","Crafting my own path, forever undefined!","https:\u002F\u002Fundefi.me\u002Fupload\u002Fb2cc1237-c3cf-44ef-a6b9-a83528b74f9f.png","https:\u002F\u002Fs0.wp.com\u002Fmshots\u002Fv1\u002Fhttps:\u002F\u002Fundefi.me\u002F?w=400&h=300",{"id":162,"name":336,"url":337,"description":338,"avatar":339,"screenshot":340,"sort":157,"is_invalid":328},"百里博客","https:\u002F\u002Fblog.my0811.cn","一个高中生的博客","https:\u002F\u002Fblog.my0811.cn\u002Ffavicon.ico","https:\u002F\u002Fs0.wp.com\u002Fmshots\u002Fv1\u002Fhttps:\u002F\u002Fblog.my0811.cn\u002F?w=400&h=300",{"id":179,"name":342,"url":343,"description":344,"avatar":345,"screenshot":346,"sort":157,"is_invalid":328},"流月小站","https:\u002F\u002Fblog.flowmoon.cn\u002F","且听风吟，静待花开","https:\u002F\u002Fcdn.liuyue.net\u002Fassets\u002Fimg\u002Favatar.jpg","https:\u002F\u002Fs0.wp.com\u002Fmshots\u002Fv1\u002Fhttps:\u002F\u002Fblog.flowmoon.cn\u002F?w=400&h=300",{"id":183,"name":348,"url":349,"description":350,"avatar":351,"screenshot":352,"sort":157,"is_invalid":328},"叶子のBlog","https:\u002F\u002Fblog.goshujin.top\u002F","叶子のBlog 是一个专注于分享前端开发、网络技术、服务器搭建、科技热点与生活感悟的个人博客，作者为垂叶叶叶","https:\u002F\u002Fq2.qlogo.cn\u002Fheadimg_dl?dst_uin=319213657&spec=0","https:\u002F\u002Fs0.wp.com\u002Fmshots\u002Fv1\u002Fhttps:\u002F\u002Fblog.goshujin.top\u002F?w=400&h=300",{"id":188,"name":354,"url":355,"description":356,"avatar":357,"screenshot":358,"sort":157,"is_invalid":328},"鈴奈咲桜","https:\u002F\u002Fblog.sakura.ink","愛することを忘れないで","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F91101909?v=4","https:\u002F\u002Fs0.wp.com\u002Fmshots\u002Fv1\u002Fhttps:\u002F\u002Fblog.sakura.ink\u002F?w=400&h=300",{"id":198,"name":360,"url":361,"description":362,"avatar":363,"screenshot":364,"sort":157,"is_invalid":328},"fishcpy的小破站","https:\u002F\u002Fblog.fis.ink","非淡泊无以明志，非宁静无以致远","https:\u002F\u002Fwww.fis.ink\u002Fimg\u002Flogo.png","https:\u002F\u002Fs0.wp.com\u002Fmshots\u002Fv1\u002Fhttps:\u002F\u002Fblog.fis.ink\u002F?w=400&h=300",{"id":208,"name":366,"url":367,"description":368,"avatar":369,"screenshot":370,"sort":157,"is_invalid":328},"Hyde Blog","https:\u002F\u002Fteek.seasir.top","人心中的成见是一座大山","https:\u002F\u002Fteek.seasir.top\u002Ffavicon.ico","https:\u002F\u002Fs0.wp.com\u002Fmshots\u002Fv1\u002Fhttps:\u002F\u002Fteek.seasir.top\u002F?w=400&h=300",{"id":217,"name":372,"url":373,"description":374,"avatar":375,"screenshot":376,"sort":157,"is_invalid":328},"Codfish Blog","https:\u002F\u002Fcodfish.top","🐟🐟🐟","https:\u002F\u002Fcodfish.top\u002Ffavicon\u002F1.jpg","https:\u002F\u002Fs0.wp.com\u002Fmshots\u002Fv1\u002Fhttps:\u002F\u002Fcodfish.top\u002F?w=400&h=300",{"id":222,"name":378,"url":379,"description":380,"avatar":381,"screenshot":382,"sort":157,"is_invalid":328},"ZLA 小站","https:\u002F\u002Fzla.pub\u002F","ZL Asica 的个人博客，记录旅行与生活，也分享前端\u002F全栈\u002FHCI 开发笔记、TypeScript\u002FReact\u002FNext.js 及更多实战、以及个人开源项目的技术剖析与复盘。","https:\u002F\u002Fadmin.strarry.top\u002Fuploads\u002F友情链接A\u002F2026\u002F08\u002F20260808095402_k4hojuka.png","https:\u002F\u002Fs0.wp.com\u002Fmshots\u002Fv1\u002Fhttps:\u002F\u002Fzla.pub\u002F?w=400&h=300",{"id":236,"name":384,"url":385,"description":386,"avatar":387,"screenshot":388,"sort":157,"is_invalid":328},"张洪Heo","https:\u002F\u002Fblog.zhheo.com\u002F","分享设计与科技生活","https:\u002F\u002Fimg.zhheo.com\u002Fi\u002F67d8fa75943e4.webp","https:\u002F\u002Fs0.wp.com\u002Fmshots\u002Fv1\u002Fhttps:\u002F\u002Fblog.zhheo.com\u002F?w=400&h=300",{"id":246,"name":390,"url":391,"description":392,"avatar":393,"screenshot":394,"sort":157,"is_invalid":328},"小改学习志","https:\u002F\u002Fwww.haoyu233.com","孩儿立志出乡关，学不成名誓不还。","https:\u002F\u002Fcn.cravatar.com\u002Favatar\u002F14e584196d31262ea144ab4d75d4c083?s=600&r=g","https:\u002F\u002Fs0.wp.com\u002Fmshots\u002Fv1\u002Fhttps:\u002F\u002Fwww.haoyu233.com\u002F?w=400&h=300",{"id":251,"name":396,"url":397,"description":398,"avatar":399,"screenshot":400,"sort":157,"is_invalid":328},"Wer Blog","https:\u002F\u002Fblog.isyyo.com","The only way to do great is to love what you do","https:\u002F\u002Fblog.isyyo.com\u002Ffavicon\u002Flogo.png","https:\u002F\u002Fs0.wp.com\u002Fmshots\u002Fv1\u002Fhttps:\u002F\u002Fblog.isyyo.com\u002F?w=400&h=300",{"id":256,"name":402,"url":403,"description":404,"avatar":405,"screenshot":406,"sort":157,"is_invalid":328},"MIFENG BLOG","https:\u002F\u002Fblog.imbee.top\u002F","路漫漫其修远兮，吾将上下而求索","https:\u002F\u002Fcdn.mfawa.top\u002Fimage\u002Flogo.svg","https:\u002F\u002Fs0.wp.com\u002Fmshots\u002Fv1\u002Fhttps:\u002F\u002Fblog.imbee.top\u002F?w=400&h=300",{"id":167,"name":408,"url":409,"description":410,"avatar":411,"screenshot":412,"sort":157,"is_invalid":328},"TNTの博客","https:\u002F\u002Fblog.tnto.fun\u002F","萝卜青菜，各有所爱","https:\u002F\u002Fpic.xn--kiv.fun\u002Fuploads\u002F2025\u002F08\u002F13\u002F13\u002F689c2986e86c4.png","https:\u002F\u002Fs0.wp.com\u002Fmshots\u002Fv1\u002Fhttps:\u002F\u002Fblog.tnto.fun\u002F?w=400&h=300",{"id":55,"name":414,"url":415,"description":416,"avatar":417,"screenshot":418,"sort":157,"is_invalid":328},"清羽飞扬","https:\u002F\u002Fblog.liushen.fun\u002F","柳影曳曳，清酒孤灯，扬笔撒墨，心境如霜","https:\u002F\u002Fblog.liushen.fun\u002Finfo\u002Favatar.ico","https:\u002F\u002Fblog.liushen.fun\u002Finfo\u002Fsiteshot.jpg",{"id":304,"name":420,"url":421,"description":422,"avatar":423,"screenshot":424,"sort":157,"is_invalid":328},"默小班","https:\u002F\u002Fwww.memxb.top\u002F","一个初中生的小站点。","https:\u002F\u002Fwmimg.com\u002Fi\u002F780\u002F2025\u002F07\u002F68677fe53c2d1.png","https:\u002F\u002Fs0.wp.com\u002Fmshots\u002Fv1\u002Fhttps:\u002F\u002Fwww.memxb.top\u002F?w=400&h=300",{"id":426,"name":427,"url":428,"description":429,"avatar":430,"screenshot":431,"sort":426,"is_invalid":328},9,"二叉树树","https:\u002F\u002F2x.nz\u002F","分享网络技术、服务器部署、内网穿透、静态网站搭建......","https:\u002F\u002Fq1.qlogo.cn\u002Fg?b=qq&nk=2726730791&s=640","https:\u002F\u002Fs0.wp.com\u002Fmshots\u002Fv1\u002Fhttps:\u002F\u002F2x.nz\u002F?w=400&h=300",{"id":291,"name":433,"url":434,"description":435,"avatar":436,"screenshot":437,"sort":291,"is_invalid":328},"小张的个人博客","http:\u002F\u002Fmrzym.top\u002F","一个初级前端开发者的博客","http:\u002F\u002Fimg.mrzym.top\u002FFsjKJtHwnWCvmbk9V4MWcZrSKhm-","\r\nhttps:\u002F\u002Fs0.wp.com\u002Fmshots\u002Fv1\u002Fhttp:\u002F\u002Fmrzym.top\u002F?w=400&h=300",{"id":286,"name":439,"url":440,"description":441,"avatar":442,"screenshot":443,"sort":286,"is_invalid":328},"吐司气泡","https:\u002F\u002Fblog.toastbubble.top\u002F","这里有多的吐司快来品鉴","https:\u002F\u002Fblog.toastbubble.top\u002Favatar.webp","https:\u002F\u002Fs0.wp.com\u002Fmshots\u002Fv1\u002Fhttps:\u002F\u002Fblog.toastbubble.top\u002F?w=400&h=300",{"id":253,"name":445,"url":446,"description":447,"avatar":448,"screenshot":449,"sort":253,"is_invalid":328},"尘の个人博客","https:\u002F\u002Fblog.mcxiaochen.top\u002F","一个高中生 UP 搭的博客 QwQ","https:\u002F\u002Fblog.mcxiaochen.top\u002Ffavicon.ico","https:\u002F\u002Fs0.wp.com\u002Fmshots\u002Fv1\u002Fhttps:\u002F\u002Fblog.mcxiaochen.top\u002F?w=400&h=300",{"id":309,"name":451,"url":452,"description":453,"avatar":454,"screenshot":455,"sort":253,"is_invalid":328},"mccsjs","https:\u002F\u002Fhexo.seln.cn\u002F","点一盏灯，等一个迷路的夜🍁🍁🍁","https:\u002F\u002Fadmin.strarry.top\u002Fuploads\u002F友情链接A\u002F2026\u002F08\u002F20260804093219_moc2g0tx.png","https:\u002F\u002Fhexo.seln.cn\u002Fimg\u002Fa.jpg",{"id":314,"name":457,"url":458,"description":7,"avatar":459,"screenshot":460,"sort":253,"is_invalid":328},"爱吃猫的鱼","https:\u002F\u002Fblog.talen.top","https:\u002F\u002Fimage.talen.top\u002F20251229184705_wgsva7g9.png","https:\u002F\u002Fimage.talen.top\u002F20260413160405_7w8hvvun.png",{"id":201,"name":462,"url":463,"description":462,"avatar":464,"screenshot":465,"sort":201,"is_invalid":328},"小笨蛋技术网","http:\u002F\u002F200655.xyz","https:\u002F\u002Fcdn.200655.xyz\u002Flogo\u002Fhead\u002Fxbd.png","https:\u002F\u002Fs0.wp.com\u002Fmshots\u002Fv1\u002Fhttp:\u002F\u002F200655.xyz\u002F?w=400&h=300",{"id":175,"name":467,"url":468,"description":469,"avatar":470,"screenshot":471,"sort":175,"is_invalid":328},"SDWL-博客","https:\u002F\u002Fblog.iokb.cn\u002F","Good Luck To You!","https:\u002F\u002Fblog.iokb.cn\u002Fzb_users\u002Fupload\u002F2022\u002F03\u002F202203091646757255754905.jpg","https:\u002F\u002Fs0.wp.com\u002Fmshots\u002Fv1\u002Fhttps:\u002F\u002Fblog.iokb.cn\u002F?w=400&h=300",{"id":170,"name":473,"url":474,"description":475,"avatar":476,"screenshot":477,"sort":170,"is_invalid":328},"无影大侠的小站","https:\u002F\u002Fblog.skyshadow.fun\u002F","在互联网留下一个脚印","https:\u002F\u002Fweavatar.com\u002Favatar\u002F7388ea4765a319d5f83fea61c3236384?s=1000","https:\u002F\u002Fs0.wp.com\u002Fmshots\u002Fv1\u002Fhttps:\u002F\u002Fblog.skyshadow.fun\u002F?w=400&h=300",{"id":162,"title":479,"slug":480,"content":481,"summary":482,"ai_summary":483,"cover":484,"location":11,"is_top":328,"is_essence":328,"is_outdated":328,"view_count":485,"comment_count":486,"url":487,"publish_time":488,"update_time":489,"category":490,"tags":493,"prev":497,"next":500},"后端开发：MyBatis的快速复习","mybatis-quick-review","## 一、MyBatis环境搭建\n\n### 1. 引入相关Maven依赖\n\n在 `pom.xml` 中引入 MyBatis + 数据库驱动（本文使用MySQL为例）：\n\n~~~xml\n\u003Cdependencies>\n    \u003C!-- MyBatis 核心依赖 -->\n    \u003Cdependency>\n        \u003CgroupId>org.mybatis\u003C\u002FgroupId>\n        \u003CartifactId>mybatis\u003C\u002FartifactId>\n        \u003Cversion>3.5.15\u003C\u002Fversion>\n    \u003C\u002Fdependency>\n\n    \u003C!-- MyBatis 与 SpringBoot 整合 -->\n    \u003Cdependency>\n        \u003CgroupId>org.mybatis.spring.boot\u003C\u002FgroupId>\n        \u003CartifactId>mybatis-spring-boot-starter\u003C\u002FartifactId>\n        \u003Cversion>3.0.3\u003C\u002Fversion>\n    \u003C\u002Fdependency>\n\n    \u003C!-- MySQL 驱动 -->\n    \u003Cdependency>\n        \u003CgroupId>mysql\u003C\u002FgroupId>\n        \u003CartifactId>mysql-connector-java\u003C\u002FartifactId>\n        \u003Cversion>8.0.33\u003C\u002Fversion>\n    \u003C\u002Fdependency>\n\n    \u003C!-- Lombok（简化实体类） -->\n    \u003Cdependency>\n        \u003CgroupId>org.projectlombok\u003C\u002FgroupId>\n        \u003CartifactId>lombok\u003C\u002FartifactId>\n        \u003Cversion>1.18.32\u003C\u002Fversion>\n    \u003C\u002Fdependency>\n\u003C\u002Fdependencies>\n\n~~~\n\n### 2. 数据库连接配置（application.yml）\n\n```yaml\nspring:\n  datasource:\n    url: jdbc:mysql:\u002F\u002Flocalhost:3306\u002Fmybatis_demo?useSSL=false&serverTimezone=UTC\n    username: root\n    password: root\n    driver-class-name: com.mysql.cj.jdbc.Driver\n\nmybatis:\n  mapper-locations: classpath:mapper\u002F*.xml\n  type-aliases-package: com.example.demo.domain\n```\n\n## 二、准备测试表（单表 & 多表）\n\n以下建表语句和相关的测试数据由`ChatGPT5`生成。\n\n```sql\n-- 建库\nCREATE DATABASE IF NOT EXISTS mybatis_demo DEFAULT CHARSET utf8mb4;\nUSE mybatis_demo;\n\n-- 用户表\nDROP TABLE IF EXISTS user;\nCREATE TABLE user (\n  id BIGINT PRIMARY KEY AUTO_INCREMENT,\n  username VARCHAR(50) NOT NULL,\n  email VARCHAR(100),\n  age INT,\n  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n);\n\n-- 订单表\nDROP TABLE IF EXISTS orders;\nCREATE TABLE orders (\n  id BIGINT PRIMARY KEY AUTO_INCREMENT,\n  user_id BIGINT NOT NULL,\n  order_no VARCHAR(50) NOT NULL,\n  amount DECIMAL(10,2),\n  status TINYINT DEFAULT 0,      -- 0:待支付 1:已支付 2:已取消\n  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n  FOREIGN KEY (user_id) REFERENCES user(id)\n);\n\n-- 产品表\nDROP TABLE IF EXISTS product;\nCREATE TABLE product (\n  id BIGINT PRIMARY KEY AUTO_INCREMENT,\n  name VARCHAR(100) NOT NULL,\n  price DECIMAL(10,2) NOT NULL,\n  category VARCHAR(50)\n);\n\n-- 订单明细表\nDROP TABLE IF EXISTS order_item;\nCREATE TABLE order_item (\n  id BIGINT PRIMARY KEY AUTO_INCREMENT,\n  order_id BIGINT NOT NULL,\n  product_id BIGINT NOT NULL,\n  quantity INT NOT NULL,\n  item_amount DECIMAL(10,2) GENERATED ALWAYS AS (quantity * 1.0) VIRTUAL,\n  FOREIGN KEY (order_id) REFERENCES orders(id),\n  FOREIGN KEY (product_id) REFERENCES product(id)\n);\n\n-- 测试数据\nINSERT INTO user (username,email,age) VALUES\n(\\'alice\\',\\'alice@example.com\\',23),\n(\\'bob\\',\\'bob@example.com\\',28),\n(\\'charlie\\',\\'charlie@example.com\\',31),\n(\\'dora\\',\\'dora@example.com\\',26);\n\nINSERT INTO product (name,price,category) VALUES\n(\\'iPhone 15\\', 8999.00, \\'phone\\'),\n(\\'iPad Air\\',  4999.00, \\'tablet\\'),\n(\\'ThinkPad X1\\', 12999.00, \\'laptop\\'),\n(\\'AirPods Pro\\', 1999.00, \\'audio\\'),\n(\\'Kindle Scribe\\', 2999.00, \\'reader\\');\n\nINSERT INTO orders (user_id, order_no, amount, status) VALUES\n(1, \\'A202501-0001\\',  1999.00, 1),\n(1, \\'A202501-0002\\', 10998.00, 1),\n(2, \\'B202501-0003\\',  4999.00, 0),\n(3, \\'C202501-0004\\', 12999.00, 2),\n(3, \\'C202501-0005\\',  1999.00, 1);\n\nINSERT INTO order_item (order_id, product_id, quantity) VALUES\n(1, 4, 1),                    -- alice 买 AirPods Pro\n(2, 1, 1), (2, 2, 1),         -- alice 买 iPhone + iPad\n(3, 2, 1),                    -- bob 预下 iPad\n(4, 3, 1),                    -- charlie 取消 ThinkPad X1\n(5, 4, 1);                    -- charlie 买 AirPods\n```\n\n设计以上几个表可以覆盖：\n\n- **单表查询** → `user`\n- **一对多** → `user` 和 `orders`\n- **多对多** → `orders` 和 `product` 通过 `order_item`\n\n## 三、使用MyBatis进行CRUD回顾\n\n### 1. 使用Lombok快速编写实体类\n\n~~~java\n\u002F\u002F User.java\n@Data\npublic class User {\n  private Long id;\n  private String username;\n  private String email;\n  private Integer age;\n  private LocalDateTime createdAt;\n  private List\u003COrder> orders; \u002F\u002F 一对多\n}\n\n\u002F\u002F Order.java\n@Data\npublic class Order {\n  private Long id;\n  private Long userId;\n  private String orderNo;\n  private BigDecimal amount;\n  private Integer status;\n  private LocalDateTime createdAt;\n  private User user;                 \u002F\u002F 一对一（下单用户）\n  private List\u003CProduct> products;    \u002F\u002F 多对多（通过明细）\n}\n\n\u002F\u002F Product.java\n@Data\npublic class Product {\n  private Long id;\n  private String name;\n  private BigDecimal price;\n  private String category;\n}\n\n\u002F\u002F OrderItem.java\n@Data\npublic class OrderItem {\n  private Long id;\n  private Long orderId;\n  private Long productId;\n  private Integer quantity;\n}\n~~~\n\n# 四、Mapper 接口定义\n\n```java\npublic interface UserMapper {\n  User selectById(Long id);\n  List\u003CUser> selectAll();\n  int insert(User u);\n  int update(User u);\n  int delete(Long id);\n\n  \u002F\u002F 动态查询\n  List\u003CUser> query(@Param(\\\"username\\\") String username,\n                   @Param(\\\"minAge\\\") Integer minAge,\n                   @Param(\\\"maxAge\\\") Integer maxAge,\n                   @Param(\\\"ids\\\") List\u003CLong> ids);\n\n  \u002F\u002F 一对多（结果集映射）\n  User selectUserWithOrders(Long id);\n\n  \u002F\u002F 分页（简单 LIMIT）\n  List\u003CUser> page(@Param(\\\"offset\\\") int offset, @Param(\\\"size\\\") int size);\n}\n\npublic interface OrderMapper {\n  Order selectOrderWithUser(Long id);            \u002F\u002F association 嵌套对象\n  Order selectOrderWithProducts(Long id);        \u002F\u002F collection 多对多\n  int insert(Order o);\n  int insertUseSelectKey(Order o);\n}\n\npublic interface ProductMapper {\n  List\u003CProduct> selectByCategory(@Param(\\\"category\\\") String category);\n}\n```\n\n# 五、使用XML标签编写SQL语句\n\n> 放在 `resources\u002Fmapper\u002F*.xml`。以下示例以 `UserMapper.xml` \u002F `OrderMapper.xml` 为主，**每个常用标签都有最小可运行示例**。\n\n## 0）顶层与命名空间：`\u003Cmapper namespace=\\\"...\\\">`\n\n```xml\n\u003C!-- UserMapper.xml -->\n\u003Cmapper namespace=\\\"com.example.demo.mapper.UserMapper\\\">\n  \u003C!-- 具体语句见下 -->\n\u003C\u002Fmapper>\n```\n\n- **namespace** 必须与接口全限定名一致，方法名与子标签 `id` 对应。\n\n## 1）基础 CRUD：`\u003Cselect>\u002F\u003Cinsert>\u002F\u003Cupdate>\u002F\u003Cdelete>`\n\n```xml\n\u003C!-- resultType 可用别名（配置了 type-aliases-package） -->\n\u003Cselect id=\\\"selectById\\\" parameterType=\\\"long\\\" resultType=\\\"User\\\">\n  SELECT id, username, email, age, created_at\n  FROM user\n  WHERE id = #{id}\n\u003C\u002Fselect>\n\n\u003Cselect id=\\\"selectAll\\\" resultType=\\\"User\\\">\n  SELECT id, username, email, age, created_at FROM user\n\u003C\u002Fselect>\n\n\u003Cinsert id=\\\"insert\\\" parameterType=\\\"User\\\" useGeneratedKeys=\\\"true\\\" keyProperty=\\\"id\\\">\n  INSERT INTO user (username, email, age)\n  VALUES (#{username}, #{email}, #{age})\n\u003C\u002Finsert>\n\n\u003Cupdate id=\\\"update\\\" parameterType=\\\"User\\\">\n  UPDATE user\n  \u003Cset>\n    \u003Cif test=\\\"username!=null\\\">username=#{username},\u003C\u002Fif>\n    \u003Cif test=\\\"email!=null\\\">email=#{email},\u003C\u002Fif>\n    \u003Cif test=\\\"age!=null\\\">age=#{age},\u003C\u002Fif>\n  \u003C\u002Fset>\n  WHERE id=#{id}\n\u003C\u002Fupdate>\n\n\u003Cdelete id=\\\"delete\\\" parameterType=\\\"long\\\">\n  DELETE FROM user WHERE id=#{id}\n\u003C\u002Fdelete>\n```\n\n**要点：**\n\n- `useGeneratedKeys + keyProperty`：MySQL\u002FJDBC 自动回填主键。\n- `parameterType`\u002F`resultType`：参数\u002F返回类型（类名或别名）。\n\n## 2）结果映射：`\u003CresultMap>`、`\u003Cid>`、`\u003Cresult>`、`\u003Cassociation>`、`\u003Ccollection>`、`ofType`、`property`、`column`\n\n```xml\n\u003C!-- 一对多：用户 + 订单列表 -->\n\u003CresultMap id=\\\"UserWithOrdersRM\\\" type=\\\"User\\\">\n  \u003Cid     property=\\\"id\\\"        column=\\\"u_id\\\"\u002F>\n  \u003Cresult property=\\\"username\\\"  column=\\\"username\\\"\u002F>\n  \u003Cresult property=\\\"email\\\"     column=\\\"email\\\"\u002F>\n  \u003Cresult property=\\\"age\\\"       column=\\\"age\\\"\u002F>\n  \u003Ccollection property=\\\"orders\\\" ofType=\\\"Order\\\">\n    \u003Cid     property=\\\"id\\\"       column=\\\"o_id\\\"\u002F>\n    \u003Cresult property=\\\"orderNo\\\"  column=\\\"order_no\\\"\u002F>\n    \u003Cresult property=\\\"amount\\\"   column=\\\"amount\\\"\u002F>\n    \u003Cresult property=\\\"status\\\"   column=\\\"status\\\"\u002F>\n    \u003Cresult property=\\\"createdAt\\\" column=\\\"o_created_at\\\"\u002F>\n  \u003C\u002Fcollection>\n\u003C\u002FresultMap>\n\n\u003Cselect id=\\\"selectUserWithOrders\\\" resultMap=\\\"UserWithOrdersRM\\\">\n  SELECT\n    u.id u_id, u.username, u.email, u.age,\n    o.id o_id, o.order_no, o.amount, o.status, o.created_at o_created_at\n  FROM user u\n  LEFT JOIN orders o ON u.id = o.user_id\n  WHERE u.id = #{id}\n\u003C\u002Fselect>\n```\n\n**要点：**\n\n- `property`：Java 字段名；`column`：SQL 列或别名。\n- `ofType`：集合元素类型（常用于 `\u003Ccollection>`）。\n\n## 3）嵌套查询（分步查询）与懒加载：`association select` \u002F `collection select`、`fetchType`\n\n```xml\n\u003C!-- OrderMapper.xml -->\n\u003CresultMap id=\\\"OrderWithUserRM\\\" type=\\\"Order\\\">\n  \u003Cid     property=\\\"id\\\"      column=\\\"id\\\"\u002F>\n  \u003Cresult property=\\\"orderNo\\\" column=\\\"order_no\\\"\u002F>\n  \u003Cresult property=\\\"amount\\\"  column=\\\"amount\\\"\u002F>\n  \u003Cassociation property=\\\"user\\\" javaType=\\\"User\\\"\n               column=\\\"user_id\\\" select=\\\"com.example.demo.mapper.UserMapper.selectById\\\"\n               fetchType=\\\"lazy\\\"\u002F>\n\u003C\u002FresultMap>\n\n\u003Cselect id=\\\"selectOrderWithUser\\\" resultMap=\\\"OrderWithUserRM\\\">\n  SELECT id, user_id, order_no, amount FROM orders WHERE id=#{id}\n\u003C\u002Fselect>\n```\n\n**要点：**\n\n- `select=\\\"namespace.method\\\"`：把某列（通过 `column` 指定）作为参数传给另一个 `select`。\n- 配合全局 `lazy-loading-enabled: true` 可懒加载，避免一次性拉大对象图。\n\n## 4）多对多（订单 → 产品列表）：`\u003Ccollection>` + 连接查询\n\n```xml\n\u003C!-- OrderMapper.xml -->\n\u003CresultMap id=\\\"OrderWithProductsRM\\\" type=\\\"Order\\\">\n  \u003Cid     property=\\\"id\\\"       column=\\\"o_id\\\"\u002F>\n  \u003Cresult property=\\\"orderNo\\\"  column=\\\"order_no\\\"\u002F>\n  \u003Cresult property=\\\"amount\\\"   column=\\\"amount\\\"\u002F>\n  \u003Ccollection property=\\\"products\\\" ofType=\\\"Product\\\">\n    \u003Cid     property=\\\"id\\\"     column=\\\"p_id\\\"\u002F>\n    \u003Cresult property=\\\"name\\\"   column=\\\"p_name\\\"\u002F>\n    \u003Cresult property=\\\"price\\\"  column=\\\"price\\\"\u002F>\n    \u003Cresult property=\\\"category\\\" column=\\\"category\\\"\u002F>\n  \u003C\u002Fcollection>\n\u003C\u002FresultMap>\n\n\u003Cselect id=\\\"selectOrderWithProducts\\\" resultMap=\\\"OrderWithProductsRM\\\">\n  SELECT\n    o.id o_id, o.order_no, o.amount,\n    p.id p_id, p.name p_name, p.price, p.category\n  FROM orders o\n  LEFT JOIN order_item oi ON o.id=oi.order_id\n  LEFT JOIN product p ON oi.product_id=p.id\n  WHERE o.id=#{id}\n\u003C\u002Fselect>\n```\n\n## 5）SQL 片段复用：`\u003Csql>` + `\u003Cinclude>`\n\n```xml\n\u003Csql id=\\\"UserColumns\\\">\n  id, username, email, age, created_at\n\u003C\u002Fsql>\n\n\u003Cselect id=\\\"page\\\" resultType=\\\"User\\\">\n  SELECT \u003Cinclude refid=\\\"UserColumns\\\"\u002F>\n  FROM user\n  ORDER BY id DESC\n  LIMIT #{offset}, #{size}\n\u003C\u002Fselect>\n```\n\n## 6）动态 SQL（开发中使用较多）\n\n### 6.1 `\u003Cif>` + `\u003Cwhere>`：自动处理 AND\u002FOR\n\n```xml\n\u003Cselect id=\\\"query\\\" resultType=\\\"User\\\">\n  SELECT id, username, email, age, created_at\n  FROM user\n  \u003Cwhere>\n    \u003Cif test=\\\"username != null and username != \\'\\'\\\">\n      AND username LIKE CONCAT(\\'%\\', #{username}, \\'%\\')\n    \u003C\u002Fif>\n    \u003Cif test=\\\"minAge != null\\\"> AND age &gt;= #{minAge}\u003C\u002Fif>\n    \u003Cif test=\\\"maxAge != null\\\"> AND age &lt;= #{maxAge}\u003C\u002Fif>\n    \u003Cif test=\\\"ids != null and ids.size() > 0\\\">\n      AND id IN\n      \u003Cforeach collection=\\\"ids\\\" item=\\\"id\\\" open=\\\"(\\\" separator=\\\",\\\" close=\\\")\\\">\n        #{id}\n      \u003C\u002Fforeach>\n    \u003C\u002Fif>\n  \u003C\u002Fwhere>\n\u003C\u002Fselect>\n```\n\n### 6.2 `\u003Cchoose>\u002F\u003Cwhen>\u002F\u003Cotherwise>`：分支\n\n```xml\n\u003Cselect id=\\\"chooseExample\\\" resultType=\\\"User\\\">\n  SELECT id, username, email, age, created_at\n  FROM user\n  \u003Cwhere>\n    \u003Cchoose>\n      \u003Cwhen test=\\\"username != null\\\"> username = #{username} \u003C\u002Fwhen>\n      \u003Cwhen test=\\\"minAge != null\\\"> age &gt;= #{minAge} \u003C\u002Fwhen>\n      \u003Cotherwise> age IS NOT NULL \u003C\u002Fotherwise>\n    \u003C\u002Fchoose>\n  \u003C\u002Fwhere>\n\u003C\u002Fselect>\n```\n\n### 6.3 `\u003Cforeach>`：遍历 List \u002F Map\n\n```xml\n\u003C!-- List 参数：ids -->\n\u003Cselect id=\\\"selectByIds\\\" resultType=\\\"User\\\">\n  SELECT id, username, email, age, created_at\n  FROM user\n  WHERE id IN\n  \u003Cforeach collection=\\\"ids\\\" item=\\\"id\\\" open=\\\"(\\\" separator=\\\",\\\" close=\\\")\\\">\n    #{id}\n  \u003C\u002Fforeach>\n\u003C\u002Fselect>\n\n\u003C!-- Map 参数：map.put(\\\"k1\\\",\\\"v1\\\") -->\n\u003Cselect id=\\\"foreachMap\\\" resultType=\\\"map\\\">\n  SELECT #{map[\\'k1\\']} AS k1_value\n\u003C\u002Fselect>\n```\n\n### 6.4 `\u003Cset>`：动态 UPDATE 字段\n\n```xml\n\u003Cupdate id=\\\"dynamicUpdate\\\" parameterType=\\\"User\\\">\n  UPDATE user\n  \u003Cset>\n    \u003Cif test=\\\"username!=null\\\"> username=#{username},\u003C\u002Fif>\n    \u003Cif test=\\\"email!=null\\\"> email=#{email},\u003C\u002Fif>\n    \u003Cif test=\\\"age!=null\\\"> age=#{age},\u003C\u002Fif>\n  \u003C\u002Fset>\n  WHERE id=#{id}\n\u003C\u002Fupdate>\n```\n\n### 6.5 `\u003Ctrim>`：灵活控制前后缀\n\n```xml\n\u003Cupdate id=\\\"updateWithTrim\\\" parameterType=\\\"User\\\">\n  UPDATE user\n  \u003Ctrim prefix=\\\"SET\\\" suffixOverrides=\\\",\\\">\n    \u003Cif test=\\\"username!=null\\\"> username=#{username},\u003C\u002Fif>\n    \u003Cif test=\\\"email!=null\\\"> email=#{email},\u003C\u002Fif>\n    \u003Cif test=\\\"age!=null\\\"> age=#{age},\u003C\u002Fif>\n  \u003C\u002Ftrim>\n  WHERE id=#{id}\n\u003C\u002Fupdate>\n```\n\n### 6.6 `\u003Cbind>`：绑定变量（常用于 LIKE）\n\n```xml\n\u003Cselect id=\\\"likeQuery\\\" resultType=\\\"User\\\">\n  \u003Cbind name=\\\"kw\\\" value=\\\"\\'%\\' + _parameter + \\'%\\'\\\" \u002F>\n  SELECT id, username, email, age, created_at\n  FROM user\n  WHERE username LIKE #{kw}\n\u003C\u002Fselect>\n```\n\n> 传入参数是一个字符串时，`_parameter` 指它本身。\n\n## 7）主键策略：`useGeneratedKeys` 与 `\u003CselectKey>`\n\n```xml\n\u003C!-- MySQL 推荐：useGeneratedKeys -->\n\u003Cinsert id=\\\"insert\\\" parameterType=\\\"User\\\" useGeneratedKeys=\\\"true\\\" keyProperty=\\\"id\\\">\n  INSERT INTO user (username,email,age) VALUES (#{username},#{email},#{age})\n\u003C\u002Finsert>\n\n\u003C!-- 兼容序列的写法（例如 Oracle \u002F PG 有 sequence） -->\n\u003Cinsert id=\\\"insertUseSelectKey\\\" parameterType=\\\"Order\\\">\n  \u003CselectKey keyProperty=\\\"id\\\" resultType=\\\"long\\\" order=\\\"BEFORE\\\">\n    SELECT nextval(\\'order_seq\\')\n  \u003C\u002FselectKey>\n  INSERT INTO orders (id, user_id, order_no, amount, status)\n  VALUES (#{id}, #{userId}, #{orderNo}, #{amount}, #{status})\n\u003C\u002Finsert>\n```\n\n## 8）构造器映射 & 鉴别器：`\u003Cconstructor>`、`\u003Cdiscriminator>`\n\n```xml\n\u003C!-- 用构造器给不可变对象赋值 -->\n\u003CresultMap id=\\\"UserCtorRM\\\" type=\\\"User\\\">\n  \u003Cconstructor>\n    \u003CidArg    column=\\\"id\\\"        javaType=\\\"long\\\"\u002F>\n    \u003Carg      column=\\\"username\\\"  javaType=\\\"string\\\"\u002F>\n    \u003Carg      column=\\\"email\\\"     javaType=\\\"string\\\"\u002F>\n    \u003Carg      column=\\\"age\\\"       javaType=\\\"int\\\"\u002F>\n  \u003C\u002Fconstructor>\n\u003C\u002FresultMap>\n\n\u003C!-- discriminator：根据列值映射不同结构（示例性） -->\n\u003CresultMap id=\\\"OrderWithStatusRM\\\" type=\\\"Order\\\">\n  \u003Cid property=\\\"id\\\" column=\\\"id\\\"\u002F>\n  \u003Cresult property=\\\"orderNo\\\" column=\\\"order_no\\\"\u002F>\n  \u003Cresult property=\\\"status\\\"  column=\\\"status\\\"\u002F>\n  \u003Cdiscriminator javaType=\\\"int\\\" column=\\\"status\\\">\n    \u003Ccase value=\\\"0\\\">\n      \u003Cresult property=\\\"amount\\\" column=\\\"amount\\\"\u002F>\n    \u003C\u002Fcase>\n    \u003Ccase value=\\\"1\\\">\n      \u003Cresult property=\\\"amount\\\" column=\\\"amount\\\"\u002F>\n    \u003C\u002Fcase>\n    \u003Ccase value=\\\"2\\\">\n      \u003Cresult property=\\\"amount\\\" column=\\\"amount\\\"\u002F>\n    \u003C\u002Fcase>\n  \u003C\u002Fdiscriminator>\n\u003C\u002FresultMap>\n\n\u003Cselect id=\\\"selectOrderDiscriminator\\\" resultMap=\\\"OrderWithStatusRM\\\">\n  SELECT id, order_no, amount, status FROM orders WHERE id=#{id}\n\u003C\u002Fselect>\n```\n\n## 9）存储过程 \u002F 多结果集：`statementType=\\\"CALLABLE\\\"`、`resultSets`（知道即可）\n\n```xml\n\u003Cselect id=\\\"callProc\\\" statementType=\\\"CALLABLE\\\">\n  { call proc_recalc_order_amount(#{orderId, mode=IN}) }\n\u003C\u002Fselect>\n```\n\n> 多结果集时可用 `resultSets=\\\"rs1,rs2\\\"` 配合多个 `resultMap`（不同库支持度差异较大）。\n\n## 10）缓存：`\u003Ccache>`、`\u003Ccache-ref>`（二级缓存）\n\n```xml\n\u003C!-- 当前 mapper 开启二级缓存 -->\n\u003Ccache eviction=\\\"LRU\\\" flushInterval=\\\"60000\\\" size=\\\"512\\\" readOnly=\\\"false\\\"\u002F>\n\n\u003C!-- 引用别的命名空间的缓存 -->\n\u003C!-- \u003Ccache-ref namespace=\\\"com.example.demo.mapper.OtherMapper\\\"\u002F> -->\n```\n\n**要点：**\n\n- 二级缓存是跨 SqlSession 的；**更新会清理**对应命名空间的缓存。\n- 生产环境慎用，注意与数据一致性、事务提交时机的关系。\n\n## 11）数据库差异：`databaseId`（同一语句不同方言）\n\n```xml\n\u003Cselect id=\\\"selectNow\\\" resultType=\\\"string\\\" databaseId=\\\"mysql\\\">\n  SELECT DATE_FORMAT(NOW(), \\'%Y-%m-%d %H:%i:%s\\')\n\u003C\u002Fselect>\n\n\u003Cselect id=\\\"selectNow\\\" resultType=\\\"string\\\" databaseId=\\\"postgresql\\\">\n  SELECT TO_CHAR(NOW(), \\'YYYY-MM-DD HH24:MI:SS\\')\n\u003C\u002Fselect>\n```\n\n> 需在全局配置里开启 `databaseIdProvider`（Spring Boot 多用 starter 自动识别）。\n\n## 12）resultType 的多种返回：`POJO \u002F Map \u002F 基本类型`\n\n```xml\n\u003C!-- 返回 Map -->\n\u003Cselect id=\\\"countByStatus\\\" resultType=\\\"map\\\">\n  SELECT status, COUNT(*) cnt FROM orders GROUP BY status\n\u003C\u002Fselect>\n\n\u003C!-- 返回基本类型 -->\n\u003Cselect id=\\\"countUser\\\" resultType=\\\"long\\\">\n  SELECT COUNT(*) FROM user\n\u003C\u002Fselect>\n```\n\n# 六、综合实战片段（把常用点串一遍）\n\n```xml\n\u003C!-- UserMapper.xml -->\n\u003Cmapper namespace=\\\"com.example.demo.mapper.UserMapper\\\">\n\n  \u003Ccache eviction=\\\"LRU\\\" size=\\\"256\\\"\u002F>\n\n  \u003Csql id=\\\"BaseCols\\\">id, username, email, age, created_at\u003C\u002Fsql>\n\n  \u003Cselect id=\\\"selectById\\\" parameterType=\\\"long\\\" resultType=\\\"User\\\">\n    SELECT \u003Cinclude refid=\\\"BaseCols\\\"\u002F> FROM user WHERE id=#{id}\n  \u003C\u002Fselect>\n\n  \u003Cselect id=\\\"selectAll\\\" resultType=\\\"User\\\">\n    SELECT \u003Cinclude refid=\\\"BaseCols\\\"\u002F> FROM user ORDER BY id\n  \u003C\u002Fselect>\n\n  \u003Cinsert id=\\\"insert\\\" parameterType=\\\"User\\\" useGeneratedKeys=\\\"true\\\" keyProperty=\\\"id\\\">\n    INSERT INTO user (username,email,age) VALUES (#{username},#{email},#{age})\n  \u003C\u002Finsert>\n\n  \u003Cupdate id=\\\"dynamicUpdate\\\" parameterType=\\\"User\\\">\n    UPDATE user\n    \u003Ctrim prefix=\\\"SET\\\" suffixOverrides=\\\",\\\">\n      \u003Cif test=\\\"username!=null\\\">username=#{username},\u003C\u002Fif>\n      \u003Cif test=\\\"email!=null\\\">email=#{email},\u003C\u002Fif>\n      \u003Cif test=\\\"age!=null\\\">age=#{age},\u003C\u002Fif>\n    \u003C\u002Ftrim>\n    WHERE id=#{id}\n  \u003C\u002Fupdate>\n\n  \u003Cdelete id=\\\"delete\\\" parameterType=\\\"long\\\">\n    DELETE FROM user WHERE id=#{id}\n  \u003C\u002Fdelete>\n\n  \u003Cselect id=\\\"query\\\" resultType=\\\"User\\\">\n    SELECT \u003Cinclude refid=\\\"BaseCols\\\"\u002F> FROM user\n    \u003Cwhere>\n      \u003Cif test=\\\"username!=null and username!=\\'\\'\\\">\n        AND username LIKE CONCAT(\\'%\\', #{username}, \\'%\\')\n      \u003C\u002Fif>\n      \u003Cif test=\\\"minAge!=null\\\"> AND age &gt;= #{minAge}\u003C\u002Fif>\n      \u003Cif test=\\\"maxAge!=null\\\"> AND age &lt;= #{maxAge}\u003C\u002Fif>\n      \u003Cif test=\\\"ids!=null and ids.size()>0\\\">\n        AND id IN\n        \u003Cforeach collection=\\\"ids\\\" item=\\\"id\\\" open=\\\"(\\\" separator=\\\",\\\" close=\\\")\\\">\n          #{id}\n        \u003C\u002Fforeach>\n      \u003C\u002Fif>\n    \u003C\u002Fwhere>\n  \u003C\u002Fselect>\n\n  \u003C!-- 一对多 -->\n  \u003CresultMap id=\\\"UserWithOrdersRM\\\" type=\\\"User\\\">\n    \u003Cid     property=\\\"id\\\"        column=\\\"u_id\\\"\u002F>\n    \u003Cresult property=\\\"username\\\"  column=\\\"username\\\"\u002F>\n    \u003Cresult property=\\\"email\\\"     column=\\\"email\\\"\u002F>\n    \u003Cresult property=\\\"age\\\"       column=\\\"age\\\"\u002F>\n    \u003Ccollection property=\\\"orders\\\" ofType=\\\"Order\\\">\n      \u003Cid     property=\\\"id\\\"       column=\\\"o_id\\\"\u002F>\n      \u003Cresult property=\\\"orderNo\\\"  column=\\\"order_no\\\"\u002F>\n      \u003Cresult property=\\\"amount\\\"   column=\\\"amount\\\"\u002F>\n      \u003Cresult property=\\\"status\\\"   column=\\\"status\\\"\u002F>\n      \u003Cresult property=\\\"createdAt\\\" column=\\\"o_created_at\\\"\u002F>\n    \u003C\u002Fcollection>\n  \u003C\u002FresultMap>\n\n  \u003Cselect id=\\\"selectUserWithOrders\\\" resultMap=\\\"UserWithOrdersRM\\\">\n    SELECT\n      u.id u_id, u.username, u.email, u.age,\n      o.id o_id, o.order_no, o.amount, o.status, o.created_at o_created_at\n    FROM user u\n    LEFT JOIN orders o ON u.id = o.user_id\n    WHERE u.id = #{id}\n  \u003C\u002Fselect>\n\n  \u003C!-- 分页 -->\n  \u003Cselect id=\\\"page\\\" resultType=\\\"User\\\">\n    SELECT \u003Cinclude refid=\\\"BaseCols\\\"\u002F> FROM user\n    ORDER BY id DESC\n    LIMIT #{offset}, #{size}\n  \u003C\u002Fselect>\n\n\u003C\u002Fmapper>\n```\n\n~~~xml\n\u003C!-- OrderMapper.xml -->\n\u003Cmapper namespace=\\\"com.example.demo.mapper.OrderMapper\\\">\n\n  \u003C!-- association：订单带用户（分步 + 懒加载） -->\n  \u003CresultMap id=\\\"OrderWithUserRM\\\" type=\\\"Order\\\">\n    \u003Cid     property=\\\"id\\\"      column=\\\"id\\\"\u002F>\n    \u003Cresult property=\\\"orderNo\\\" column=\\\"order_no\\\"\u002F>\n    \u003Cresult property=\\\"amount\\\"  column=\\\"amount\\\"\u002F>\n    \u003Cassociation property=\\\"user\\\" javaType=\\\"User\\\"\n                 column=\\\"user_id\\\" select=\\\"com.example.demo.mapper.UserMapper.selectById\\\"\n                 fetchType=\\\"lazy\\\"\u002F>\n  \u003C\u002FresultMap>\n\n  \u003Cselect id=\\\"selectOrderWithUser\\\" resultMap=\\\"OrderWithUserRM\\\">\n    SELECT id, user_id, order_no, amount FROM orders WHERE id=#{id}\n  \u003C\u002Fselect>\n\n  \u003C!-- 多对多：订单带产品列表 -->\n  \u003CresultMap id=\\\"OrderWithProductsRM\\\" type=\\\"Order\\\">\n    \u003Cid     property=\\\"id\\\"       column=\\\"o_id\\\"\u002F>\n    \u003Cresult property=\\\"orderNo\\\"  column=\\\"order_no\\\"\u002F>\n    \u003Cresult property=\\\"amount\\\"   column=\\\"amount\\\"\u002F>\n    \u003Ccollection property=\\\"products\\\" ofType=\\\"Product\\\">\n      \u003Cid     property=\\\"id\\\"     column=\\\"p_id\\\"\u002F>\n      \u003Cresult property=\\\"name\\\"   column=\\\"p_name\\\"\u002F>\n      \u003Cresult property=\\\"price\\\"  column=\\\"price\\\"\u002F>\n      \u003Cresult property=\\\"category\\\" column=\\\"category\\\"\u002F>\n    \u003C\u002Fcollection>\n  \u003C\u002FresultMap>\n\n  \u003Cselect id=\\\"selectOrderWithProducts\\\" resultMap=\\\"OrderWithProductsRM\\\">\n    SELECT\n      o.id o_id, o.order_no, o.amount,\n      p.id p_id, p.name p_name, p.price, p.category\n    FROM orders o\n    LEFT JOIN order_item oi ON o.id=oi.order_id\n    LEFT JOIN product p ON oi.product_id=p.id\n    WHERE o.id=#{id}\n  \u003C\u002Fselect>\n\n  \u003C!-- insert：主键回填 -->\n  \u003Cinsert id=\\\"insert\\\" parameterType=\\\"Order\\\" useGeneratedKeys=\\\"true\\\" keyProperty=\\\"id\\\">\n    INSERT INTO orders (user_id, order_no, amount, status)\n    VALUES (#{userId}, #{orderNo}, #{amount}, #{status})\n  \u003C\u002Finsert>\n\n  \u003C!-- insert：selectKey 示例（非 MySQL 必要） -->\n  \u003Cinsert id=\\\"insertUseSelectKey\\\" parameterType=\\\"Order\\\">\n    \u003CselectKey keyProperty=\\\"id\\\" resultType=\\\"long\\\" order=\\\"BEFORE\\\">\n      SELECT nextval(\\'order_seq\\')\n    \u003C\u002FselectKey>\n    INSERT INTO orders (id, user_id, order_no, amount, status)\n    VALUES (#{id}, #{userId}, #{orderNo}, #{amount}, #{status})\n  \u003C\u002Finsert>\n\n\u003C\u002Fmapper>\n~~~\n\n# 七、事务实战（Service 层）\n\n```java\n@Service\n@RequiredArgsConstructor\npublic class OrderService {\n  private final OrderMapper orderMapper;\n  private final SqlSessionFactory sqlSessionFactory;\n\n  @Transactional\n  public Long createOrder(Order order, List\u003COrderItem> items) {\n    orderMapper.insert(order); \u002F\u002F 回填 order.id\n    try (SqlSession session = sqlSessionFactory.openSession()) {\n      for (OrderItem it : items) {\n        session.insert(\\\"com.example.demo.mapper.OrderItemMapper.insert\\\", it);\n      }\n      \u002F\u002F 模拟异常可测试回滚\n      \u002F\u002F int x = 1\u002F0;\n    }\n    return order.getId();\n  }\n}\n```\n\n# 八、常见的坑\n\n- **命名参数**：多参数场景务必用 `@Param` 指定名称，与 XML 中占位符一致。\n- **驼峰映射**：开启 `map-underscore-to-camel-case` 或 SQL 中加别名。\n- **N+1**：能用联表就联表，分步查询配合懒加载谨慎使用。\n- **分页**：MySQL 直接 `LIMIT`；生产建议用分页插件（PageHelper \u002F MyBatis-Plus）。\n- **缓存**：二级缓存注意一致性与事务提交时机。\n- **动态 SQL**：优先 `\u003Cwhere>\u002F\u003Cset>\u002F\u003Ctrim>`，避免字符串拼接。\n- **返回 Map**：`resultType=\\\"map\\\"` 可快速做统计类查询。\n- **数据库差异**：`databaseId` + 多语句兼容不同方言。","我在本文中完整演示了MyBatis环境搭建、CRUD操作及XML映射文件的核心用法，涵盖resultMap、动态SQL、主键回填、多表关联与常见坑点，并给出可直接运行的代码示例，帮助读者快速掌握MyBatis开发要点。","这篇文章系统梳理了MyBatis的核心用法，从环境搭建、表结构设计到CRUD、结果映射、动态SQL、缓存及事务，覆盖全面。通过具体XML示例展示了`\u003CresultMap>`的一对多、多对多关联，以及`\u003Cwhere>`、`\u003Cforeach>`等动态标签，并附有常见坑点。内容务实，适合需要快速回顾或上手MyBatis的开发者参考，是一份实用性很强的技术指南。","https:\u002F\u002Fblog.strarry.top\u002Fuploads\u002Fcovers\u002F2026\u002F05\u002Fea8c8718f9b9447c85a89a0baf47aadc.png",127,0,"\u002Fposts\u002Fmybatis-quick-review","2025-08-20 10:29:49","2025-08-30 11:14:46",{"id":170,"name":491,"url":492},"技术教程","\u002Fcategory\u002Fcat-189",[494],{"id":306,"name":495,"url":496},"Mybatis","\u002Ftag\u002Ftag-37",{"title":498,"url":499},"Vue2和Vue3的区别简单总结：后端开发者需要了解的区别","\u002Fposts\u002Fvue2-vs-vue3-comparison",{"title":501,"url":502},"我用Vue3写了一个个人主页","\u002Fposts\u002Fvue3-personal-homepage",{"total_words":504,"total_visitors":505,"total_page_views":506,"online_users":486,"today_visitors":159,"today_pageviews":159,"yesterday_visitors":208,"yesterday_pageviews":222,"month_pageviews":299,"total_articles":204,"total_comments":286,"total_friends":246,"total_moments":170,"total_categories":175,"total_tags":193},"95k",512,2135]