
1. 项目概述与环境准备在Java企业级开发领域SpringBootMyBatisMySQL的技术组合已成为中小型项目的黄金搭档。作为从业多年的全栈开发者我见证过太多团队在项目初始化阶段就埋下技术债。本文将分享如何用IntelliJ IDEA从零搭建一个结构清晰、可维护性高的标准工程重点解决三个核心问题依赖管理的版本控制、MyBatis与SpringBoot的优雅集成、以及开发环境与生产环境的数据库配置分离。1.1 工具选型与版本控制工欲善其事必先利其器以下是经过生产验证的工具组合IDEA 2023.3社区版足够无需破解Java 17LTS版本新项目不建议再用Java 8SpringBoot 3.1.5注意GroupId已改为org.springframework.bootMyBatis 3.5.13 MyBatis-Spring 3.0.2MySQL 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 typegradle-project \ -d languagejava \ -d packagingjar \ -d javaVersion17 \ -d groupIdcom.example \ -d artifactIddemo \ -d namedemo \ -d dependenciesweb,mysql,mybatis \ -o demo.zip2. 核心组件集成实战2.1 MyBatis的三层集成方案数据源配置application.yml示例spring: datasource: url: jdbc:mysql://localhost:3306/demo?useSSLfalseserverTimezoneAsia/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?useSSLtrue username: ${DB_USER} password: ${DB_PASSWORD} # 从环境变量读取启动时通过VM参数指定环境-Dspring.profiles.activeprod3.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.includemetrics分析慢查询spring.datasource.hikari.leak-detection-threshold60000检查事务未关闭情况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也需要注意禁止拼接SQLSELECT * FROM user WHERE id id动态表名使用${}时要白名单校验复杂查询使用Provider类SelectProvider(type UserSqlProvider.class, method findByCondition) ListUser 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://...?passwordEncryptortype:AES;key:${ENCRYPT_KEY}或者在应用层使用JasyptBean 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 9javax包名改为jakartaHibernate 6.x新特性移除SpringFox支持改用SpringDoc OpenAPI10.2 MySQL 5.7 → 8.0注意事项默认认证插件改为caching_sha2_password需要更新连接器版本dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency11. 扩展技术选型11.1 MyBatis-Plus进阶增强功能示例Service public class UserServiceImpl extends ServiceImplUserMapper, User implements UserService { public PageUser 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 nameLOGSTASH classnet.logstash.logback.appender.LogstashTcpSocketAppender destinationlogstash:5044/destination encoder classnet.logstash.logback.encoder.LogstashEncoder customFields{app:${spring.application.name}}/customFields /encoder /appender15. 容器化部署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 --frombuilder /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/checkoutv3 - uses: actions/setup-javav3 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.html19. 压力测试方案19.1 JMeter测试计划关键测试指标吞吐量Requests/sec95%响应时间错误率数据库连接池使用率测试脚本保存为src/test/resources/jmeter/UserTest.jmx20. 项目总结与演进经过完整项目实践后建议从三个维度持续优化工程规范引入Checkstyle/Spotless统一代码风格架构演进随着业务复杂度的提升考虑引入DDD分层性能优化建立基准测试体系量化性能指标技术栈的升级路线建议初期SpringBoot MyBatis快速迭代中期引入Spring Cloud组件服务治理后期考虑Kotlin协程/Quarkus等新技术方案