1. 为什么选择SpringBoot操作MySQL数据库
在Java生态中,SpringBoot已经成为构建企业级应用的事实标准。根据2023年最新的开发者调查报告显示,超过78%的Java项目采用SpringBoot作为基础框架。而MySQL作为最流行的开源关系型数据库,其与SpringBoot的整合更是开发者必备的核心技能。
我最初接触这个技术栈时,发现很多教程都停留在简单的"Hello World"层面。但在实际企业开发中,我们需要考虑更多工程化问题:如何设计合理的数据库连接池?事务管理的最佳实践是什么?MyBatis与JPA该如何选择?这些都是在真实项目中必须面对的挑战。
2. 环境准备与基础配置
2.1 MySQL安装与初始化
在开始SpringBoot项目前,我们需要确保本地MySQL环境正确配置。推荐使用MySQL 8.0+版本,它提供了更好的性能和安全性支持。安装过程中有几个关键点需要注意:
- 字符集设置:务必选择utf8mb4字符集,这是支持完整Unicode(包括emoji)的必要配置
- 密码加密方式:MySQL 8.0默认使用caching_sha2_password,如果遇到客户端兼容性问题可以改为mysql_native_password
- 端口开放:确认3306端口未被占用,或者配置自定义端口
安装完成后,建议执行以下初始化SQL创建专用数据库和用户:
CREATE DATABASE springboot_demo CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER 'demo_user'@'%' IDENTIFIED BY 'Demo@1234'; GRANT ALL PRIVILEGES ON springboot_demo.* TO 'demo_user'@'%'; FLUSH PRIVILEGES;2.2 SpringBoot项目初始化
使用Spring Initializr创建项目时,需要勾选以下关键依赖:
- Spring Web (构建Web应用)
- Spring Data JDBC/MyBatis (数据库访问)
- MySQL Driver (数据库连接)
对于IDE的选择,IntelliJ IDEA提供了最完善的SpringBoot支持。在创建项目后,建议立即配置application.properties(或application.yml):
# 数据库配置 spring.datasource.url=jdbc:mysql://localhost:3306/springboot_demo?useSSL=false&serverTimezone=Asia/Shanghai spring.datasource.username=demo_user spring.datasource.password=Demo@1234 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver # 连接池配置(HikariCP默认) spring.datasource.hikari.maximum-pool-size=10 spring.datasource.hikari.minimum-idle=5 spring.datasource.hikari.idle-timeout=30000注意:在生产环境中,务必使用加密方式存储数据库密码,推荐使用Jasypt等工具进行敏感信息加密
3. 数据库操作实战
3.1 使用JdbcTemplate进行基础CRUD
对于简单的数据库操作,Spring自带的JdbcTemplate是不错的选择。它避免了ORM框架的学习成本,适合快速开发:
@Repository public class UserRepository { private final JdbcTemplate jdbcTemplate; public UserRepository(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } public int createUser(User user) { String sql = "INSERT INTO users(username, email) VALUES(?, ?)"; return jdbcTemplate.update(sql, user.getUsername(), user.getEmail()); } public User findById(Long id) { String sql = "SELECT * FROM users WHERE id = ?"; return jdbcTemplate.queryForObject(sql, new Object[]{id}, (rs, rowNum) -> new User( rs.getLong("id"), rs.getString("username"), rs.getString("email") )); } }在实际使用中,我发现JdbcTemplate有几点需要注意:
- SQL注入防护:永远使用参数化查询,不要直接拼接SQL字符串
- 异常处理:需要捕获DataAccessException及其子类异常
- 结果映射:对于复杂对象,建议使用RowMapper接口实现
3.2 集成MyBatis实现高级映射
对于复杂业务场景,MyBatis提供了更强大的SQL映射能力。首先添加依赖:
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>3.0.2</version> </dependency>配置Mapper接口和XML文件:
@Mapper public interface UserMapper { @Insert("INSERT INTO users(username, email) VALUES(#{username}, #{email})") @Options(useGeneratedKeys = true, keyProperty = "id") int insert(User user); @Select("SELECT * FROM users WHERE id = #{id}") User findById(Long id); }对于复杂查询,可以使用XML配置方式:
<!-- UserMapper.xml --> <mapper namespace="com.example.mapper.UserMapper"> <resultMap id="userResultMap" type="User"> <id property="id" column="id"/> <result property="username" column="username"/> <result property="email" column="email"/> <collection property="roles" ofType="Role" select="findRolesByUserId" column="id"/> </resultMap> <select id="findUserWithRoles" resultMap="userResultMap"> SELECT * FROM users WHERE id = #{id} </select> </mapper>经验分享:MyBatis的@Param注解在方法有多个参数时必须添加,否则会导致参数绑定失败
4. 事务管理与性能优化
4.1 Spring声明式事务实践
SpringBoot默认使用声明式事务管理。在Service层添加@Transactional注解即可:
@Service public class UserService { private final UserRepository userRepository; public UserService(UserRepository userRepository) { this.userRepository = userRepository; } @Transactional public void createUserWithProfile(User user, Profile profile) { userRepository.save(user); profile.setUserId(user.getId()); profileRepository.save(profile); } }需要注意的几个关键点:
- 默认情况下,Spring事务只在运行时异常时回滚
- 事务传播行为需要根据业务场景谨慎选择
- 同类内方法调用不会触发事务代理(自调用问题)
4.2 连接池优化与监控
SpringBoot 2.x默认使用HikariCP连接池,以下是一些优化建议:
# 连接池优化配置 spring.datasource.hikari.maximum-pool-size=20 spring.datasource.hikari.minimum-idle=10 spring.datasource.hikari.idle-timeout=600000 spring.datasource.hikari.max-lifetime=1800000 spring.datasource.hikari.connection-timeout=30000 spring.datasource.hikari.connection-test-query=SELECT 1可以通过Actuator监控连接池状态:
@RestController @RequestMapping("/api/db") public class DbMonitorController { @Autowired private DataSource dataSource; @GetMapping("/pool-info") public Map<String, Object> getPoolInfo() { if (dataSource instanceof HikariDataSource) { HikariPoolMXBean pool = ((HikariDataSource) dataSource).getHikariPoolMXBean(); Map<String, Object> info = new HashMap<>(); info.put("activeConnections", pool.getActiveConnections()); info.put("idleConnections", pool.getIdleConnections()); info.put("totalConnections", pool.getTotalConnections()); return info; } return Collections.singletonMap("error", "Not HikariCP datasource"); } }5. 常见问题排查与调试技巧
5.1 连接问题诊断
当遇到数据库连接问题时,可以按照以下步骤排查:
- 验证基础连接信息:
try (Connection conn = DriverManager.getConnection( "jdbc:mysql://localhost:3306/springboot_demo", "demo_user", "Demo@1234")) { System.out.println("Connection successful!"); } catch (SQLException e) { e.printStackTrace(); }- 检查MySQL服务器状态:
sudo systemctl status mysql- 查看连接数限制:
SHOW VARIABLES LIKE 'max_connections';5.2 MyBatis日志调试
在开发阶段,开启MyBatis的SQL日志非常有用:
# MyBatis日志配置 logging.level.com.example.mapper=DEBUG mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl对于更复杂的调试,可以使用MyBatis Log Plugin等IDE插件,它能将预编译的SQL与参数合并输出,方便直接复制到客户端执行。
5.3 性能问题分析
当遇到查询性能问题时,可以:
- 使用EXPLAIN分析SQL执行计划
- 开启MySQL慢查询日志:
# MySQL慢查询配置 slow_query_log = 1 slow_query_log_file = /var/log/mysql/mysql-slow.log long_query_time = 1- 使用Spring Data的@QueryHints添加查询提示
6. 进阶实践与扩展
6.1 多数据源配置
在实际项目中,经常需要连接多个数据库。SpringBoot中可以通过以下方式实现:
@Configuration public class DataSourceConfig { @Bean @Primary @ConfigurationProperties("spring.datasource.primary") public DataSource primaryDataSource() { return DataSourceBuilder.create().build(); } @Bean @ConfigurationProperties("spring.datasource.secondary") public DataSource secondaryDataSource() { return DataSourceBuilder.create().build(); } }然后为每个数据源配置独立的MyBatis环境:
@Configuration @MapperScan(basePackages = "com.example.primary.mapper", sqlSessionFactoryRef = "primarySqlSessionFactory") public class PrimaryDataSourceConfig { @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(); } }6.2 数据库迁移工具集成
对于数据库版本控制,推荐使用Flyway或Liquibase。以Flyway为例:
<dependency> <groupId>org.flywaydb</groupId> <artifactId>flyway-core</artifactId> </dependency>然后在resources/db/migration目录下创建迁移脚本:
-- V1__Create_user_table.sql CREATE TABLE users ( id BIGINT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL, email VARCHAR(100) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );Flyway会在应用启动时自动执行这些脚本,确保数据库结构始终与代码保持同步。
6.3 测试数据准备
良好的测试数据对开发至关重要。可以使用以下方式准备测试数据:
- 使用Spring的@Sql注解:
@Test @Sql(scripts = "/test-data.sql") public void testWithData() { // 测试逻辑 }- 使用Testcontainers进行集成测试:
@Testcontainers @SpringBootTest public class UserRepositoryTest { @Container static MySQLContainer<?> mysql = new MySQLContainer<>("mysql:8.0"); @DynamicPropertySource static void configureProperties(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 testDatabaseConnection() { // 测试逻辑 } }在实际项目中,我发现合理使用测试数据可以显著提高开发效率和代码质量。特别是在持续集成环境中,自动化测试能够及时发现数据库相关的兼容性问题。