1. Spring Boot与MyBatis集成概述
在现代Java企业级应用开发中,Spring Boot和MyBatis的组合已经成为处理关系型数据库访问的黄金搭档。Spring Boot通过自动配置简化了项目搭建过程,而MyBatis则提供了灵活且强大的SQL映射能力。这种组合既保留了Spring框架的便利性,又不会像JPA那样完全屏蔽SQL细节,特别适合需要精细控制SQL语句的场景。
我曾在多个电商和金融项目中采用这种技术栈,发现它特别适合以下场景:
- 需要执行复杂SQL查询的业务系统
- 对数据库性能有较高要求的应用
- 遗留系统改造项目(可以复用原有SQL)
- 需要同时支持多种数据库的产品
2. 环境准备与项目初始化
2.1 开发环境要求
在开始集成前,请确保你的开发环境满足以下要求:
- JDK 17或更高版本(推荐使用Amazon Corretto发行版)
- Maven 3.9+或Gradle 8.0+
- MySQL 8.0+或其他兼容数据库
- IDE推荐IntelliJ IDEA或VS Code
提示:虽然Spring Boot 3.x支持JDK 17+,但如果你必须使用JDK 8,可以考虑降级到Spring Boot 2.7.x版本,不过会失去一些新特性。
2.2 创建Spring Boot项目
使用Spring Initializr创建项目时,除了选择Web和MyBatis依赖外,我通常会添加以下依赖:
- Lombok(减少样板代码)
- Spring Boot DevTools(开发热部署)
- HikariCP(高性能连接池,默认已包含)
xml复制<!-- pom.xml关键依赖示例 -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<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>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
3. 数据库配置与MyBatis集成
3.1 数据源配置
在application.yml中配置数据源时,有几个关键参数需要注意:
yaml复制spring:
datasource:
url: jdbc:mysql://localhost:3306/test?useSSL=false&allowPublicKeyRetrieval=true
username: root
password: root
hikari:
maximum-pool-size: 20
connection-timeout: 30000
mybatis:
mapper-locations: classpath:mapper/**/*.xml
configuration:
map-underscore-to-camel-case: true
default-fetch-size: 100
实际项目中我遇到过的坑:
- MySQL 8.x驱动需要显式关闭SSL(useSSL=false)
- 连接池大小不是越大越好,一般建议是CPU核心数*2 + 有效磁盘数
- 生产环境一定要配置连接超时和验证查询
3.2 实体类设计
使用Lombok简化实体类代码:
java复制@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Long id;
private String email;
private String name;
private Role role;
private String description;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createdAt;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updatedAt;
private Boolean deleted;
public enum Role {
ADMIN, EDITOR, VIEWER
}
}
注意:日期字段建议添加@JsonFormat注解,避免前端接收时间格式不一致问题
4. MyBatis Mapper开发详解
4.1 接口定义与XML映射
MyBatis的核心在于Mapper接口与XML文件的配合使用。以下是一个完整的用户管理Mapper示例:
java复制@Mapper
public interface UserMapper {
@Select("SELECT COUNT(*) FROM user WHERE deleted = false")
long countActiveUsers();
@Options(useGeneratedKeys = true, keyProperty = "id")
@Insert("INSERT INTO user(email, name) VALUES(#{email}, #{name})")
int insertUser(User user);
List<User> selectByCondition(UserQuery query);
@Update("UPDATE user SET name = #{name} WHERE id = #{id}")
int updateName(@Param("id") Long id, @Param("name") String name);
}
对应的XML映射文件:
xml复制<mapper namespace="com.example.mapper.UserMapper">
<sql id="baseColumn">
id, email, name, role
</sql>
<select id="selectByCondition" resultType="User">
SELECT <include refid="baseColumn"/>
FROM user
<where>
<if test="name != null">
AND name LIKE CONCAT('%', #{name}, '%')
</if>
<if test="role != null">
AND role = #{role}
</if>
</where>
ORDER BY id DESC
</select>
</mapper>
4.2 动态SQL技巧
MyBatis强大的动态SQL能力可以极大减少代码量。以下是我总结的实用技巧:
<where>标签会自动处理前缀AND- 使用
<foreach>处理批量操作 <choose>实现条件分支#{}防止SQL注入,${}用于动态表名
xml复制<update id="batchUpdateStatus">
UPDATE user
SET status = #{status}
WHERE id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</update>
5. 高级特性与性能优化
5.1 二级缓存配置
MyBatis二级缓存可以显著提升查询性能,但需要谨慎使用:
xml复制<cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>
缓存使用注意事项:
- 只读缓存性能更好
- 更新频繁的表不适合缓存
- 分布式环境需要改用Redis等集中式缓存
5.2 分页插件集成
PageHelper是国内最流行的MyBatis分页插件:
java复制// 分页查询示例
PageHelper.startPage(1, 10);
List<User> users = userMapper.selectByCondition(query);
PageInfo<User> pageInfo = new PageInfo<>(users);
5.3 多数据源配置
大型项目常需要访问多个数据源:
java复制@Configuration
@MapperScan(basePackages = "com.example.mapper.db1", sqlSessionTemplateRef = "db1SqlSessionTemplate")
public class Db1DataSourceConfig {
@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();
}
@Bean
public SqlSessionTemplate db1SqlSessionTemplate(
@Qualifier("db1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
6. 常见问题排查
6.1 SQL语句不生效
可能原因及解决方案:
- XML文件未加载:检查mybatis.mapper-locations配置
- 方法名冲突:确保Mapper接口方法名与XML id一致
- 参数不匹配:使用@Param注解明确参数名
6.2 性能问题优化
我遇到的典型性能问题及解决方法:
- N+1查询问题:使用
<collection>或<association>实现关联查询 - 大结果集内存溢出:使用ResultHandler流式处理
- 批量插入慢:改用BatchExecutor
java复制// 批量插入优化示例
SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);
try {
UserMapper mapper = session.getMapper(UserMapper.class);
for (User user : users) {
mapper.insert(user);
}
session.commit();
} finally {
session.close();
}
6.3 事务管理
Spring事务与MyBatis集成要点:
- 使用@Transactional注解
- 事务传播行为根据业务需求设置
- 注意事务失效的常见场景(如自调用)
java复制@Service
@RequiredArgsConstructor
public class UserService {
private final UserMapper userMapper;
@Transactional(rollbackFor = Exception.class)
public void createUser(User user) {
userMapper.insert(user);
// 其他数据库操作...
}
}
7. 测试与监控
7.1 单元测试配置
Spring Boot测试支持:
java复制@SpringBootTest
@Transactional
@Slf4j
class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
void testSelect() {
User user = userMapper.selectById(1L);
assertNotNull(user);
log.debug("查询结果:{}", user);
}
}
7.2 SQL监控
开发阶段可以开启MyBatis日志:
yaml复制logging:
level:
org.mybatis: DEBUG
生产环境建议使用P6Spy或Druid的SQL监控功能。
8. 项目实践建议
经过多个项目实践,我总结了以下最佳实践:
- 保持Mapper接口的单一职责
- 复杂SQL写在XML中,简单SQL用注解
- 数据库字段与Java属性使用不同命名规范(如user_name vs userName)
- 为常用查询建立BaseMapper接口
- 使用MyBatis Generator或MyBatis Plus减少样板代码
java复制// 通用Mapper示例
public interface BaseMapper<T, ID> {
int insert(T entity);
int updateById(T entity);
T selectById(ID id);
List<T> selectAll();
int deleteById(ID id);
}
对于新项目,我建议考虑MyBatis Plus,它在MyBatis基础上提供了更多开箱即用的功能,可以显著提升开发效率。但对于需要精细控制SQL的复杂项目,原生MyBatis仍然是更好的选择。
