1. Spring Boot与MyBatis整合基础环境搭建
1.1 项目初始化与依赖配置
在IntelliJ IDEA中创建新的Spring Boot项目时,推荐使用Spring Initializr向导。关键依赖选择需要注意以下配置项:
- Spring Boot版本:当前稳定版为3.2.x(截至2024年),对应Java 17+环境。若需兼容Java 8需降级到2.7.x版本
- 依赖勾选:必须包含
Spring Web、MyBatis Framework和对应数据库驱动(如MySQL Driver) - POM关键依赖:
<dependencies> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>3.0.3</version> </dependency> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> </dependencies>注意:mybatis-spring-boot-starter已自动包含MyBatis核心和MyBatis-Spring适配器,无需单独引入
1.2 数据库连接池配置
Spring Boot默认使用HikariCP连接池,在application.yml中配置示例:
spring: datasource: url: jdbc:mysql://localhost:3306/demo?useSSL=false&serverTimezone=UTC username: root password: 123456 hikari: maximum-pool-size: 15 connection-timeout: 30000 idle-timeout: 600000 max-lifetime: 1800000实测中发现三个易错点:
- 时区问题:MySQL 8.x必须指定serverTimezone参数
- SSL警告:开发环境建议显式关闭useSSL
- 连接泄漏:建议设置合理的max-lifetime(单位毫秒)
2. MyBatis核心组件配置详解
2.1 实体类与Mapper接口定义
实体类需要遵循JPA规范注解:
@Data @Table(name = "t_user") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String username; private LocalDateTime createTime; }Mapper接口定义技巧:
@Mapper public interface UserMapper { @Select("SELECT * FROM t_user WHERE id = #{id}") User findById(Long id); @Insert("INSERT INTO t_user(username) VALUES(#{username})") @Options(useGeneratedKeys = true, keyProperty = "id") int insert(User user); }经验:简单SQL推荐使用注解方式,复杂SQL建议XML配置。@MapperScan可批量扫描接口
2.2 XML映射文件配置
在resources/mapper目录下创建UserMapper.xml:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.example.mapper.UserMapper"> <resultMap id="userMap" type="com.example.entity.User"> <id column="id" property="id"/> <result column="username" property="username"/> <result column="create_time" property="createTime"/> </resultMap> <select id="selectAll" resultMap="userMap"> SELECT * FROM t_user </select> </mapper>需在application.yml添加配置:
mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.entity3. 高级特性实战应用
3.1 动态SQL构建
MyBatis提供强大的动态SQL能力:
<select id="searchUsers" resultMap="userMap"> SELECT * FROM t_user <where> <if test="username != null"> AND username LIKE CONCAT('%', #{username}, '%') </if> <if test="startTime != null"> AND create_time >= #{startTime} </if> </where> ORDER BY id DESC </select>对应Java接口:
List<User> searchUsers(@Param("username") String username, @Param("startTime") LocalDateTime startTime);3.2 事务管理配置
Spring Boot中启用事务管理:
@Service @RequiredArgsConstructor public class UserService { private final UserMapper userMapper; @Transactional(rollbackFor = Exception.class) public void createUser(User user) { userMapper.insert(user); // 其他数据库操作 } }关键注意事项:
- 事务方法必须public
- 默认只回滚RuntimeException
- 同类方法调用不会触发事务代理
4. 性能优化与生产实践
4.1 二级缓存配置
在application.yml中启用缓存:
mybatis: configuration: cache-enabled: trueMapper接口添加注解:
@CacheNamespace public interface UserMapper { // 方法定义 }警告:分布式环境需要配合Redis等实现自定义缓存
4.2 分页插件集成
添加PageHelper依赖:
<dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>2.1.0</version> </dependency>使用示例:
PageHelper.startPage(1, 10); List<User> users = userMapper.selectAll(); PageInfo<User> pageInfo = new PageInfo<>(users);4.3 监控与诊断
Spring Boot Actuator集成:
management: endpoints: web: exposure: include: health,metrics,datasource关键监控指标:
hikaricp.connections.active:活跃连接数hikaricp.connections.idle:空闲连接数jdbc.connections.max:最大连接数
5. 常见问题排查指南
5.1 启动时Mapper注入失败
典型错误:
Field userMapper in com.example.service.UserService required a bean of type 'com.example.mapper.UserMapper' that could not be found解决方案检查清单:
- 确认接口有@Mapper注解或主类有@MapperScan
- 检查mapper-locations路径是否正确
- MyBatis版本与Spring Boot版本匹配
5.2 SQL执行参数异常
日志中看到:
### SQL: SELECT * FROM t_user WHERE id = ? ### Cause: java.sql.SQLException: Parameter index out of range (1 > number of parameters, which is 0)可能原因:
- #{param}被写成了${param}
- @Param注解缺失
- XML中parameterType与实际不符
5.3 事务不生效场景
典型情况:
- 方法非public
- 异常被catch未抛出
- 数据库引擎不支持(如MyISAM)
- 同类方法自调用
排查步骤:
- 检查日志是否有"Creating new transaction"
- 确认代理模式(建议使用CGLIB)
- 测试异常是否触发回滚
6. 扩展功能开发实践
6.1 自定义TypeHandler
处理枚举类型示例:
@MappedTypes(UserType.class) public class UserTypeHandler extends BaseTypeHandler<UserType> { @Override public void setNonNullParameter(PreparedStatement ps, int i, UserType parameter, JdbcType jdbcType) { ps.setInt(i, parameter.getCode()); } // 其他抽象方法实现... }注册TypeHandler:
mybatis: type-handlers-package: com.example.handler6.2 插件开发示例
实现执行时间统计插件:
@Intercepts(@Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class})) public class PerformanceInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { long start = System.currentTimeMillis(); try { return invocation.proceed(); } finally { long cost = System.currentTimeMillis() - start; if (cost > 100) { System.out.println("SQL执行耗时: " + cost + "ms"); } } } }注册插件:
@Configuration public class MyBatisConfig { @Bean public PerformanceInterceptor performanceInterceptor() { return new PerformanceInterceptor(); } }7. 测试策略与技巧
7.1 单元测试配置
测试类基础配置:
@SpringBootTest @Transactional @Rollback class UserMapperTest { @Autowired private UserMapper userMapper; @Test void testInsert() { User user = new User(); user.setUsername("test"); assertEquals(1, userMapper.insert(user)); assertNotNull(user.getId()); } }7.2 测试数据准备
使用SQL脚本初始化数据:
-- src/test/resources/data.sql INSERT INTO t_user(username) VALUES('test1'), ('test2');测试配置:
spring: datasource: initialization-mode: always schema: classpath:schema.sql data: classpath:data.sql7.3 集成测试示例
REST API测试示例:
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) class UserControllerTest { @LocalServerPort private int port; @Autowired private TestRestTemplate restTemplate; @Test void testGetUser() { ResponseEntity<User> response = restTemplate.getForEntity( "http://localhost:" + port + "/users/1", User.class); assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getBody().getUsername()); } }8. 生产环境部署建议
8.1 多环境配置管理
使用profile区分环境:
# application-dev.yml spring: datasource: url: jdbc:mysql://dev-db:3306/demo --- # application-prod.yml spring: datasource: url: jdbc:mysql://prod-db:3306/demo hikari: maximum-pool-size: 30启动命令:
java -jar app.jar --spring.profiles.active=prod8.2 健康检查配置
自定义健康指标:
@Component public class MyBatisHealthIndicator implements HealthIndicator { private final SqlSessionFactory sqlSessionFactory; @Override public Health health() { try (SqlSession session = sqlSessionFactory.openSession()) { session.selectOne("SELECT 1"); return Health.up().build(); } catch (Exception e) { return Health.down(e).build(); } } }8.3 性能调优参数
关键JVM参数建议:
-XX:+UseG1GC -Xms1024m -Xmx1024m -XX:MaxGCPauseMillis=200 -XX:ParallelGCThreads=4MyBatis额外配置:
mybatis: configuration: default-fetch-size: 100 default-statement-timeout: 30