1. 项目概述
这个后端技术栈组合就像一套精密的瑞士军刀,Spring Boot是那把主刀,MyBatis是开瓶器,Maven是螺丝刀,MySQL则是剪刀。我在过去五年里用这套工具开发过电商平台、医疗系统和物联网中间件,今天就把实战中积累的干货一次性分享出来。
这套组合拳特别适合需要快速迭代的中小型项目,比如最近帮朋友做的健身房会员系统,从零开始到上线只用了三周。Spring Boot 2.7 + MyBatis 3.5 + MySQL 8.0是目前最稳定的版本组合,Maven建议用3.8以上版本避免依赖下载问题。
重要提示:新手常犯的错误是直接照搬网上的配置,实际上不同版本组合的兼容性差异很大,本文所有配置都经过生产环境验证。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境搭建与工程初始化
2.1 开发环境准备
我的标准开发环境是JDK17+IntelliJ IDEA 2023+MySQL 8.0+Docker(用于本地测试),这是经过20多个项目验证的黄金组合。JDK17的LTS支持到2029年,比JDK8的性能提升40%以上。
安装Maven时有个小技巧:在settings.xml中加入阿里云镜像:
xml复制<mirror>
<id>aliyunmaven</id>
<mirrorOf>*</mirrorOf>
<name>阿里云公共仓库</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
这能让依赖下载速度提升10倍,特别是当需要下载Spring Boot那上百个依赖的时候。
2.2 工程初始化细节
用Spring Initializr生成项目时,我必选的依赖除了Web和MyBatis,还有:
- Lombok(减少样板代码)
- DevTools(热部署)
- Actuator(监控端点)
- Configuration Processor(配置提示)
工程结构我推荐这种分层方式:
code复制src
├── main
│ ├── java
│ │ └── com
│ │ └── example
│ │ ├── config(配置类)
│ │ ├── controller(API入口)
│ │ ├── service(业务逻辑)
│ │ │ ├── impl(实现类)
│ │ ├── dao(数据访问)
│ │ ├── entity(实体类)
│ │ ├── dto(数据传输对象)
│ │ └── Application.java
│ └── resources
│ ├── mapper(MyBatis映射文件)
│ ├── static(静态资源)
│ ├── templates(模板文件)
│ └── application.yml
3. MyBatis深度集成实战
3.1 高效配置技巧
在application.yml中配置MyBatis时,这几个参数最关键:
yaml复制mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.example.entity
configuration:
map-underscore-to-camel-case: true
default-fetch-size: 100
default-statement-timeout: 30
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
踩坑记录:千万别在生产环境开启StdOutImpl日志,会严重拖慢性能!建议用SLF4J配合Logback,按需开启DEBUG日志。
3.2 动态SQL高级用法
除了常规的增删改查,MyBatis的动态SQL能实现很多骚操作。比如这个按条件更新的写法:
xml复制<update id="updateSelective">
UPDATE user
<set>
<if test="username != null">username=#{username},</if>
<if test="email != null">email=#{email},</if>
<if test="status != null">status=#{status}</if>
</set>
WHERE id=#{id}
</update>
批量插入的优化方案(MySQL):
xml复制<insert id="batchInsert" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user (username, email) VALUES
<foreach collection="list" item="item" separator=",">
(#{item.username}, #{item.email})
</foreach>
</insert>
4. 生产级部署方案
4.1 数据库优化配置
MySQL的my.cnf要针对Spring Boot应用调整:
ini复制[mysqld]
innodb_buffer_pool_size = 4G # 建议设为物理内存的50-70%
innodb_log_file_size = 256M
max_connections = 200
wait_timeout = 600
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
Spring Boot连接池配置(HikariCP):
yaml复制spring:
datasource:
hikari:
maximum-pool-size: 20
minimum-idle: 5
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000
connection-test-query: SELECT 1
4.2 容器化部署实战
Dockerfile的优化写法:
dockerfile复制FROM eclipse-temurin:17-jre-jammy
WORKDIR /app
COPY target/*.jar app.jar
RUN bash -c 'touch /app.jar'
ENV JAVA_OPTS="-XX:+UseG1GC -Xmx512m -Xms256m -Dspring.profiles.active=prod"
EXPOSE 8080
ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar app.jar"]
用docker-compose编排MySQL和Spring Boot:
yaml复制version: '3.8'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root123
MYSQL_DATABASE: app_db
volumes:
- mysql_data:/var/lib/mysql
ports:
- "3306:3306"
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
timeout: 5s
retries: 10
app:
build: .
ports:
- "8080:8080"
depends_on:
mysql:
condition: service_healthy
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/app_db
SPRING_DATASOURCE_USERNAME: root
SPRING_DATASOURCE_PASSWORD: root123
volumes:
mysql_data:
5. 性能调优与监控
5.1 JVM参数优化
在application.yml中加入:
yaml复制server:
tomcat:
threads:
max: 200
min-spare: 20
connection-timeout: 5000
accept-count: 100
启动参数推荐:
code复制-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:InitiatingHeapOccupancyPercent=35
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/tmp/heapdump.hprof
-Xlog:gc*:file=/tmp/gc.log:time:filecount=5,filesize=10M
5.2 监控方案集成
Spring Boot Actuator配置:
yaml复制management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
endpoint:
health:
show-details: always
prometheus:
enabled: true
metrics:
export:
prometheus:
enabled: true
配合Grafana监控看板,重点关注这些指标:
- JVM内存使用率
- GC次数和时间
- Tomcat线程池活跃数
- MySQL连接池等待数
- 接口QPS和响应时间
6. 常见问题解决方案
6.1 MyBatis典型异常处理
-
Invalid bound statement错误:
- 检查mapper.xml的namespace是否对应接口全限定名
- 确认maven是否编译了xml文件(需要在pom.xml中配置资源过滤)
-
慢SQL问题:
- 使用MyBatis-Plus的PerformanceInterceptor插件
- 配置阿里云Druid的WallFilter拦截危险SQL
-
事务失效场景:
- 确保@Transactional注解的方法是被代理对象调用的
- 检查异常类型是否被捕获未抛出RuntimeException
6.2 部署问题排查清单
-
应用启动失败:
java -jar --debug app.jar查看详细日志- 检查数据库连接配置(特别是密码特殊字符)
-
接口响应慢:
arthas trace com.example.controller.* *追踪方法调用链- 检查MySQL慢查询日志
-
内存泄漏:
jmap -histo:live <pid>查看对象分布jstack <pid>分析线程阻塞情况
7. 进阶技巧与扩展
7.1 MyBatis插件开发
实现一个分页插件示例:
java复制@Intercepts(@Signature(type= StatementHandler.class,
method="prepare",
args={Connection.class, Integer.class}))
public class PaginationInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler handler = (StatementHandler) invocation.getTarget();
BoundSql boundSql = handler.getBoundSql();
String sql = boundSql.getSql();
// 识别分页参数并改写SQL
if (boundSql.getParameterObject() instanceof PageParam) {
PageParam pageParam = (PageParam) boundSql.getParameterObject();
String newSql = sql + " LIMIT " + pageParam.getOffset() + "," + pageParam.getLimit();
resetSql(handler, boundSql, newSql);
}
return invocation.proceed();
}
private void resetSql(...) {
// 通过反射修改SQL
}
}
7.2 多数据源配置
主从数据库配置方案:
java复制@Configuration
@MapperScan(basePackages = "com.example.mapper.primary",
sqlSessionFactoryRef = "primarySqlSessionFactory")
public class PrimaryDataSourceConfig {
@Bean
@ConfigurationProperties("spring.datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
public SqlSessionFactory primarySqlSessionFactory(
@Qualifier("primaryDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setMapperLocations(
new PathMatchingResourcePatternResolver()
.getResources("classpath:mapper/primary/*.xml"));
return bean.getObject();
}
}
8. 安全加固方案
8.1 SQL注入防护
- 永远不要用字符串拼接SQL
- 使用MyBatis的#{}语法
- 配置Druid的WallFilter:
yaml复制spring:
datasource:
druid:
filters: stat,wall
wall:
config:
drop-table-allow: false
alter-table-allow: false
8.2 API安全防护
- 接口签名验证:
java复制@RestControllerAdvice
public class SignInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
String sign = request.getHeader("X-Sign");
String timestamp = request.getHeader("X-Timestamp");
// 验证时间戳有效期(防止重放攻击)
if (System.currentTimeMillis() - Long.parseLong(timestamp) > 300000) {
throw new ApiException("请求已过期");
}
// 验证签名
String expectedSign = buildSign(request, timestamp);
if (!expectedSign.equals(sign)) {
throw new ApiException("签名无效");
}
return true;
}
private String buildSign(HttpServletRequest request, String timestamp) {
// 按约定规则生成签名
}
}
- XSS防护:
java复制@Bean
public FilterRegistrationBean<XssFilter> xssFilter() {
FilterRegistrationBean<XssFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(new XssFilter());
registration.addUrlPatterns("/*");
registration.setName("xssFilter");
return registration;
}
