1. 项目概述与环境准备
在Java企业级开发领域,SpringBoot+MyBatis+MySQL的技术组合已成为中小型项目的黄金搭档。作为从业多年的全栈开发者,我见证过太多团队在项目初始化阶段就埋下技术债。本文将分享如何用IntelliJ IDEA从零搭建一个结构清晰、可维护性高的标准工程,重点解决三个核心问题:依赖管理的版本控制、MyBatis与SpringBoot的优雅集成、以及开发环境与生产环境的数据库配置分离。
1.1 工具选型与版本控制
工欲善其事必先利其器,以下是经过生产验证的工具组合:
- IDEA 2023.3+(社区版足够,无需破解)
- Java 17(LTS版本,新项目不建议再用Java 8)
- SpringBoot 3.1.5(注意GroupId已改为org.springframework.boot)
- MyBatis 3.5.13+ MyBatis-Spring 3.0.2
- MySQL 8.0.33(生产环境推荐Percona分支)
重要提示:版本兼容性直接影响后续开发体验。SpringBoot 3.x要求JDK 17+,若必须使用JDK 8,需降级到SpringBoot 2.7.x系列。
1.2 初始化工程的正确姿势
通过IDEA创建项目时,90%的开发者会忽略这两个关键配置:
- Artifact命名:建议采用反向域名+功能描述(如com.example.warehouse)
- 包结构规划:提前划分好controller/service/dao分层,避免后期重构
实操步骤:
# 使用Spring Initializr生成项目骨架 curl https://start.spring.io/starter.zip \ -d type=gradle-project \ -d language=java \ -d packaging=jar \ -d javaVersion=17 \ -d groupId=com.example \ -d artifactId=demo \ -d name=demo \ -d dependencies=web,mysql,mybatis \ -o demo.zip2. 核心组件集成实战
2.1 MyBatis的三层集成方案
数据源配置(application.yml示例)
spring: datasource: url: jdbc:mysql://localhost:3306/demo?useSSL=false&serverTimezone=Asia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver hikari: maximum-pool-size: 15 # 根据CPU核心数调整 connection-timeout: 30000 mybatis: mapper-locations: classpath:mapper/*.xml configuration: map-underscore-to-camel-case: true # 自动驼峰转换注解式Mapper的最佳实践
@Mapper public interface UserMapper { @Select("SELECT * FROM users WHERE id = #{id}") User findById(@Param("id") Long id); @Options(useGeneratedKeys = true, keyProperty = "id") @Insert("INSERT INTO users(name) VALUES(#{name})") int insert(User user); }2.2 事务管理的坑与解决方案
SpringBoot默认事务管理经常遇到的三个坑:
- 自调用失效问题:同类方法调用不会触发事务代理
- 异常捕获陷阱:try-catch会"吃掉"异常导致事务不回滚
- 连接泄漏风险:MyBatis查询未关闭ResultSet
解决方案示例:
@Service @Transactional(rollbackFor = Exception.class) // 明确指定回滚异常类型 public class UserService { private final UserMapper userMapper; // 构造器注入代替@Autowired public UserService(UserMapper userMapper) { this.userMapper = userMapper; } public void createUser(User user) { userMapper.insert(user); // 模拟业务异常 if (user.getName().contains("test")) { throw new RuntimeException("Invalid username"); } } }3. 工程化进阶技巧
3.1 多环境配置方案
采用profile区分环境是基础操作,但真正的工程化需要更多考量:
# application-dev.yml spring: datasource: url: jdbc:mysql://localhost:3306/dev_db username: dev_user # application-prod.yml spring: datasource: url: jdbc:mysql://prod-db.cluster:3306/prod_db?useSSL=true username: ${DB_USER} password: ${DB_PASSWORD} # 从环境变量读取启动时通过VM参数指定环境:
-Dspring.profiles.active=prod3.2 监控与健康检查
生产环境必备的监控端点配置:
management: endpoints: web: exposure: include: health,info,metrics endpoint: health: show-details: always metrics: enabled: true自定义健康检查指标示例:
@Component public class DatabaseHealthIndicator implements HealthIndicator { private final DataSource dataSource; public DatabaseHealthIndicator(DataSource dataSource) { this.dataSource = dataSource; } @Override public Health health() { try (Connection conn = dataSource.getConnection()) { return Health.up().withDetail("version", conn.getMetaData().getDatabaseProductVersion()).build(); } catch (Exception e) { return Health.down(e).build(); } } }4. 性能优化实战
4.1 MyBatis二级缓存陷阱
虽然MyBatis支持二级缓存,但在分布式环境中直接使用会导致严重的数据一致性问题。推荐方案:
@Configuration public class MyBatisConfig { @Bean public MyBatisSqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) throws Exception { MyBatisSqlSessionFactoryBean factory = new MyBatisSqlSessionFactoryBean(); factory.setDataSource(dataSource); // 显式关闭二级缓存 org.apache.ibatis.session.Configuration config = new org.apache.ibatis.session.Configuration(); config.setCacheEnabled(false); factory.setConfiguration(config); return factory; } }4.2 连接池参数调优
HikariCP推荐配置(针对4核8G服务器):
spring: datasource: hikari: minimum-idle: 5 maximum-pool-size: 20 idle-timeout: 30000 max-lifetime: 1800000 connection-timeout: 30000 connection-test-query: SELECT 15. 开发效率提升技巧
5.1 MyBatisX插件妙用
IDEA安装MyBatisX插件后可以实现:
- XML与Mapper接口方法智能跳转
- SQL语句自动补全
- 一键生成CRUD代码
5.2 测试数据准备
使用Testcontainers实现集成测试自动化:
@Testcontainers @SpringBootTest class UserRepositoryTest { @Container static MySQLContainer<?> mysql = new MySQLContainer<>("mysql:8.0"); @DynamicPropertySource static void registerPgProperties(DynamicPropertyRegistry registry) { registry.add("spring.datasource.url", mysql::getJdbcUrl); registry.add("spring.datasource.username", mysql::getUsername); registry.add("spring.datasource.password", mysql::getPassword); } @Test void testSaveUser() { // 测试逻辑 } }6. 常见问题排查指南
6.1 连接池耗尽问题
现象:出现"HikariPool-1 - Connection is not available"错误
排查步骤:
- 检查active连接数:
management.endpoints.web.exposure.include=metrics - 分析慢查询:
spring.datasource.hikari.leak-detection-threshold=60000 - 检查事务未关闭情况
6.2 MyBatis映射失败
典型错误:"Invalid bound statement (not found)"
解决方案检查清单:
- 确认mapper.xml文件在resources/mapper目录下
- 检查namespace与Mapper接口全限定名一致
- 方法名与statement id完全匹配
- 清理编译输出重新构建
7. 项目结构优化建议
标准项目目录结构示例:
src/ ├── main/ │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ ├── config/ # 配置类 │ │ ├── controller/ # 表现层 │ │ ├── service/ # 业务逻辑 │ │ ├── dao/ # 数据访问 │ │ ├── model/ # 数据实体 │ │ └── DemoApplication.java │ └── resources/ │ ├── mapper/ # MyBatis映射文件 │ ├── static/ # 静态资源 │ ├── templates/ # 模板文件 │ ├── application.yml # 主配置 │ └── application-dev.yml # 环境配置 └── test/ # 测试代码8. 安全防护要点
8.1 SQL注入防护
即使使用MyBatis也需要注意:
- 禁止拼接SQL:
"SELECT * FROM user WHERE id = " + id - 动态表名使用
${}时要白名单校验 - 复杂查询使用Provider类:
@SelectProvider(type = UserSqlProvider.class, method = "findByCondition") List<User> findByCondition(@Param("condition") UserCondition condition); public class UserSqlProvider { public String findByCondition(UserCondition condition) { return new SQL() {{ SELECT("*"); FROM("users"); if (condition.getName() != null) { WHERE("name = #{condition.name}"); } }}.toString(); } }8.2 敏感数据加密
数据库层面加密方案:
spring: datasource: password: jdbc:mysql://...?passwordEncryptor=type:AES;key:${ENCRYPT_KEY}或者在应用层使用Jasypt:
@Bean public StringEncryptor encryptor() { PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor(); encryptor.setPassword(System.getenv("ENCRYPT_PASSWORD")); return encryptor; }9. 部署与监控
9.1 打包注意事项
生产环境打包建议:
# 跳过测试构建 ./gradlew clean build -x test # 分离依赖jar减少体积 jar { enabled = true archiveClassifier = '' } bootJar { archiveClassifier = 'boot' }9.2 健康检查端点
Kubernetes就绪探针配置示例:
spring: application: name: user-service management: endpoint: health: probes: enabled: true health: livenessstate: enabled: true readinessstate: enabled: true10. 升级与迁移策略
10.1 SpringBoot 2.x → 3.x
关键变更点:
- Jakarta EE 9+(javax包名改为jakarta)
- Hibernate 6.x新特性
- 移除SpringFox支持,改用SpringDoc OpenAPI
10.2 MySQL 5.7 → 8.0
注意事项:
- 默认认证插件改为caching_sha2_password
- 需要更新连接器版本:
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency>11. 扩展技术选型
11.1 MyBatis-Plus进阶
增强功能示例:
@Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { public Page<User> queryByPage(PageParam param) { return lambdaQuery() .like(StringUtils.isNotBlank(param.getKeyword()), User::getName, param.getKeyword()) .page(new Page<>(param.getPage(), param.getSize())); } }11.2 多数据源方案
动态数据源配置要点:
@Configuration @MapperScan(basePackages = "com.example.dao.db1", sqlSessionTemplateRef = "db1SqlSessionTemplate") public class Db1Config { @Bean @ConfigurationProperties("spring.datasource.db1") public DataSource db1DataSource() { return DataSourceBuilder.create().build(); } @Bean public SqlSessionFactory db1SqlSessionFactory(@Qualifier("db1DataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); bean.setMapperLocations(new PathMatchingResourcePatternResolver() .getResources("classpath:mapper/db1/*.xml")); return bean.getObject(); } }12. 性能监控方案
12.1 Micrometer指标
集成Prometheus监控:
management: metrics: export: prometheus: enabled: true endpoint: prometheus: enabled: true自定义业务指标:
@RestController public class OrderController { private final Counter orderCounter; public OrderController(MeterRegistry registry) { this.orderCounter = registry.counter("orders.created"); } @PostMapping("/orders") public Order createOrder() { orderCounter.increment(); // 业务逻辑 } }13. 缓存集成策略
13.1 Redis二级缓存
替代MyBatis原生二级缓存:
@Configuration @EnableCaching public class CacheConfig { @Bean public CacheManager cacheManager(RedisConnectionFactory factory) { return RedisCacheManager.builder(factory) .cacheDefaults(RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofMinutes(30)) .disableCachingNullValues()) .build(); } } @Cacheable(value = "users", key = "#id") public User getUser(Long id) { return userMapper.selectById(id); }14. 日志收集方案
14.1 ELK集成
Logback配置示例:
<appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender"> <destination>logstash:5044</destination> <encoder class="net.logstash.logback.encoder.LogstashEncoder"> <customFields>{"app":"${spring.application.name}"}</customFields> </encoder> </appender>15. 容器化部署
15.1 Dockerfile优化
分层构建示例:
# 构建阶段 FROM gradle:7-jdk17 AS builder WORKDIR /app COPY build.gradle . COPY src ./src RUN gradle build -x test # 运行阶段 FROM eclipse-temurin:17-jre WORKDIR /app COPY --from=builder /app/build/libs/*.jar app.jar EXPOSE 8080 ENTRYPOINT ["java","-jar","app.jar"]16. 持续集成方案
16.1 GitHub Actions
自动化测试流水线:
name: CI on: [push] jobs: build: runs-on: ubuntu-latest services: mysql: image: mysql:8.0 env: MYSQL_ROOT_PASSWORD: root ports: - 3306:3306 steps: - uses: actions/checkout@v3 - uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: '17' - run: ./gradlew build17. 代码质量保障
17.1 SonarQube集成
Gradle配置示例:
plugins { id "org.sonarqube" version "3.5.0.2730" } sonarqube { properties { property "sonar.host.url", "http://localhost:9000" property "sonar.login", System.getenv("SONAR_TOKEN") } }18. API文档生成
18.1 SpringDoc OpenAPI
配置示例:
@OpenAPIDefinition( info = @Info(title = "用户服务API", version = "1.0") ) public class OpenApiConfig { @Bean public OpenAPI customOpenAPI() { return new OpenAPI() .components(new Components()) .info(new Info().title("用户服务API").version("1.0")); } }访问地址:http://localhost:8080/swagger-ui.html
19. 压力测试方案
19.1 JMeter测试计划
关键测试指标:
- 吞吐量(Requests/sec)
- 95%响应时间
- 错误率
- 数据库连接池使用率
测试脚本保存为src/test/resources/jmeter/UserTest.jmx
20. 项目总结与演进
经过完整项目实践后,建议从三个维度持续优化:
- 工程规范:引入Checkstyle/Spotless统一代码风格
- 架构演进:随着业务复杂度的提升,考虑引入DDD分层
- 性能优化:建立基准测试体系,量化性能指标
技术栈的升级路线建议:
- 初期:SpringBoot + MyBatis(快速迭代)
- 中期:引入Spring Cloud组件(服务治理)
- 后期:考虑Kotlin协程/Quarkus等新技术方案