
做后端开发这些年Spring Boot MyBatis Maven MySQL这套组合可以说是国内Java后端最经典的“上班四件套”。无论你是刚入行的新人还是从其他语言转过来的同学只要打开招聘网站看后端岗位要求几乎绕不开这几个名词。很多教程喜欢把这四个东西拆开单独讲结果就是“单个都懂一合起来就废”。这篇内容我就按实际项目的完整主线——从选型、搭建、写代码、调问题到最后部署把整套技术栈串起来讲一遍里面涉及到的坑和取舍都是实打实踩过的。这套组合能干什么简单说Spring Boot负责把业务代码跑起来并提供HTTP接口MyBatis负责和MySQL数据库打交道Maven负责管理项目依赖和构建打包MySQL负责数据存储。四者各司其职组合在一起就是一个能开发、能测试、能上线的最小可用后端系统。适合正在做毕业设计的学生、准备面试的初级开发以及前端转后端想快速上手完整链路的同学。1. 技术选型为什么Java后端绕不开这套组合1.1 每个组件在项目里的真实角色先说Spring Boot。它的核心价值是“自动配置”和“开箱即用”把过去Spring MVC项目里繁琐的XML配置、Web容器配置全给简化掉了。以前搭一个SSMSpring Spring MVC MyBatis项目光是applicationContext.xml、spring-mvc.xml、web.xml这些配置文件就能劝退一拨人。Spring Boot直接用注解和自动配置搞定内置Tomcat打一个jar包就能跑这对快速迭代和部署都非常友好。再来说MyBatis。它属于半自动ORM框架SQL由你自己写映射关系由框架帮你搞定。京东、阿里这些大厂内部很多团队到现在还是用MyBatis体系包括基于它扩展的TkMyBatis、MyBatis-Plus等原因很简单复杂查询SQL可控性强性能优化空间大DBA给过来的慢SQL能直接定位调优。相比Hibernate的全自动映射MyBatis在复杂业务下更踏实。Maven的角色就更好理解了它就是Java世界的“快递调度中心”。你项目里要用什么第三方库声明一下坐标Maven自动从中央仓库下载并管理依赖版本。它还能帮你完成编译、测试、打包、发布这些构建动作。没有Maven的话你光是把Spring Boot相关的十几个jar包手工拷到lib目录再配好ClassPath就足够折腾半天了。MySQL就不用多说了关系型数据库里的常青树开源免费性能可靠中小型项目乃至大型互联网项目的核心业务数据绝大多数都跑在MySQL上。它和MyBatis的组合支持动态SQL、分页、事务、多数据源等覆盖日常开发绰绰有余。1.2 这套方案相比其他组合的优势有些同学会问现在Spring Data JPA也挺火的为什么教程和公司里还是大量用MyBatis以我参与过的项目经验来看国内团队用MyBatis有个很现实的原因——团队成员SQL水平参差不齐用JPA有时候实体关系映射一复杂生成的SQL简直没法看。MyBatis让你把SQL明明白白写出来出了问题一眼就能看出是哪里的问题。这也是我们在团队里做技术选型时重点考量的点。另一个组合选择是Spring Boot JdbcTemplate。它比MyBatis更轻但查出来的结果集要自己封装业务复杂之后代码量会非常大而且没有缓存、二级缓存、插件机制这些生态支持。MyBatis在这两者之间正好是一个平衡点SQL可写可调映射自动化程度又足够高。1.3 从零到一拉通这套技术栈需要掌握的核心点如果你是在准备毕设或者个人项目需要重点关注下面这些核心能力点。第一会用Maven创建Spring Boot项目并理解POM文件里的依赖关系第二会配置application.yml里的数据源和MyBatis相关配置第三能写Mapper接口、XML映射文件并把动态SQL用熟练第四能用MySQL设计表结构并且会看执行计划调慢查询第五能对Spring Boot应用做打包部署处理线上环境的数据库迁移。把这五点串起来你就能走通一个完整的开发到部署闭环。下面我会按这个链路逐步拆开讲也会把一些面试常问的原理性东西穿插进去比如MyBatis的缓存机制、Maven的依赖仲裁等。2. 环境搭建与工程初始化Maven和MySQL是重灾区2.1 Maven下载、安装与配置的完整过程Maven的安装本身不难但很多同学卡在“环境变量配了还是用不了”这种莫名其妙的问题上。这里我按Windows和macOS分别说一下实操要点。Windows下先去Maven官网下载apache-maven-3.8.x-bin.zip解压到比如D:\apache-maven-3.8.8。然后配置环境变量MAVEN_HOME指向这个目录再在Path里加上%MAVEN_HOME%\bin。完成后在命令行输入mvn -v看到版本信息就说明装好了。macOS上更简单用Homebrew执行brew install maven或者直接下载二进制包解压并配置.bash_profile或.zshrc里的PATH。装完之后必须做的一件事是配置阿里云仓库镜像。为什么因为Maven中央仓库服务器在国外国内网络拉依赖经常超时——天知道第一次执行mvn package时卡在“Downloading...”界面等半天是什么体验。在Maven安装目录下的conf/settings.xml中找到mirrors节点加入如下配置mirror idaliyunmaven/id mirrorOfcentral/mirrorOf nameAliyun Maven Repository/name urlhttps://maven.aliyun.com/repository/public/url /mirror这个配置的意思是把所有中央仓库的请求都转发到阿里云仓库。配置完重启终端再执行项目构建速度会有质的飞跃。如果你在公司内网可能还需要配置私服地址同理把mirrorOf里的中心仓库指向公司Nexus就行。还有一点需要注意Maven的JDK版本兼容性。Maven 3.8可以配合JDK 8和JDK 11使用但如果你用的是JDK 17建议选择Maven 3.8.8以上版本否则某些插件可能报错。这个坑我在升级JDK的时候踩过花了不少时间才定位到是Maven版本过旧导致的编译异常。2.2 IDEA社区版能不能做Spring Boot开发这是不少学生党关心的问题IntelliJ IDEA Community Edition社区版能不能跑Spring Boot项目答案是能但要做一点调整。社区版不包含Spring Initializr但解决方式很简单——先去 start.spring.io 这个网站填写项目信息选定Spring Boot版本和依赖下载生成好的ZIP包再用IDEA直接打开即可。社区版对Java代码的编写、Maven构建、内置终端、Git支持都是完全可用的缺的只是企业版里针对Spring的图形化配置辅助功能。对于大多数学习和单体项目开发来说社区版完全够用。如果你要开发单体应用但发现缺少“Spring”相关的插件提示可以尝试在插件市场搜索并安装“Spring Boot Helper”等第三方插件但实际控制一下依赖就够了。真正的核心还是代码本身别被工具束缚了。2.3 MySQL安装与初始化Windows、macOS和Docker三条路线MySQL安装是热词里出现次数最高的痛点之一我分别说三条路线。Windows下推荐直接下载MySQL Installer选择MySQL Server 8.0版本。安装过程中会让你选认证方式这里务必选“Use Legacy Authentication”或确保你的客户端驱动支持caching_sha2_password。否则用老版本Navicat连8.0会报Authentication plugin错误。首次安装会让你设置root密码建议设置一个专门用于开发的简单密码比如root本机开发图方便。接着配置环境变量把MySQL安装目录下的bin加到Path里例如C:\Program Files\MySQL\MySQL Server 8.0\bin这样才能在命令行直接敲mysql命令。macOS下建议用brew install mysql装完执行mysql_secure_installation设置一下安全选项。然后启动服务brew services start mysql。如果你的项目需要指定版本比如5.7.44可以用brew安装指定版本或者在官网下载dmg包直接安装。如果你的操作系统是Windows 10、没有图形界面可用、或者想模拟生产环境则可以用Docker跑MySQL。这里有个常见失败情况docker run mysql时端口占用或数据目录权限问题。推荐命令如下docker run -d --name mysql8 -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDroot \ -e MYSQL_DATABASEtest_db \ -v /my/own/datadir:/var/lib/mysql \ mysql:8.0注意-v参数挂载宿主机目录时如果宿主机的MySQL数据目录之前有脏数据容器起不来通常报错“mysql: [ERROR] unknown variable”。解决方式是挂载一个全新空目录或者先不挂载启动一次再拷贝数据出来。2.4 Spring Boot项目的初始化与POM核心依赖初始化Spring Boot项目的思路上面提过了用start.spring.io拉一个骨架最稳。这里我给出一个典型的Maven POM关键依赖列表适用于Spring Boot 2.7.x版本2.3.x、2.6.x系列其实同理主要差异在依赖版本上。你需要引入四类依赖web、mybatis、mysql驱动以及lombok可选。parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.7.18/version relativePath/ /parent dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version2.3.1/version /dependency dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId scoperuntime/scope /dependency /dependencies注意一个坑mybatis-spring-boot-starter并不会帮你引入MySQL驱动两者是分开的。有些教程会漏掉驱动依赖导致启动时报告“No suitable driver found”。在Spring Boot 2.7.x里MySQL驱动的groupId是com.mysqlartifactId是mysql-connector-jSpring Boot会帮你管理版本号。如果你用的是老版本Spring Boot 2.3.x则应该是mysql-connector-java这里要留意版本对应关系。3. 项目实战核心从建表到MyBatis映射再到动态SQL3.1 需求分析与表设计从业务到数据库的落地动手写代码之前最重要的其实是需求和表设计。有同学问“Java后端怎样和产品经理确定需求”我自己的经验是先看原型图把页面能看到的字段全部列出来再思考字段之间的关联然后反推表结构。遇到拿不准的情况、比如“订单状态这个字段到底有几种状态”一定当场问清楚而不是自己拍脑袋。需求中每个不确定点到开发后期都会变成返工成本。以“基于Spring Boot的大学生就业推荐系统”这类典型毕设为例核心业务可以拆成学生、企业、职位、投递记录、推荐结果这几张表。设计表结构时有个原则先定业务主键再定唯一约束和普通索引最后再考虑扩展字段。比如职位表里可以加一个status字段表示上/下架状态用tinyint类型即可0下架、1上架别用字符串省空间还快。MySQL 8.0默认字符集是utf8mb4建议所有表都显式指定否则表情符号或生僻字入库会乱码。建表语句示例CREATE DATABASE IF NOT EXISTS job_recommend DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; CREATE TABLE t_job ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 主键, company_id BIGINT NOT NULL COMMENT 企业ID, title VARCHAR(128) NOT NULL COMMENT 职位名称, salary_min DECIMAL(10,2) DEFAULT 0 COMMENT 最低薪资, salary_max DECIMAL(10,2) DEFAULT 0 COMMENT 最高薪资, status TINYINT NOT NULL DEFAULT 1 COMMENT 状态1上架 0下架, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, KEY idx_company_id (company_id), KEY idx_status (status) ) ENGINEInnoDB COMMENT 职位信息表;注意一个小习惯字段名统一用下划线风格Java实体类里用驼峰通过MyBatis的map-underscore-to-camel-case配置自动映射省去大量手写resultMap的工作。3.2 MyBatis的Mapper接口与XML映射最佳实践MyBatis有两种写法一种注解写SQL一种XML写SQL。我个人建议单表简单增删改查用注解可以但多表关联、动态条件查询一律用XML。原因有两个第一XML里写动态SQL的可读性好第二SQL和Java代码分离后期DBA优化SQL时不用碰Java代码。Mapper接口写法如下Mapper public interface JobMapper { ListJob searchJobs(Param(keyword) String keyword, Param(minSalary) BigDecimal minSalary, Param(status) Integer status); }对应的XML文件放在src/main/resources/mapper/JobMapper.xml?xml version1.0 encodingUTF-8? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacecom.example.demo.mapper.JobMapper select idsearchJobs resultTypecom.example.demo.entity.Job SELECT id, company_id, title, salary_min, salary_max, status FROM t_job where if testkeyword ! null and keyword ! AND title LIKE CONCAT(%, #{keyword}, %) /if if testminSalary ! null AND salary_max gt; #{minSalary} /if if teststatus ! null AND status #{status} /if /where ORDER BY created_at DESC /select /mapper这里有两个细节值得关注。第一个是 标签的用法它会自动去掉第一个条件前面的AND这是MyBatis动态SQL里“条件不生效”以外最常见的痛点——多余的AND导致SQL语法错误。第二个是“”这个写法因为XML文件中“”和“”是特殊字符必须转义否则解析报错。如果不喜欢转义也可以把比较符号写进CDATA区里。3.3 动态SQL“条件不生效”的排查套路热词里有一条“mybatis条件不生效”这问题我见过太多次了归纳起来主要有三种原因。第一种是test表达式里的属性名写错MyBatis对不到值就按false处理第二种是传参没有加Param注解XML里引用不到第三种是if条件里写的判断和实际类型不匹配比如Integer类传了0你判断“teststatus ! null and status ! ”这个表达式在OGNL里对Integer类型会报错或者判断异常。排查方法也有套路。第一步在application.yml里开启SQL日志输出看MyBatis实际生成的SQL长什么样mybatis: configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl这样每次执行查询都会在控制台打印解析后的SQL和参数。第二步看日志里的“ Preparing”和“ Parameters”如果SQL里少了某个条件就说明对应的test判断是false去检查参数名和表达式。第三步如果你用了Spring Boot 3.0以上版本注意MyBatis Spring Boot Starter版本必须用3.x否则有些标签解析会有兼容问题。3.4 MyBatis一级缓存、二级缓存机制与实现MyBatis缓存是面试高频问题也是实际排查“数据查出来是旧的”这类问题的切入点。一级缓存是SqlSession级别的同一个SqlSession里执行两次相同查询第二次直接返回缓存对象不查数据库。但Spring Boot整合MyBatis后默认每个Mapper方法调用都新建SqlSession通过SqlSessionTemplate所以一级缓存基本感知不到。注意一级缓存不需要配置默认开启。二级缓存是Mapper级别的可以跨SqlSession共享。实现方式是在Mapper XML里加一行cache evictionLRU flushInterval60000 size512 readOnlytrue/配置表示缓存淘汰策略为LRU、每60秒刷新一次、最多缓存512个对象、只读模式。开启后查询结果会先放二级缓存同namespace下其他SqlSession的查询会直接命中缓存。但这里有一个大坑如果表数据被其他应用或手工修改缓存不会自动失效会导致数据陈旧。所以在实际项目中涉及频繁更新的表不推荐开二级缓存或者只在配置表这种低频变更的场景下用。我当时在订单系统里吃过亏开了二级缓存之后隔几分钟查出来的订单状态还是旧的最后把缓存关掉才消停。3.5 Maven多模块项目与多个后端项目合并的要点热词里有“多个java后端项目合并要点有哪些”这在很多公司是常见需求——几个小系统做成独立服务跑后面发现维护成本高打算合并成一个多模块Maven项目。合并时最核心的动作是梳理POM的父子关系。父POM负责统一管理依赖版本子模块之间通过 引入。比如你要把用户系统和订单系统合并父POM里放公共依赖和dependencyManagement子模块分成user-service、order-service、common-core。合并时最容易出的问题有三个。第一是包名冲突两个项目里有同名类合并后编译报错要提前做包结构调整第二是配置文件冲突多个application.yml会被覆盖需要统一拆成不同profile比如application-user.yml、application-order.yml第三是数据库连接配置冲突多模块单应用只能有一个数据源配置如果两个项目原来连不同的库合并时要考虑使用动态数据源方案或者拆分为微服务。这里补充一句如果两个系统业务关联度很低合并反而不如保持两个独立服务别为了“合并”而合并。4. 数据访问优化与进阶SQL调优与分页实现4.1 MySQL排序与分页的性能陷阱做后端开发难免会遇到“MySQL排序”相关的性能问题很多人直接在SQL里ORDER BY某个字段数据量一上来就变慢。根本原因是排序字段上没有索引MySQL只能用filesort文件排序把结果集放到临时表里排。优化思路就一条让排序字段走索引。比如按created_at排序的同时按status过滤那就建联合索引(status, created_at)过滤和排序都能命中索引。分页的大坑在深翻页比如LIMIT 100000, 20这种写法MySQL要先扫10万行再丢弃前10万行越翻越慢。常见优化手段是“延迟关联”或“子查询分页”。延迟关联的写法是先查出主键范围再回表查完整数据SELECT t.* FROM t_job t INNER JOIN ( SELECT id FROM t_job ORDER BY created_at DESC LIMIT 100000, 20 ) tmp ON t.id tmp.id;这个写法让内层子查询只走索引覆盖不回表速度提升非常明显。实测在百万级数据场景下深翻页耗时能从几秒降到几百毫秒。4.2 MySQL 8.0窗口函数与分组取Top NMySQL 8.0引入窗口函数之后很多以前要写子查询或变量的SQL变得简单非常多。举个例子“查每个企业薪资最高的职位”在8.0之前你得用相关子查询或者临时表自连接现在直接SELECT company_id, title, salary_max FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY company_id ORDER BY salary_max DESC) AS rn FROM t_job ) t WHERE rn 1;窗口函数PARTITION BY把数据按企业分组ORDER BY在组内排序ROW_NUMBER()为每一组生成行号外层取rn1就是每组最大。这个写法可读性高执行效率也不错面试聊到MySQL优化时可以提一下。4.3 MyBatis分页插件与手写分页的取舍实际项目里MyBatis分页一般用PageHelper插件依赖如下dependency groupIdcom.github.pagehelper/groupId artifactIdpagehelper-spring-boot-starter/artifactId version1.4.6/version /dependency使用方式是在查询前调用PageHelper.startPage(pageNum, pageSize)然后紧跟着执行Mapper查询。这里有几个禁忌必须记住startPage和查询之间不能有别的SQL否则分页会作用到别的查询上PageHelper只对紧跟着的一条查询生效不要试图复用它在循环里调用分页查询是大忌会导致线程安全问题。如果项目对分页SQL有特殊要求比如多表join并带聚合查询PageHelper生成的count语句偶尔会不准确。这时候我建议手写分页本质就是两条SQL一条count(*)、一条limit查询。虽然多写一点代码但完全可控反而是我更推荐的生产实践。5. 前后端协作与接口设计跨域、重复提交、第三方对接和监控5.1 后端跨域的真正解法和注意事项前后端分离项目里“后端跨域”是必考题。跨域本质是浏览器的同源策略限制后端解决跨域的通用方法是CORS跨域资源共享。在Spring Boot里最简单的配置是使用CrossOrigin注解加在Controller类上或者写一个全局CorsFilter。但这里我想多说一句跨域不是后端单方面解决就完事的生产环境更常见的做法是用Nginx做反向代理让前后端同源从根子上规避跨域问题。开发环境才依赖CORS配置。如果你在后端配置了CORS还不行先看浏览器Network面板里的OPTIONS预检请求是否返回200再看Access-Control-Allow-Origin响应头是否带上了域名。另外携带Cookie跨域时allowedOrigins不能写“*”必须写具体域名并且需要设置allowCredentials(true)。这个细节很多人栽过。5.2 前后端按钮重复提交的校验方案热词里有“前后端对于按钮重复提交校验方法”这是电商、订单类项目里非常关键的一环。前端的思路众所周知点击按钮后置灰请求完成或超时后再恢复。但前端禁用挡不住绕过页面的直接请求所以后端必须做幂等校验。常用的后端方案是“Token令牌”Redis。流程是前端进入下单页时向后端请求一个幂等Token后端把Token存Redis并设置过期时间前端提交订单时带着这个Token后端先删除Redis里的Token删成功了才执行下单逻辑删除失败说明请求是重复的直接拒绝。这里关键在“先删令牌再执行业务”而不是“先查令牌再删”因为先查后删在并发请求下会出现两个请求都查到Token存在的情况导致重复下单。要是用先查再删必须加分布式锁否则还是有窗口期。5.3 给第三方开放的接口应该放在哪热词里问“Spring Boot对外提供的接口给第三方应该放在哪里是单独服务还是放在对应模块”这问题要分情况回答。如果是第三方需要调你们的核心业务接口比如查询订单状态或回传支付结果建议不要直接暴露在内部业务服务上而是单独建一个OpenAPI模块或服务做独立的鉴权、限流、签名验签逻辑。这样内部接口的权限体系和对外开放策略不会互相干扰。如果第三方接口量很少只是回调通知那放在原有服务里开一个独立Controller前缀也够用但要做加密验签和IP白名单两个基本防护。签名的推荐方案是HMAC-SHA256双方约定AppId和AppSecret请求参数加时间戳防重放。需要注意的是对外接口的响应结构要统一比如code/message/data三层结构并且对异常情况也要有明确的错误码不能把内部异常堆栈直接抛回去。5.4 Spring Boot Admin监控的接入方法部署上线之后你总得知道服务活没活、内存够不够“Spring Boot Admin”是热词里的高频项。它是一个轻量监控面板分服务端和客户端两部分。服务端新建一个Spring Boot项目加依赖dependency groupIdde.codecentric/groupId artifactIdspring-boot-admin-starter-server/artifactId version2.7.10/version /dependency然后在启动类加EnableAdminServer注解。被监控的服务只需要加spring-boot-admin-starter-client依赖并在application.yml里配置服务端地址spring: boot: admin: client: url: http://localhost:9000 management: endpoints: web: exposure: include: *这个面板能展示实例的在线状态、JVM内存、线程数、HTTP接口调用情况甚至可以通过日志查看器远程看日志。对于单机项目已经足够。如果服务数量多了可以考虑上Prometheus Grafana那套监控体系更专业但学习成本也上了一个台阶。6. 构建打包与部署全流程Maven生命周期、镜像部署与常见问题6.1 Maven构建生命周期与打包策略Maven的构建过程可以用一条链路概括validate → compile → test → package → install → deploy。日常开发最常用的是mvn clean package。clean会删掉target目录package会执行编译、跑测试并打包成jar/war。Spring Boot项目默认打可执行jar包用spring-boot-maven-plugin重打包让普通jar包变成可运行的胖jar包。构建时需要注意两件事。第一执行package前如果不想跑单元测试可以用-DskipTests跳过但强烈建议本地至少跑一次完整测试再交付。第二配置 Maven 打包时不要把本地配置文件覆盖掉线上配置。我的习惯是打包时用profile指定环境比如mvn clean package -Pprod把生产环境的application-prod.yml打进去。6.2 Docker部署MySQL失败的原因排查热词里“docker安装mysql失败”出现了不止一次这里集中讲最常见的几个原因。第一个是端口冲突。3306端口被本机MySQL占用了容器启动失败。解决办法是改映射端口比如把宿主机的3307映射到容器的3306然后项目里的JDBC连接串改成3307。第二个是权限问题容器内的MySQL进程默认以mysql用户运行挂在宿主机目录的权限不对就会启动报错。解决办法是给宿主机目录开放权限chown -R 1000:1000 /my/own/datadir第三个是配置文件挂载错误。如果你把宿主机my.cnf挂载到容器里MySQL版本不一致时会直接启动失败报unknown variable。解决方法是先不挂配置文件启动容器确认版本兼容后再挂载或者只挂载conf.d目录里的增量配置。6.3 从jar包到系统服务的部署经验打包好的Spring Boot jar包部署时我不推荐直接用java -jar丢在终端里因为退出终端进程就断了。Linux下最省事的方式是写Systemd服务。在/etc/systemd/system/myapp.service里写入[Unit] DescriptionMy Spring Boot App Afternetwork.target [Service] Userroot ExecStart/usr/bin/java -jar /opt/app/myapp.jar --spring.profiles.activeprod Restartalways RestartSec5 [Install] WantedBymulti-user.target配置完毕执行systemctl daemon-reload、systemctl start myapp、systemctl enable myapp。这样服务崩了会自动重启开机自动拉起比nohup java -jar可靠得多。如果服务器内存有限可以在启动命令上加JVM参数比如-Xms256m -Xmx512m避免默认堆占掉整台机器内存。热词里还有“rpm安装mysql 5.7.44”这种场景适用于离线服务器或特殊版本需求。流程就是下载mysql-community-server的rpm包执行rpm -ivh按依赖顺序安装再初始化数据目录并启动mysqld服务。这个安装方式比较老但一些国企或银行内网环境没有Docker和在线Yum源就只能这么处理。6.4 部署后需要立刻检查的三个东西部署完成后我建议立刻检查三件事。第一确认防火墙和云安全组是否放行了应用端口不然接口“永远不通”第二检查数据库连接账号的主机权限MySQL8.0默认root只允许localhost登录如果应用和数据库不在同一台机器要先授权远程访问CREATE USER app% IDENTIFIED BY password; GRANT SELECT, INSERT, UPDATE, DELETE ON mydb.* TO app%; FLUSH PRIVILEGES;第三查看应用启动日志确认没有WARN级别的数据源告警。Spring Boot的默认日志不落盘只在控制台输出建议配置Logback把日志写到文件否则重启后日志全丢了排障会变得很被动。7. 真题与面试高频点MyBatis缓存、Maven依赖机制和Spring Boot原理7.1 MyBatis面试题从缓存到动态SQL原理面试官问MyBatis必绕不开缓存和动态SQL。动态SQL的本质是基于OGNL表达式的SQL拼接你写的 、 、 标签在解析阶段会被翻译成对应的SQL片段文本。理解这一点后你就明白为什么test里的参数引用要加Param——因为OGNL要通过这个名字在上下文中取值。缓存问题上面讲过了一级缓存是SqlSession级默认开启二级缓存是namespace级需要手动配置。真正容易被追问的是“开启二级缓存后如果一个Mapper里出现了多表查询会把其他表的数据也缓存吗”。答案是会而且一旦其他表数据变了这个缓存不会自动失效这就是为什么多表关联场景不建议开二级缓存。如果你确实想开必须在SQL里配置flushCachetrue或者管理好表级失效逻辑。7.2 Maven依赖仲裁与依赖冲突排查“Maven依赖报错”是每个Java开发都遇到过的噩梦。依赖冲突的本质是Maven的“最短路径优先”原则——两个依赖传递引入同一个库的不同版本Maven默认选路径最短的那个。如果路径一样长谁先声明谁生效。这个原则平时没什么存在感一旦两个版本API不兼容运行时抛NoSuchMethodError或ClassNotFoundException你就知道什么是“依赖地狱”了。排查依赖冲突的正确姿势是用mvn dependency:tree把整个项目的依赖树打出来然后用exclusions标签排除多余的版本。比如dependency groupIdorg.apache.poi/groupId artifactIdpoi/artifactId version5.2.3/version exclusions exclusion groupIdcommons-io/groupId artifactIdcommons-io/artifactId /exclusion /exclusions /dependency还有一个使用习惯值得注意父POM里的dependencyManagement只管版本管理不会真正引入依赖。子模块要用哪个依赖还是要自己声明。很多同学在父POM里加了依赖坐标子模块里想当然直接用结果编译报“找不到符号”。7.3 Spring Boot自动配置的实质Spring Boot之所以能“开箱即用”核心是EnableAutoConfiguration注解。它通过SPI机制加载META-INF/spring.factories文件里声明的所有AutoConfiguration类再按条件注解ConditionalOnClass、ConditionalOnMissingBean、ConditionalOnProperty等决定哪些配置生效。比如DataSourceAutoConfiguration只要classpath下有javax.sql.DataSource就自动帮你配好DataSource如果你自己定义了DataSourceBean它又会自动退让。理解这个机制对排查启动问题非常关键。比如你引入了mybatis-spring-boot-starter但没配数据源启动时就会报“Failed to configure a DataSource”这就是因为自动配置尝试创建数据源但没有连接参数。反过来如果你想让某个自动配置不生效可以在启动类上加exclude属性或者通过spring.autoconfigure.exclude配置项排除。这个知识点不光面试爱考实际排查疑难杂症也很管用。8. 从单体到多模块的演进实践跨境商城系统与推荐系统的落地参考8.1 多商户跨境商城系统的架构参考热词里有一条“spring boot mybatis的java开源多商户跨境商城源码下载”这类项目在GitHub上确实很多比如基于若依框架二次开发的商城系统。如果你要拿这种项目来学习或者改造建议先理清它的模块划分。典型的多商户商城包括商户管理模块、商品模块、订单模块、支付模块、营销模块和用户模块。用Spring Boot单体应用承载这些模块时代码结构上要按功能包划分比如controller、service、mapper、entity。但更推荐的是用Maven多模块结构mall-parent ├── mall-common // 公共工具、常量、统一返回体 ├── mall-system // 后台管理模块 ├── mall-order // 订单模块 ├── mall-product // 商品模块 └── mall-front // 前台API模块这种结构对单体应用来说已经足够而且为将来拆微服务留了后路。跨境商城比普通商城多出来的东西是多币种结算、国际物流、海关报关数据对接这些在表设计时要提前预留字段。比如订单表里要有币种字段currency_code结算汇率要单独存表不能靠写死在代码里的所谓“当天汇率”。8.2 推荐系统项目里的协同过滤与冷启动大学生就业推荐系统这类项目核心是一个简单的推荐引擎。很多同学一上来就想用机器学习协同过滤其实对于课程设计和毕设来说一个可解释的规则推荐已经足够了。最简单的做法是基于内容的推荐先从学生表取专业、技能标签从职位表取技能要求标签用标签匹配度计算职位得分按分数排序推给用户。SQL层面用LIKE匹配标签或者用中间表存关联关系均可。冷启动问题是这类系统绕不开的。新学生没有行为数据时怎么推荐我的做法是用专业大类做兜底把该专业对口的通用岗位铺一轮。这个逻辑可以写成SQL加Java逻辑混合实现核心是先跑一个兜底查询再跑个性化查询两个结果集合并去重。这种实现完全可以用MyBatis的多个查询方法组合完成不用引入额外框架。8.3 若依框架后端的学习价值与合作边界热词里提到“ruoyi框架后端”若依RuoYi是国内最流行的Spring Boot后台管理脚手架之一。它集成了Spring Boot MyBatis Shiro/Spring Security Vue自带用户、部门、角色、菜单权限和代码生成器。我见过很多公司的内部后台系统就是拿若依改的。它的价值在于让你看到一套标准化的RBAC权限模型是怎么落地的尤其是数据权限的SQL拼接思路非常值得学习。不过我不建议直接把若依的代码原封不动抄进毕设因为查重是一方面更重要的是如果你说不清每一个表的作用和权限流程答辩时必然被老师问穿。9. 常见问题与排查技巧实录我的排障流水账9.1 问题速查表我在实际项目中遇到并解决过的问题里挑几个最高频的整理成速查表方便你直接对照排查。现象可能原因排查手段启动报Failed to configure a DataSource没有配置数据源或JDBC驱动缺失检查application.yml的spring.datasource配置检查pom是否有mysql驱动控制台SQL日志不打印mybatis.configuration.log-impl未设置设置log-impl为StdOutImpl页面报跨域错误后端未配置CORS或前端端口不匹配看Network预检请求状态检查Access-Control-Allow-*头Maven下载依赖超级慢未配置阿里云镜像修改settings.xml配置mirrorMySQL连接报Public Key Retrieval is not allowedJDBC连接串缺少allowPublicKeyRetrieval参数在JDBC URL上加?allowPublicKeyRetrievaltrueuseSSLfalseDocker容器启动后马上退出数据目录权限或配置挂载错误用docker logs mysql8查看启动日志定位查询结果字段全是nullmap-underscore-to-camel-case未开启开启驼峰映射或手写resultMap9.2 MySQL连接报Public Key Retrieval的解决办法这个问题几乎每个用MySQL 8.0的人都遇到过IDEA里测试连接或者应用启动时经常报“Public Key Retrieval is not allowed”。原因理解起来很绕MySQL 8.0默认使用caching_sha2_password认证客户端第一次连接时如果连接不是SSL加密的需要向服务器请求公钥做密码加密传输而JDBC驱动默认禁止了这个请求。解决办法就是在JDBC连接串里显式加两个参数jdbc:mysql://localhost:3306/mydb?useSSLfalseallowPublicKeyRetrievaltrue注意useSSLfalse在开发环境没问题生产环境如果对安全有要求应该走SSL加密连接同时配置证书而不是简单关掉SSL。这一点在面试时展示出来会很加分。9.3 Spring Boot跨域配置的一个容易忽视的问题我在实际项目中遇到过这样一种情况CORS配置看起来完全正确但前端就是报跨域。最后查出来是因为接口走了一个通用拦截器拦截器在处理OPTIONS预检请求时直接返回了401导致浏览器拿不到CORS头。所以记住一个原则如果你写了拦截器或者过滤器必须对OPTIONS请求放行否则CORS配置形同虚设。9.4 事务不生效的排查心得MyBatis整合Spring Boot后事务很简单在Service方法上加Transactional就行。但“事务不生效”也是常见问题。我遇到过的原因有两种。第一种是方法被同类内部调用比如方法A调用了本类的方法BB上的Transactional不生效。原理是Spring事务依赖AOP代理内部调用不会经过代理对象。第二种是异常被代码吃掉了比如try-catch里catch了Exception但没有抛出事务就不会回滚。正确的做法是catch块里必须抛出RuntimeException或者使用TransactionTemplate手动控制。这个道理我当年是在生产环境用一条脏数据换来的教训。10. 尾声一点个人的实操感受写到这里这套Spring Boot MyBatis Maven MySQL的组合拳基本覆盖了从开发到部署的所有关键环节。我个人在实际项目中的体感是这套技术栈的入门门槛已经很低了但真正能从“能跑”做到“跑得好”的人并不多。差距往往不在某个框架的高级特性上而在于你对底层机制的理解——比如能不能说清MyBatis的缓存策略、Maven的依赖仲裁、Spring Boot的三个条件注解。希望这篇内容不只是帮你把项目跑起来更能让你对这些平时“看不见摸不着”的原理有一个清晰的把握。最后再分享一个我自己的习惯每次搭建新项目我都会花十分钟把Maven的settings.xml检查一遍把MySQL的字符集和时区确认一遍再决定表结构。磨刀不误砍柴工环境问题排查的半小时省下来能写掉一个接口。这套流程跑熟了你也就具备了独立把一个后端项目从零带到上线交付的能力了。